You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@pivot.apache.org by gb...@apache.org on 2010/08/27 17:02:11 UTC

svn commit: r990170 - in /pivot/trunk: core/src/org/apache/pivot/beans/ tutorials/src/org/apache/pivot/tutorials/databinding/

Author: gbrown
Date: Fri Aug 27 15:02:11 2010
New Revision: 990170

URL: http://svn.apache.org/viewvc?rev=990170&view=rev
Log:
Add bind mapping support to NamespaceBinding and BXMLSerializer; automatically generate an ID for bind target if none specified.


Modified:
    pivot/trunk/core/src/org/apache/pivot/beans/BXMLSerializer.java
    pivot/trunk/core/src/org/apache/pivot/beans/NamespaceBinding.java
    pivot/trunk/tutorials/src/org/apache/pivot/tutorials/databinding/PropertyBinding.java
    pivot/trunk/tutorials/src/org/apache/pivot/tutorials/databinding/property_binding.bxml

Modified: pivot/trunk/core/src/org/apache/pivot/beans/BXMLSerializer.java
URL: http://svn.apache.org/viewvc/pivot/trunk/core/src/org/apache/pivot/beans/BXMLSerializer.java?rev=990170&r1=990169&r2=990170&view=diff
==============================================================================
--- pivot/trunk/core/src/org/apache/pivot/beans/BXMLSerializer.java (original)
+++ pivot/trunk/core/src/org/apache/pivot/beans/BXMLSerializer.java Fri Aug 27 15:02:11 2010
@@ -193,6 +193,40 @@ public class BXMLSerializer implements S
         }
     }
 
+    private static class ScriptBindMapping implements NamespaceBinding.BindMapping {
+        private ScriptEngine scriptEngine;
+        private String functionName;
+
+        public ScriptBindMapping(ScriptEngine scriptEngine, String functionName) {
+            this.scriptEngine = scriptEngine;
+            this.functionName = functionName;
+        }
+
+        public Object evaluate(Object value) {
+            Bindings bindings = scriptEngine.getBindings(ScriptContext.GLOBAL_SCOPE);
+            if (bindings.containsKey(functionName)) {
+                Invocable invocable;
+                try {
+                    invocable = (Invocable)scriptEngine;
+                } catch (ClassCastException exception) {
+                    throw new RuntimeException(exception);
+                }
+
+                try {
+                    value = invocable.invokeFunction(functionName, value);
+                } catch (NoSuchMethodException exception) {
+                    throw new RuntimeException(exception);
+                } catch (ScriptException exception) {
+                    throw new RuntimeException(exception);
+                }
+            } else {
+                throw new RuntimeException("Mapping function \"" + functionName + "\" is not defined.");
+            }
+
+            return value;
+        }
+    };
+
     private XMLInputFactory xmlInputFactory;
     private ScriptEngineManager scriptEngineManager;
 
@@ -205,6 +239,7 @@ public class BXMLSerializer implements S
 
     private Object root = null;
     private String language = null;
+    private int nextID = 0;
 
     private LinkedList<Attribute> namespaceBindingAttributes = new LinkedList<Attribute>();
 
@@ -218,6 +253,8 @@ public class BXMLSerializer implements S
 
     public static final String NAMESPACE_BINDING_PREFIX = OBJECT_REFERENCE_PREFIX + "{";
     public static final String NAMESPACE_BINDING_SUFFIX = "}";
+    public static final String BIND_MAPPING_DELIMITER = ":";
+    public static final String INTERNAL_ID_PREFIX = "$";
 
     public static final String LANGUAGE_PROCESSING_INSTRUCTION = "language";
 
@@ -422,16 +459,28 @@ public class BXMLSerializer implements S
             Element element = attribute.element;
             String sourcePath = (String)attribute.value;
 
