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 2009/11/11 21:25:52 UTC

svn commit: r835045 - in /incubator/pivot/trunk: core/src/org/apache/pivot/serialization/ core/src/org/apache/pivot/xml/ demos/src/org/apache/pivot/demos/million/ tools/src/org/apache/pivot/tools/json/ tools/src/org/apache/pivot/tools/xml/

Author: gbrown
Date: Wed Nov 11 20:25:51 2009
New Revision: 835045

URL: http://svn.apache.org/viewvc?rev=835045&view=rev
Log:
Add XML Viewer tool; fix issues in XML classes; make ISO-8859 the default encoding for CSVSerializer; make UTF-8 the default encoding for JSONSerializer.

Added:
    incubator/pivot/trunk/tools/src/org/apache/pivot/tools/xml/
    incubator/pivot/trunk/tools/src/org/apache/pivot/tools/xml/NodeRenderer.java
    incubator/pivot/trunk/tools/src/org/apache/pivot/tools/xml/XMLViewer.java
    incubator/pivot/trunk/tools/src/org/apache/pivot/tools/xml/xml_viewer.js
    incubator/pivot/trunk/tools/src/org/apache/pivot/tools/xml/xml_viewer.wtkx
Modified:
    incubator/pivot/trunk/core/src/org/apache/pivot/serialization/CSVSerializer.java
    incubator/pivot/trunk/core/src/org/apache/pivot/serialization/JSONSerializer.java
    incubator/pivot/trunk/core/src/org/apache/pivot/xml/Element.java
    incubator/pivot/trunk/core/src/org/apache/pivot/xml/XMLSerializer.java
    incubator/pivot/trunk/demos/src/org/apache/pivot/demos/million/LargeData.java
    incubator/pivot/trunk/tools/src/org/apache/pivot/tools/json/JSONViewer.java
    incubator/pivot/trunk/tools/src/org/apache/pivot/tools/json/json_viewer.wtkx

Modified: incubator/pivot/trunk/core/src/org/apache/pivot/serialization/CSVSerializer.java
URL: http://svn.apache.org/viewvc/incubator/pivot/trunk/core/src/org/apache/pivot/serialization/CSVSerializer.java?rev=835045&r1=835044&r2=835045&view=diff
==============================================================================
--- incubator/pivot/trunk/core/src/org/apache/pivot/serialization/CSVSerializer.java (original)
+++ incubator/pivot/trunk/core/src/org/apache/pivot/serialization/CSVSerializer.java Wed Nov 11 20:25:51 2009
@@ -136,12 +136,13 @@
     private KeySequence keySequence = new KeySequence();
     private LineNumberReader lineNumberReader = null;
 
+    public static final String DEFAULT_CHARSET_NAME = "ISO-8859-1";
     public static final String MIME_TYPE = "text/csv";
     public static final int BUFFER_SIZE = 2048;
 
 
     public CSVSerializer() {
-        this(Charset.defaultCharset());
+        this(DEFAULT_CHARSET_NAME);
     }
 
     public CSVSerializer(String charsetName) {

Modified: incubator/pivot/trunk/core/src/org/apache/pivot/serialization/JSONSerializer.java
URL: http://svn.apache.org/viewvc/incubator/pivot/trunk/core/src/org/apache/pivot/serialization/JSONSerializer.java?rev=835045&r1=835044&r2=835045&view=diff
==============================================================================
--- incubator/pivot/trunk/core/src/org/apache/pivot/serialization/JSONSerializer.java (original)
+++ incubator/pivot/trunk/core/src/org/apache/pivot/serialization/JSONSerializer.java Wed Nov 11 20:25:51 2009
@@ -50,11 +50,12 @@
     private boolean alwaysDelimitMapKeys = false;
     private LineNumberReader lineNumberReader = null;
 
+    public static final String DEFAULT_CHARSET_NAME = "UTF-8";
     public static final String MIME_TYPE = "application/json";
     public static final int BUFFER_SIZE = 2048;
 
     public JSONSerializer() {
-        this(Charset.defaultCharset());
+        this(DEFAULT_CHARSET_NAME);
     }
 
     public JSONSerializer(String charsetName) {

Modified: incubator/pivot/trunk/core/src/org/apache/pivot/xml/Element.java
URL: http://svn.apache.org/viewvc/incubator/pivot/trunk/core/src/org/apache/pivot/xml/Element.java?rev=835045&r1=835044&r2=835045&view=diff
==============================================================================
--- incubator/pivot/trunk/core/src/org/apache/pivot/xml/Element.java (original)
+++ incubator/pivot/trunk/core/src/org/apache/pivot/xml/Element.java Wed Nov 11 20:25:51 2009
@@ -255,7 +255,9 @@
             for (int i = 1, n = namespacePrefix.length(); i < n; i++) {
                 c = namespacePrefix.charAt(i);
 
-                if (!Character.isLetterOrDigit(c)) {
+                if (!Character.isLetterOrDigit(c)
+                    && c != '-'
+                    && c != '.') {
                     throw new IllegalArgumentException("'" + c + "' is not a valid character"
                         + " for a namespace prefix.");
                 }
@@ -480,6 +482,13 @@
     }
 
     /**
+     * Returns an iterator over this element's attributes.
+     */
+    public Iterator<String> getAttributes() {
+        return new ImmutableIterator<String>(attributes.iterator());
+    }
+
+    /**
      * Adds a node to this element.
      *
      * @param node
@@ -489,7 +498,12 @@
      */
     @Override
     public int add(Node node) {
+        if (node.getParent() != null) {
+            throw new IllegalArgumentException();
+        }
+
         int index = nodes.add(node);
+        node.setParent(this);
         listListeners.itemInserted(this, index);
 
         return index;
@@ -503,22 +517,22 @@
      */
     @Override
     public void insert(Node node, int index) {
+        if (node.getParent() != null) {
+            throw new IllegalArgumentException();
+        }
+
         nodes.insert(node, index);
+        node.setParent(this);
         listListeners.itemInserted(this, index);
     }
 
     /**
-     * Updates the node at the given location.
-     *
-     * @param index
-     * @param node
+     * @throws UnsupportedOperationException
+     * This method is not supported.
      */
     @Override
     public Node update(int index, Node node) {
-        Node previousNode = nodes.update(index, node);
-        listListeners.itemUpdated(this, index, previousNode);
-
-        return previousNode;
+        throw new UnsupportedOperationException();
     }
 
     /**
@@ -549,6 +563,11 @@
     public Sequence<Node> remove(int index, int count) {
         Sequence<Node> removed = nodes.remove(index, count);
         if (count > 0) {
+            for (int i = 0, n = removed.getLength(); i < n; i++ ) {
+                Node node = removed.get(i);
+                node.setParent(null);
+            }
+
             listListeners.itemsRemoved(this, index, removed);
         }
 
@@ -561,6 +580,11 @@
     @Override
     public void clear() {
         if (getLength() > 0) {
+            for (int i = 0, n = nodes.getLength(); i < n; i++) {
+                Node node = nodes.get(i);
+                node.setParent(null);
+            }
+
             nodes.clear();
             listListeners.listCleared(this);
         }

Modified: incubator/pivot/trunk/core/src/org/apache/pivot/xml/XMLSerializer.java
URL: http://svn.apache.org/viewvc/incubator/pivot/trunk/core/src/org/apache/pivot/xml/XMLSerializer.java?rev=835045&r1=835044&r2=835045&view=diff
==============================================================================
--- incubator/pivot/trunk/core/src/org/apache/pivot/xml/XMLSerializer.java (original)
+++ incubator/pivot/trunk/core/src/org/apache/pivot/xml/XMLSerializer.java Wed Nov 11 20:25:51 2009
@@ -16,9 +16,16 @@
  */
 package org.apache.pivot.xml;
 
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
 import java.io.IOException;
 import java.io.InputStream;
+import java.io.InputStreamReader;
 import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.Reader;
+import java.io.Writer;
+import java.nio.charset.Charset;
 
 import javax.xml.stream.XMLInputFactory;
 import javax.xml.stream.XMLStreamConstants;
@@ -32,21 +39,38 @@
  * Reads and writes XML data.
  */
 public class XMLSerializer implements Serializer<Element> {
-    public static final String MIME_TYPE = "text/xml";
-
+    private Charset charset = null;
     private XMLInputFactory xmlInputFactory;
 
     private Element element = null;
 
     public static final String XMLNS_ATTRIBUTE_PREFIX = "xmlns";
 
+    public static final String DEFAULT_CHARSET_NAME = "UTF-8";
+    public static final String MIME_TYPE = "text/xml";
+    public static final int BUFFER_SIZE = 2048;
+
     public XMLSerializer() {
-        this(true);
+        this(DEFAULT_CHARSET_NAME);
     }
 
-    public XMLSerializer(boolean coalesceText) {
+    public XMLSerializer(String charsetName) {
+        this(charsetName == null ? Charset.defaultCharset() : Charset.forName(charsetName));
+    }
+
+    public XMLSerializer(Charset charset) {
+        if (charset == null) {
+            throw new IllegalArgumentException("charset is null.");
+        }
+
+        this.charset = charset;
+
         xmlInputFactory = XMLInputFactory.newInstance();
-        xmlInputFactory.setProperty("javax.xml.stream.isCoalescing", coalesceText);
+        xmlInputFactory.setProperty("javax.xml.stream.isCoalescing", true);
+    }
+
+    public Charset getCharset() {
+        return charset;
     }
 
     @Override
@@ -55,50 +79,74 @@
             throw new IllegalArgumentException("inputStream is null.");
         }
 
+        Reader reader = new BufferedReader(new InputStreamReader(inputStream, charset), BUFFER_SIZE);
+        Element element = readObject(reader);
+
+        return element;
+    }
+
+    public Element readObject(Reader reader) throws SerializationException {
+        if (reader == null) {
+            throw new IllegalArgumentException("reader is null.");
+        }
+
         // Parse the XML stream
         element = null;
 
         try {
-            XMLStreamReader reader = xmlInputFactory.createXMLStreamReader(inputStream);
+            XMLStreamReader xmlStreamReader = xmlInputFactory.createXMLStreamReader(reader);
 
-            while (reader.hasNext()) {
-                int event = reader.next();
+            while (xmlStreamReader.hasNext()) {
+                int event = xmlStreamReader.next();
 
                 switch (event) {
+                    case XMLStreamConstants.NAMESPACE: {
+                        // TODO
+                        break;
+                    }
+
                     case XMLStreamConstants.CHARACTERS: {
-                        element.add(new TextNode(reader.getText()));
+                        String text = xmlStreamReader.getText();
+                        text = text.trim();
+                        if (text.length() > 0) {
+                            element.add(new TextNode(text));
+                        }
+
                         break;
                     }
 
                     case XMLStreamConstants.START_ELEMENT: {
                         // Create the element
-                        String prefix = reader.getPrefix();
-                        String localName = reader.getLocalName();
+                        String prefix = xmlStreamReader.getPrefix();
+                        if (prefix.length() == 0) {
+                            prefix = null;
+                        }
 
-                        Element element = new Element(prefix, localName);
+                        String localName = xmlStreamReader.getLocalName();
 
-                        for (int i = 0, n = reader.getAttributeCount(); i < n; i++) {
-                            String attributePrefix = reader.getAttributePrefix(i);
-                            String attributeLocalName = reader.getAttributeLocalName(i);
-                            String attributeValue = reader.getAttributeValue(i);
-
-                            if (attributePrefix != null) {
-                                if (!attributePrefix.equals(XMLNS_ATTRIBUTE_PREFIX)) {
-                                    throw new SerializationException("Attribute namespaces are not supported.");
-                                }
+                        Element element = new Element(prefix, localName);
 
-                                element.getNamespaces().put(attributeLocalName, attributeValue);
+                        for (int i = 0, n = xmlStreamReader.getAttributeCount(); i < n; i++) {
+                            String attributePrefix = xmlStreamReader.getAttributePrefix(i);
+                            String attributeLocalName = xmlStreamReader.getAttributeLocalName(i);
+                            String attributeValue = xmlStreamReader.getAttributeValue(i);
+
+                            String attribute;
+                            if (attributePrefix.length() == 0) {
+                                attribute = attributeLocalName;
                             } else {
-                                element.put(attributeLocalName, attributeValue);
+                                attribute = attributePrefix + ":" + attributeLocalName;
                             }
+
+                            element.put(attribute, attributeValue);
                         }
 
-                        if (this.element == null) {
-                            this.element = element;
-                        } else {
+                        if (this.element != null) {
                             this.element.add(element);
                         }
 
+                        this.element = element;
+
                         break;
                     }
 
@@ -114,7 +162,7 @@
                 }
             }
 
-            reader.close();
+            xmlStreamReader.close();
         } catch (XMLStreamException exception) {
             throw new SerializationException(exception);
         }
@@ -123,10 +171,29 @@
     }
 
     @Override
-    public void writeObject(Element object, OutputStream outputStream)
+    public void writeObject(Element element, OutputStream outputStream)
         throws IOException, SerializationException {
+        if (outputStream == null) {
+            throw new IllegalArgumentException("outputStream is null.");
+        }
+
+        Writer writer = new BufferedWriter(new OutputStreamWriter(outputStream, charset),
+            BUFFER_SIZE);
+        writeObject(element, writer);
+    }
+
+    public void writeObject(Element element, Writer writer) {
+        if (writer == null) {
+            throw new IllegalArgumentException("writer is null.");
+        }
+
+        if (element == null) {
+            throw new IllegalArgumentException("element is null.");
+        }
+
         // TODO (note that we'll need to check for valid namespace prefixes here,
         // since we don't do it in Element)
+
         throw new UnsupportedOperationException();
     }
 

Modified: incubator/pivot/trunk/demos/src/org/apache/pivot/demos/million/LargeData.java
URL: http://svn.apache.org/viewvc/incubator/pivot/trunk/demos/src/org/apache/pivot/demos/million/LargeData.java?rev=835045&r1=835044&r2=835045&view=diff
==============================================================================
--- incubator/pivot/trunk/demos/src/org/apache/pivot/demos/million/LargeData.java (original)
+++ incubator/pivot/trunk/demos/src/org/apache/pivot/demos/million/LargeData.java Wed Nov 11 20:25:51 2009
@@ -79,7 +79,7 @@
                 try {
                     inputStream = fileURL.openStream();
 
-                    CSVSerializer csvSerializer = new CSVSerializer("ISO-8859-1");
+                    CSVSerializer csvSerializer = new CSVSerializer();
                     csvSerializer.getKeys().add("c0");
                     csvSerializer.getKeys().add("c1");
                     csvSerializer.getKeys().add("c2");
@@ -152,7 +152,7 @@
     private static final String BASE_PATH_KEY = "basePath";
 
     public LargeData() {
-        csvSerializer = new CSVSerializer("ISO-8859-1");
+        csvSerializer = new CSVSerializer();
         csvSerializer.getKeys().add("c0");
         csvSerializer.getKeys().add("c1");
         csvSerializer.getKeys().add("c2");

Modified: incubator/pivot/trunk/tools/src/org/apache/pivot/tools/json/JSONViewer.java
URL: http://svn.apache.org/viewvc/incubator/pivot/trunk/tools/src/org/apache/pivot/tools/json/JSONViewer.java?rev=835045&r1=835044&r2=835045&view=diff
==============================================================================
--- incubator/pivot/trunk/tools/src/org/apache/pivot/tools/json/JSONViewer.java (original)
+++ incubator/pivot/trunk/tools/src/org/apache/pivot/tools/json/JSONViewer.java Wed Nov 11 20:25:51 2009
@@ -42,11 +42,14 @@
 import org.apache.pivot.wtk.content.TreeBranch;
 import org.apache.pivot.wtk.content.TreeNode;
 import org.apache.pivot.wtk.effects.OverlayDecorator;
+import org.apache.pivot.wtkx.WTKX;
 import org.apache.pivot.wtkx.WTKXSerializer;
 
 public class JSONViewer implements Application {
     private Window window = null;
-    private TreeView treeView = null;
+
+    @WTKX private TreeView treeView = null;
+
     private OverlayDecorator promptDecorator = new OverlayDecorator();
 
     public static final String APPLICATION_KEY = "application";
@@ -59,7 +62,7 @@
         wtkxSerializer.put(APPLICATION_KEY, this);
 
         window = (Window)wtkxSerializer.readObject(this, "json_viewer.wtkx");
-        treeView = (TreeView)wtkxSerializer.get("treeView");
+        wtkxSerializer.bind(this);
 
         Label prompt = new Label("Drag or paste JSON here");
         prompt.getStyles().put("horizontalAlignment", HorizontalAlignment.CENTER);

Modified: incubator/pivot/trunk/tools/src/org/apache/pivot/tools/json/json_viewer.wtkx
URL: http://svn.apache.org/viewvc/incubator/pivot/trunk/tools/src/org/apache/pivot/tools/json/json_viewer.wtkx?rev=835045&r1=835044&r2=835045&view=diff
==============================================================================
--- incubator/pivot/trunk/tools/src/org/apache/pivot/tools/json/json_viewer.wtkx (original)
+++ incubator/pivot/trunk/tools/src/org/apache/pivot/tools/json/json_viewer.wtkx Wed Nov 11 20:25:51 2009
@@ -37,7 +37,7 @@
                                 importPackage(org.apache.pivot.wtk);
                                 function keyPressed(component, keyCode, keyLocation) {
                                     if (keyCode == Keyboard.KeyCode.V
-                                        && Keyboard.isPressed(Keyboard.Modifier.CTRL)) {
+                                        && Keyboard.isPressed(Platform.getCommandModifier())) {
                                         application.paste();
                                     }
                                 }

Added: incubator/pivot/trunk/tools/src/org/apache/pivot/tools/xml/NodeRenderer.java
URL: http://svn.apache.org/viewvc/incubator/pivot/trunk/tools/src/org/apache/pivot/tools/xml/NodeRenderer.java?rev=835045&view=auto
==============================================================================
--- incubator/pivot/trunk/tools/src/org/apache/pivot/tools/xml/NodeRenderer.java (added)
+++ incubator/pivot/trunk/tools/src/org/apache/pivot/tools/xml/NodeRenderer.java Wed Nov 11 20:25:51 2009
@@ -0,0 +1,85 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.pivot.tools.xml;
+
+import java.awt.Color;
+import java.awt.Font;
+
+import org.apache.pivot.collections.Sequence;
+import org.apache.pivot.wtk.Label;
+import org.apache.pivot.wtk.TreeView;
+import org.apache.pivot.xml.Element;
+import org.apache.pivot.xml.TextNode;
+
+public class NodeRenderer extends Label implements TreeView.NodeRenderer {
+    public static int MAXIMUM_TEXT_LENGTH = 20;
+
+    @Override
+    public void setSize(int width, int height) {
+        super.setSize(width, height);
+
+        // Since this component doesn't have a parent, it won't be validated
+        // via layout; ensure that it is valid here
+        validate();
+    }
+
+    @Override
+    public void render(Object node, Sequence.Tree.Path path, int rowIndex, TreeView treeView,
+        boolean expanded, boolean selected, TreeView.NodeCheckState checkState,
+        boolean highlighted, boolean disabled) {
+        if (node != null) {
+            String text;
+            if (node instanceof Element) {
+                Element element = (Element)node;
+                text = "<" + element.getName() + ">";
+            } else if (node instanceof TextNode) {
+                TextNode textNode = (TextNode)node;
+                text = textNode.getText();
+
+                if (text.length() > MAXIMUM_TEXT_LENGTH) {
+                    text = "\"" + text.substring(0, MAXIMUM_TEXT_LENGTH) + "\"...";
+                } else {
+                    text = "\"" + text + "\"";
+                }
+            } else {
+                throw new IllegalArgumentException();
+            }
+
+            setText(text);
+
+            Font font = (Font)treeView.getStyles().get("font");
+            getStyles().put("font", font);
+
+            Color color;
+            if (treeView.isEnabled() && !disabled) {
+                if (selected) {
+                    if (treeView.isFocused()) {
+                        color = (Color)treeView.getStyles().get("selectionColor");
+                    } else {
+                        color = (Color)treeView.getStyles().get("inactiveSelectionColor");
+                    }
+                } else {
+                    color = (Color)treeView.getStyles().get("color");
+                }
+            } else {
+                color = (Color)treeView.getStyles().get("disabledColor");
+            }
+
+            getStyles().put("color", color);
+        }
+    }
+}

Added: incubator/pivot/trunk/tools/src/org/apache/pivot/tools/xml/XMLViewer.java
URL: http://svn.apache.org/viewvc/incubator/pivot/trunk/tools/src/org/apache/pivot/tools/xml/XMLViewer.java?rev=835045&view=auto
==============================================================================
--- incubator/pivot/trunk/tools/src/org/apache/pivot/tools/xml/XMLViewer.java (added)
+++ incubator/pivot/trunk/tools/src/org/apache/pivot/tools/xml/XMLViewer.java Wed Nov 11 20:25:51 2009
@@ -0,0 +1,206 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.pivot.tools.xml;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.StringReader;
+import java.util.Iterator;
+
+import org.apache.pivot.collections.ArrayList;
+import org.apache.pivot.collections.HashMap;
+import org.apache.pivot.collections.Map;
+import org.apache.pivot.collections.Sequence;
+import org.apache.pivot.io.FileList;
+import org.apache.pivot.wtk.Application;
+import org.apache.pivot.wtk.CardPane;
+import org.apache.pivot.wtk.Clipboard;
+import org.apache.pivot.wtk.DesktopApplicationContext;
+import org.apache.pivot.wtk.Display;
+import org.apache.pivot.wtk.DropAction;
+import org.apache.pivot.wtk.HorizontalAlignment;
+import org.apache.pivot.wtk.Label;
+import org.apache.pivot.wtk.Manifest;
+import org.apache.pivot.wtk.Prompt;
+import org.apache.pivot.wtk.TableView;
+import org.apache.pivot.wtk.TextArea;
+import org.apache.pivot.wtk.TreeView;
+import org.apache.pivot.wtk.VerticalAlignment;
+import org.apache.pivot.wtk.Window;
+import org.apache.pivot.wtk.effects.OverlayDecorator;
+import org.apache.pivot.wtkx.WTKX;
+import org.apache.pivot.wtkx.WTKXSerializer;
+import org.apache.pivot.xml.Element;
+import org.apache.pivot.xml.Node;
+import org.apache.pivot.xml.TextNode;
+import org.apache.pivot.xml.XMLSerializer;
+
+public class XMLViewer implements Application {
+    private Window window = null;
+
+    @WTKX private TreeView treeView = null;
+    @WTKX private CardPane propertiesCardPane = null;
+    @WTKX private TableView attributesTableView = null;
+    @WTKX private TextArea textArea = null;
+
+    private OverlayDecorator promptDecorator = new OverlayDecorator();
+
+    public static final String APPLICATION_KEY = "application";
+    public static final String WINDOW_TITLE = "XML Viewer";
+
+    @Override
+    public void startup(Display display, Map<String, String> properties)
+        throws Exception {
+        WTKXSerializer wtkxSerializer = new WTKXSerializer();
+        wtkxSerializer.put(APPLICATION_KEY, this);
+
+        window = (Window)wtkxSerializer.readObject(this, "xml_viewer.wtkx");
+        wtkxSerializer.bind(this);
+
+        Label prompt = new Label("Drag or paste XML here");
+        prompt.getStyles().put("horizontalAlignment", HorizontalAlignment.CENTER);
+        prompt.getStyles().put("verticalAlignment", VerticalAlignment.CENTER);
+        promptDecorator.setOverlay(prompt);
+        treeView.getDecorators().add(promptDecorator);
+
+        window.setTitle(WINDOW_TITLE);
+        window.open(display);
+        window.requestFocus();
+    }
+
+    @Override
+    public boolean shutdown(boolean optional) {
+        if (window != null) {
+            window.close();
+        }
+
+        return false;
+    }
+
+    @Override
+    public void suspend() {
+    }
+
+    @Override
+    public void resume() {
+    }
+
+    public void paste() {
+        Manifest clipboardContent = Clipboard.getContent();
+
+        if (clipboardContent != null
+            && clipboardContent.containsText()) {
+            String xml = null;
+            XMLSerializer xmlSerializer = new XMLSerializer();
+            try {
+                xml = clipboardContent.getText();
+                setDocument(xmlSerializer.readObject(new StringReader(xml)));
+            } catch (Exception exception) {
+                Prompt.prompt(exception.getMessage(), window);
+            }
+
+            window.setTitle(WINDOW_TITLE);
+        }
+    }
+
+    public DropAction drop(Manifest dragContent) {
+        DropAction dropAction = null;
+
+        try {
+            FileList fileList = dragContent.getFileList();
+            if (fileList.getLength() == 1) {
+                File file = fileList.get(0);
+
+                XMLSerializer xmlSerializer = new XMLSerializer();
+                FileInputStream fileInputStream = null;
+                try {
+                    try {
+                        fileInputStream = new FileInputStream(file);
+                        setDocument(xmlSerializer.readObject(fileInputStream));
+                    } finally {
+                        if (fileInputStream != null) {
+                            fileInputStream.close();
+                        }
+                    }
+                } catch (Exception exception) {
+                    Prompt.prompt(exception.getMessage(), window);
+                }
+
+                window.setTitle(WINDOW_TITLE + " - " + file.getName());
+
+                dropAction = DropAction.COPY;
+            } else {
+                Prompt.prompt("Multiple files not supported.", window);
+            }
+        } catch(IOException exception) {
+            Prompt.prompt(exception.getMessage(), window);
+        }
+
+        return dropAction;
+    }
+
+    public void updateProperties() {
+        Node node = (Node)treeView.getSelectedNode();
+
+        if (node instanceof TextNode) {
+            TextNode textNode = (TextNode)node;
+            textArea.setText(textNode.getText());
+            propertiesCardPane.setSelectedIndex(1);
+        } else if (node instanceof Element) {
+            Element element = (Element)node;
+
+            ArrayList<HashMap<String, String>> attributesTableData =
+                new ArrayList<HashMap<String, String>>();
+            Iterator<String> attributes = element.getAttributes();
+
+            while (attributes.hasNext()) {
+                String attribute = attributes.next();
+                HashMap<String, String> row = new HashMap<String, String>();
+                row.put("attribute", attribute);
+                row.put("value", element.get(attribute));
+                attributesTableData.add(row);
+            }
+
+            attributesTableView.setTableData(attributesTableData);
+
+            propertiesCardPane.setSelectedIndex(0);
+        } else {
+            propertiesCardPane.setSelectedIndex(-1);
+        }
+    }
+
+    private void setDocument(Element document) {
+        // Remove prompt decorator
+        if (promptDecorator != null) {
+            treeView.getDecorators().remove(promptDecorator);
+            promptDecorator = null;
+        }
+
+        ArrayList<Element> treeData = new ArrayList<Element>();
+        treeData.add(document);
+        treeView.setTreeData(treeData);
+
+        Sequence.Tree.Path path = new Sequence.Tree.Path(0);
+        treeView.expandBranch(path);
+        treeView.setSelectedPath(path);
+    }
+
+    public static void main(String[] args) {
+        DesktopApplicationContext.main(XMLViewer.class, args);
+    }
+}

Added: incubator/pivot/trunk/tools/src/org/apache/pivot/tools/xml/xml_viewer.js
URL: http://svn.apache.org/viewvc/incubator/pivot/trunk/tools/src/org/apache/pivot/tools/xml/xml_viewer.js?rev=835045&view=auto
==============================================================================
--- incubator/pivot/trunk/tools/src/org/apache/pivot/tools/xml/xml_viewer.js (added)
+++ incubator/pivot/trunk/tools/src/org/apache/pivot/tools/xml/xml_viewer.js Wed Nov 11 20:25:51 2009
@@ -0,0 +1,55 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+importPackage(java.lang);
+importPackage(org.apache.pivot.wtk);
+
+var treeViewDropTarget = new DropTarget() {
+    dragEnter: function(component, dragContent, supportedDropActions, userDropAction) {
+        var dropAction = null;
+
+        if (dragContent.containsFileList()
+            && DropAction.COPY.isSelected(supportedDropActions)) {
+            dropAction = DropAction.COPY;
+        }
+
+        return dropAction;
+    },
+
+    dragExit: function(component) {
+    },
+
+    dragMove: function(component, dragContent, supportedDropActions, x, y, userDropAction) {
+        return (dragContent.containsFileList() ? DropAction.COPY : null);
+    },
+
+    userDropActionChange: function(component, dragContent, supportedDropActions, x, y, 
+        userDropAction) {
+        return (dragContent.containsFileList() ? DropAction.COPY : null);
+    },
+
+    drop: function(component, dragContent, supportedDropActions, x, y, userDropAction) {
+        var dropAction = null;
+
+        if (dragContent.containsFileList()) {
+            return application.drop(dragContent);                
+        }
+
+        dragExit(component);
+
+        return dropAction;
+    }
+};

Added: incubator/pivot/trunk/tools/src/org/apache/pivot/tools/xml/xml_viewer.wtkx
URL: http://svn.apache.org/viewvc/incubator/pivot/trunk/tools/src/org/apache/pivot/tools/xml/xml_viewer.wtkx?rev=835045&view=auto
==============================================================================
--- incubator/pivot/trunk/tools/src/org/apache/pivot/tools/xml/xml_viewer.wtkx (added)
+++ incubator/pivot/trunk/tools/src/org/apache/pivot/tools/xml/xml_viewer.wtkx Wed Nov 11 20:25:51 2009
@@ -0,0 +1,100 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to you under the Apache License,
+Version 2.0 (the "License"); you may not use this file except in
+compliance with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+
+<Window maximized="true"
+    xmlns:wtkx="http://pivot.apache.org/wtkx"
+    xmlns:tools.xml="org.apache.pivot.tools.xml"
+    xmlns="org.apache.pivot.wtk">
+    <wtkx:script src="xml_viewer.js"/>
+    <content>
+        <Border styles="{padding:4}">
+            <content>
+                <SplitPane splitRatio="0.6">
+                    <left>
+                        <Border styles="{color:10}">
+                            <content>
+                                <ScrollPane horizontalScrollBarPolicy="fill_to_capacity"
+                                    verticalScrollBarPolicy="fill_to_capacity">
+                                    <view>
+                                        <TreeView wtkx:id="treeView" dropTarget="$treeViewDropTarget">
+                                            <nodeRenderer>
+                                                <tools.xml:NodeRenderer/>
+                                            </nodeRenderer>
+                                            <componentKeyListeners>
+                                                <wtkx:script>
+                                                <![CDATA[
+                                                importPackage(org.apache.pivot.wtk);
+                                                function keyPressed(component, keyCode, keyLocation) {
+                                                    if (keyCode == Keyboard.KeyCode.V
+                                                        && Keyboard.isPressed(Platform.getCommandModifier())) {
+                                                        application.paste();
+                                                    }
+                                                }
+                                                ]]>
+                                                </wtkx:script>
+                                            </componentKeyListeners>
+                                            <treeViewSelectionListeners>
+                                                <wtkx:script>
+                                                <![CDATA[
+                                                function selectedPathsChanged(treeView, previousSelectedPaths) {
+                                                    application.updateProperties();
+                                                }
+                                                ]]>
+                                                </wtkx:script>
+                                            </treeViewSelectionListeners>
+                                        </TreeView>
+                                    </view>
+                                </ScrollPane>
+                            </content>
+                        </Border>
+                    </left>
+                    <right>
+                        <Border styles="{color:10}">
+                            <content>
+                                <CardPane wtkx:id="propertiesCardPane">
+                                    <ScrollPane horizontalScrollBarPolicy="fill_to_capacity"
+                                        verticalScrollBarPolicy="fill_to_capacity">
+                                        <view>
+                                            <TableView wtkx:id="attributesTableView" selectMode="none">
+                                                <columns>
+                                                    <TableView.Column name="attribute" width="1*" headerData="Attribute"/>
+                                                    <TableView.Column name="value" width="1*" headerData="Value"/>
+                                                </columns>
+                                            </TableView>
+                                        </view>
+                                        <columnHeader>
+                                            <TableViewHeader tableView="$attributesTableView"/>
+                                        </columnHeader>
+                                    </ScrollPane>
+
+                                    <ScrollPane horizontalScrollBarPolicy="fill"
+                                        verticalScrollBarPolicy="fill_to_capacity">
+                                        <view>
+                                            <TextArea wtkx:id="textArea"/>
+                                        </view>
+                                    </ScrollPane>
+                                </CardPane>
+
+                            </content>
+                        </Border>
+                    </right>
+                </SplitPane>
+            </content>
+        </Border>
+    </content>
+</Window>