+            NamespaceBinding.BindMapping bindMapping;
+            int i = sourcePath.indexOf(BIND_MAPPING_DELIMITER);
+            if (i == -1) {
+                bindMapping = null;
+            } else {
+                String bindFunction = sourcePath.substring(0, i);
+                sourcePath = sourcePath.substring(i + 1);
+                bindMapping = new ScriptBindMapping(scriptEngineManager.getEngineByName(language), bindFunction);
+            }
+
             switch (element.type) {
                 case INSTANCE:
                 case INCLUDE: {
                     // Bind to <element ID>.<attribute name>
                     if (element.id == null) {
-                        throw new SerializationException("Bind target does not have an ID.");
+                        element.id = INTERNAL_ID_PREFIX + Integer.toString(nextID++);
+                        namespace.put(element.id, element.value);
                     }
 
                     String targetPath = element.id + "." + attribute.name;
-                    NamespaceBinding namespaceBinding = new NamespaceBinding(namespace, sourcePath, targetPath);
+                    NamespaceBinding namespaceBinding = new NamespaceBinding(namespace, sourcePath, targetPath,
+                        bindMapping);
                     namespaceBinding.bind();
 
                     break;
@@ -440,11 +489,13 @@ public class BXMLSerializer implements S
                 case READ_ONLY_PROPERTY: {
                     // Bind to <parent element ID>.<element name>.<attribute name>
                     if (element.parent.id == null) {
-                        throw new SerializationException("Bind target does not have an ID.");
+                        element.parent.id = INTERNAL_ID_PREFIX + Integer.toString(nextID++);
+                        namespace.put(element.parent.id, element.parent.value);
                     }
 
                     String targetPath = element.parent.id + "." + element.name + "." + attribute.name;
-                    NamespaceBinding namespaceBinding = new NamespaceBinding(namespace, sourcePath, targetPath);
+                    NamespaceBinding namespaceBinding = new NamespaceBinding(namespace, sourcePath, targetPath,
+                        bindMapping);
                     namespaceBinding.bind();
 
                     break;
@@ -1472,7 +1523,7 @@ public class BXMLSerializer implements S
     }
 
     /**
-     * Gets a read-only version of the xml stream reader that's being used by
+     * Gets a read-only version of the XML stream reader that's being used by
      * this serializer. Subclasses can use this to access information about the
      * current event.
      */

Modified: pivot/trunk/core/src/org/apache/pivot/beans/NamespaceBinding.java
URL: http://svn.apache.org/viewvc/pivot/trunk/core/src/org/apache/pivot/beans/NamespaceBinding.java?rev=990170&r1=990169&r2=990170&view=diff
==============================================================================
--- pivot/trunk/core/src/org/apache/pivot/beans/NamespaceBinding.java (original)
+++ pivot/trunk/core/src/org/apache/pivot/beans/NamespaceBinding.java Fri Aug 27 15:02:11 2010
@@ -27,6 +27,18 @@ import org.apache.pivot.json.JSON;
  * property within a namespace.
  */
 public class NamespaceBinding {
+    /**
+     * Namespace bind mapping interface.
+     */
+    public interface BindMapping {
+        /**
+         * Transforms a source value during a bind operation.
+         *
+         * @param value
+         */
+        public Object evaluate(Object value);
+    }
+
     private Map<String, Object> namespace;
 
     private String sourcePath;
@@ -40,6 +52,8 @@ public class NamespaceBinding {
     private Dictionary<String, Object> targetDictionary;
     private String targetKey;
 
+    private BindMapping bindMapping;
+
     private boolean updating = false;
 
     private MapListener<String, Object> sourceMapListener = new MapListener.Adapter<String, Object>() {
@@ -48,7 +62,7 @@ public class NamespaceBinding {
             if (key.equals(sourceKey)
                 && !updating) {
                 updating = true;
-                targetDictionary.put(targetKey, sourceMap.get(sourceKey));
+                targetDictionary.put(targetKey, getMappedSourceValue());
                 updating = false;
             }
         }
@@ -60,14 +74,19 @@ public class NamespaceBinding {
             if (propertyName.equals(sourceKey)
                 && !updating) {
                 updating = true;
-                targetDictionary.put(targetKey, sourceMap.get(sourceKey));
+                targetDictionary.put(targetKey, getMappedSourceValue());
                 updating = false;
             }
         }
     };
 
-    @SuppressWarnings("unchecked")
     public NamespaceBinding(Map<String, Object> namespace, String sourcePath, String targetPath) {
+        this(namespace, sourcePath, targetPath, null);
+    }
+
+    @SuppressWarnings("unchecked")
+    public NamespaceBinding(Map<String, Object> namespace, String sourcePath, String targetPath,
+        BindMapping bindMapping) {
         if (namespace == null) {
             throw new IllegalArgumentException();
         }
@@ -126,8 +145,11 @@ public class NamespaceBinding {
                 + "\" does not exist.");
         }
 
+        // Set the bind mapping
+        this.bindMapping = bindMapping;
+
         // Perform the initial set from source to target
-        targetDictionary.put(targetKey, sourceMap.get(sourceKey));
+        targetDictionary.put(targetKey, getMappedSourceValue());
     }
 
     /**
@@ -180,6 +202,25 @@ public class NamespaceBinding {
     }
 
     /**
+     * Returns the bind mapping.
+     *
+     * @return
+     * The bind mapping to use during binding, or <tt>null</tt> if no bind
+     * mapping is specified.
+     */
+    public BindMapping getBindMapping() {
+        return bindMapping;
+    }
+
+    /**
+     * Returns the current source value with any bind mapping applied.
+     */
+    public Object getMappedSourceValue() {
+        Object sourceValue = sourceMap.get(sourceKey);
+        return (bindMapping == null) ? sourceValue : bindMapping.evaluate(sourceValue);
+    }
+
+    /**
      * Binds the source property to the target property.
      */
     public void bind() {

Modified: pivot/trunk/tutorials/src/org/apache/pivot/tutorials/databinding/PropertyBinding.java
URL: http://svn.apache.org/viewvc/pivot/trunk/tutorials/src/org/apache/pivot/tutorials/databinding/PropertyBinding.java?rev=990170&r1=990169&r2=990170&view=diff
==============================================================================
--- pivot/trunk/tutorials/src/org/apache/pivot/tutorials/databinding/PropertyBinding.java (original)
+++ pivot/trunk/tutorials/src/org/apache/pivot/tutorials/databinding/PropertyBinding.java Fri Aug 27 15:02:11 2010
@@ -16,6 +16,7 @@
  */
 package org.apache.pivot.tutorials.databinding;
 
+import java.awt.Color;
 import java.net.URL;
 
 import org.apache.pivot.beans.Bindable;
@@ -27,9 +28,25 @@ import org.apache.pivot.wtk.Window;
 public class PropertyBinding extends Window implements Bindable {
     @Override
     public void initialize(Map<String, Object> namespace, URL location, Resources resources) {
-        // Manually bind list button selection to label text
-        NamespaceBinding namespaceBinding = new NamespaceBinding(namespace,
-            "listButton.selectedItem", "listButtonLabel.text");
-        namespaceBinding.bind();
+        // Bind list button selection to label text
+        NamespaceBinding namespaceBinding1 = new NamespaceBinding(namespace,
+            "listButton.selectedItem", "listButtonLabel1.text");
+
+        namespaceBinding1.bind();
+
+        // Bind list button selection to label text with bind mapping
+        NamespaceBinding namespaceBinding2 = new NamespaceBinding(namespace,
+            "listButton.selectedItem", "listButtonLabel2.text", new NamespaceBinding.BindMapping() {
+            @Override
+            public Object evaluate(Object value) {
+                return value.toString().toUpperCase();
+            }
+        });
+
+        namespaceBinding2.bind();
+    }
+
+    public static String toHex(Color color) {
+        return String.format("#%02X%02X%02X", color.getRed(), color.getBlue(), color.getGreen());
     }
 }

Modified: pivot/trunk/tutorials/src/org/apache/pivot/tutorials/databinding/property_binding.bxml
URL: http://svn.apache.org/viewvc/pivot/trunk/tutorials/src/org/apache/pivot/tutorials/databinding/property_binding.bxml?rev=990170&r1=990169&r2=990170&view=diff
==============================================================================
--- pivot/trunk/tutorials/src/org/apache/pivot/tutorials/databinding/property_binding.bxml (original)
+++ pivot/trunk/tutorials/src/org/apache/pivot/tutorials/databinding/property_binding.bxml Fri Aug 27 15:02:11 2010
@@ -20,11 +20,24 @@ limitations under the License.
     xmlns:bxml="http://pivot.apache.org/bxml"
     xmlns:databinding="org.apache.pivot.tutorials.databinding"
     xmlns="org.apache.pivot.wtk">
+    <bxml:script>
+    importClass(org.apache.pivot.tutorials.databinding.PropertyBinding);
+
+    function toUpperCase(value) {
+        return value.toUpperCase();
+    }
+
+    function toHex(color) {
+        return PropertyBinding.toHex(color);
+    }
+    </bxml:script>
+
     <Border>
         <Form>
             <Form.Section heading="One-Way Binding">
                 <TextInput bxml:id="textInput" Form.label="Text Input"/>
-                <Label bxml:id="textInputLabel" Form.label="Text" text="${textInput.text}"/>
+                <Label Form.label="Text" text="${textInput.text}"/>
+                <Label Form.label="Uppercase Text" text="${toUpperCase:textInput.text}"/>
             </Form.Section>
 
             <Form.Section heading="Two-Way Binding">
@@ -35,16 +48,19 @@ limitations under the License.
             <Form.Section heading="Style Binding">
                 <ColorChooserButton bxml:id="colorChooserButton" Form.label="Color Chooser Button"
                     selectedColor="#000000"/>
-                <Label bxml:id="colorChooserLabel" Form.label="Selected Color"
-                    text="${colorChooserButton.selectedColor}">
+                <Label Form.label="Selected Color" text="${colorChooserButton.selectedColor}">
                     <styles color="${colorChooserButton.selectedColor}"/>
                 </Label>
+                <Label Form.label="Selected Color (Hex)" text="${toHex:colorChooserButton.selectedColor}">
+                    <styles color="${toHex:colorChooserButton.selectedColor}"/>
+                </Label>
             </Form.Section>
 
             <Form.Section heading="Manual Binding">
                 <ListButton bxml:id="listButton" Form.label="List Button"
                     listData="['Zero', 'One', 'Two', 'Three']" selectedIndex="0"/>
-                <Label bxml:id="listButtonLabel" Form.label="Selected Index"/>
+                <Label bxml:id="listButtonLabel1" Form.label="Selected Item"/>
+                <Label bxml:id="listButtonLabel2" Form.label="Uppercase Selected Item"/>
             </Form.Section>
         </Form>
     </Border>