You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@pivot.apache.org by tv...@apache.org on 2010/07/29 17:46:30 UTC

svn commit: r980482 [4/4] - in /pivot/trunk: ./ core/src/org/apache/pivot/beans/ core/src/org/apache/pivot/json/ core/src/org/apache/pivot/util/ core/test/org/apache/pivot/json/test/ demos-server/ demos-server/src/org/apache/pivot/demos/rest/server/ de...

Modified: pivot/trunk/wtk/src/org/apache/pivot/wtk/skin/TextAreaSkinSpanView.java
URL: http://svn.apache.org/viewvc/pivot/trunk/wtk/src/org/apache/pivot/wtk/skin/TextAreaSkinSpanView.java?rev=980482&r1=980481&r2=980482&view=diff
==============================================================================
--- pivot/trunk/wtk/src/org/apache/pivot/wtk/skin/TextAreaSkinSpanView.java (original)
+++ pivot/trunk/wtk/src/org/apache/pivot/wtk/skin/TextAreaSkinSpanView.java Thu Jul 29 15:46:23 2010
@@ -1,151 +1,151 @@
-/*
- * 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.wtk.skin;
-
-import org.apache.pivot.collections.Sequence;
-import org.apache.pivot.wtk.FocusTraversalDirection;
-import org.apache.pivot.wtk.text.Element;
-import org.apache.pivot.wtk.text.Node;
-import org.apache.pivot.wtk.text.TextNode;
-
-/**
- * Span node view.
- */
-class TextAreaSkinSpanView extends TextAreaSkinElementView {
-
-    private final TextAreaSkin textAreaSkin;
-
-    public TextAreaSkinSpanView(TextAreaSkin textAreaSkin, org.apache.pivot.wtk.text.Span span) {
-        super(span);
-        this.textAreaSkin = textAreaSkin;
-    }
-
-    @Override
-    public void validate() {
-
-        if (!isValid()) {
-            // I have to re-create my children here instead of in attach(),
-            // because that is how ParagraphView works,
-            // and ParagraphView is always my parent node.
-
-            // Clear all existing views
-            remove(0, getLength());
-
-            org.apache.pivot.wtk.text.Span span = (org.apache.pivot.wtk.text.Span)getNode();
-
-            // for now, assume that span contains at most one child, and
-            // that child is a TextNode
-            if (span.getLength() > 1) {
-                throw new IllegalStateException();
-            }
-
-            if (span.getLength() == 0) {
-                setSize(0, 0);
-            } else {
-
-                // create and attach child node views
-                add(new TextAreaSkinTextNodeView(textAreaSkin, (TextNode)span.get(0), 0));
-
-                int breakWidth = getBreakWidth();
-
-                TextAreaSkinNodeView nodeView = get(0);
-                nodeView.setBreakWidth(breakWidth);
-                nodeView.validate();
-
-                setSize(nodeView.getWidth(), nodeView.getHeight());
-            }
-        }
-
-        super.validate();
-    }
-
-    @Override
-    public int getCharacterCount() {
-        if (getLength() == 0) {
-            return 0;
-        } else {
-            return get(0).getCharacterCount();
-        }
-    }
-
-    @Override
-    public TextAreaSkinNodeView getNext() {
-        if (getLength() == 0) {
-            return null;
-        } else {
-            return get(0).getNext();
-        }
-    }
-
-    @Override
-    public int getInsertionPoint(int x, int y) {
-        if (getLength() == 0) {
-            return -1;
-        } else {
-            return get(0).getInsertionPoint(x, y);
-        }
-    }
-
-    @Override
-    public int getNextInsertionPoint(int x, int from, FocusTraversalDirection direction) {
-        if (getLength() == 0) {
-            return -1;
-        } else {
-            return get(0).getNextInsertionPoint(x, from, direction);
-        }
-    }
-
-    @Override
-    public int getRowCount() {
-        if (getLength() == 0) {
-            return 0;
-        } else {
-            return get(0).getRowCount();
-        }
-    }
-
-    @Override
-    public int getRowIndex(int offset) {
-        if (getLength() == 0) {
-            return 0;
-        } else {
-            return get(0).getRowIndex(offset);
-        }
-    }
-
-    @Override
-    protected void setSkinLocation(int skinX, int skinY) {
-        for (TextAreaSkinNodeView nodeView : this) {
-            nodeView.setSkinLocation(skinX, skinY + nodeView.getY());
-        }
-    }
-
-    @Override
-    public void nodeInserted(Element element, int index) {
-        super.nodeInserted(element, index);
-
-        org.apache.pivot.wtk.text.Span span = (org.apache.pivot.wtk.text.Span)getNode();
-        insert(textAreaSkin.createNodeView(span.get(index)), index);
-    }
-
-    @Override
-    public void nodesRemoved(Element element, int index, Sequence<Node> nodes) {
-        remove(index, nodes.getLength());
-
-        super.nodesRemoved(element, index, nodes);
-    }
+/*
+ * 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.wtk.skin;
+
+import org.apache.pivot.collections.Sequence;
+import org.apache.pivot.wtk.FocusTraversalDirection;
+import org.apache.pivot.wtk.text.Element;
+import org.apache.pivot.wtk.text.Node;
+import org.apache.pivot.wtk.text.TextNode;
+
+/**
+ * Span node view.
+ */
+class TextAreaSkinSpanView extends TextAreaSkinElementView {
+
+    private final TextAreaSkin textAreaSkin;
+
+    public TextAreaSkinSpanView(TextAreaSkin textAreaSkin, org.apache.pivot.wtk.text.Span span) {
+        super(span);
+        this.textAreaSkin = textAreaSkin;
+    }
+
+    @Override
+    public void validate() {
+
+        if (!isValid()) {
+            // I have to re-create my children here instead of in attach(),
+            // because that is how ParagraphView works,
+            // and ParagraphView is always my parent node.
+
+            // Clear all existing views
+            remove(0, getLength());
+
+            org.apache.pivot.wtk.text.Span span = (org.apache.pivot.wtk.text.Span)getNode();
+
+            // for now, assume that span contains at most one child, and
+            // that child is a TextNode
+            if (span.getLength() > 1) {
+                throw new IllegalStateException();
+            }
+
+            if (span.getLength() == 0) {
+                setSize(0, 0);
+            } else {
+
+                // create and attach child node views
+                add(new TextAreaSkinTextNodeView(textAreaSkin, (TextNode)span.get(0), 0));
+
+                int breakWidth = getBreakWidth();
+
+                TextAreaSkinNodeView nodeView = get(0);
+                nodeView.setBreakWidth(breakWidth);
+                nodeView.validate();
+
+                setSize(nodeView.getWidth(), nodeView.getHeight());
+            }
+        }
+
+        super.validate();
+    }
+
+    @Override
+    public int getCharacterCount() {
+        if (getLength() == 0) {
+            return 0;
+        } else {
+            return get(0).getCharacterCount();
+        }
+    }
+
+    @Override
+    public TextAreaSkinNodeView getNext() {
+        if (getLength() == 0) {
+            return null;
+        } else {
+            return get(0).getNext();
+        }
+    }
+
+    @Override
+    public int getInsertionPoint(int x, int y) {
+        if (getLength() == 0) {
+            return -1;
+        } else {
+            return get(0).getInsertionPoint(x, y);
+        }
+    }
+
+    @Override
+    public int getNextInsertionPoint(int x, int from, FocusTraversalDirection direction) {
+        if (getLength() == 0) {
+            return -1;
+        } else {
+            return get(0).getNextInsertionPoint(x, from, direction);
+        }
+    }
+
+    @Override
+    public int getRowCount() {
+        if (getLength() == 0) {
+            return 0;
+        } else {
+            return get(0).getRowCount();
+        }
+    }
+
+    @Override
+    public int getRowIndex(int offset) {
+        if (getLength() == 0) {
+            return 0;
+        } else {
+            return get(0).getRowIndex(offset);
+        }
+    }
+
+    @Override
+    protected void setSkinLocation(int skinX, int skinY) {
+        for (TextAreaSkinNodeView nodeView : this) {
+            nodeView.setSkinLocation(skinX, skinY + nodeView.getY());
+        }
+    }
+
+    @Override
+    public void nodeInserted(Element element, int index) {
+        super.nodeInserted(element, index);
+
+        org.apache.pivot.wtk.text.Span span = (org.apache.pivot.wtk.text.Span)getNode();
+        insert(textAreaSkin.createNodeView(span.get(index)), index);
+    }
+
+    @Override
+    public void nodesRemoved(Element element, int index, Sequence<Node> nodes) {
+        remove(index, nodes.getLength());
+
+        super.nodesRemoved(element, index, nodes);
+    }
 }
\ No newline at end of file

Propchange: pivot/trunk/wtk/src/org/apache/pivot/wtk/skin/TextAreaSkinSpanView.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: pivot/trunk/wtk/src/org/apache/pivot/wtk/skin/TextAreaSkinTextNodeView.java
URL: http://svn.apache.org/viewvc/pivot/trunk/wtk/src/org/apache/pivot/wtk/skin/TextAreaSkinTextNodeView.java?rev=980482&r1=980481&r2=980482&view=diff
==============================================================================
--- pivot/trunk/wtk/src/org/apache/pivot/wtk/skin/TextAreaSkinTextNodeView.java (original)
+++ pivot/trunk/wtk/src/org/apache/pivot/wtk/skin/TextAreaSkinTextNodeView.java Thu Jul 29 15:46:23 2010
@@ -1,434 +1,434 @@
-/*
- * 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.wtk.skin;
-
-import java.awt.Color;
-import java.awt.Font;
-import java.awt.Graphics2D;
-import java.awt.Rectangle;
-import java.awt.Shape;
-import java.awt.font.FontRenderContext;
-import java.awt.font.GlyphVector;
-import java.awt.font.LineMetrics;
-import java.awt.geom.Area;
-import java.awt.geom.Rectangle2D;
-import java.text.CharacterIterator;
-
-import org.apache.pivot.wtk.Bounds;
-import org.apache.pivot.wtk.FocusTraversalDirection;
-import org.apache.pivot.wtk.Platform;
-import org.apache.pivot.wtk.Span;
-import org.apache.pivot.wtk.TextArea;
-import org.apache.pivot.wtk.text.Element;
-import org.apache.pivot.wtk.text.TextNode;
-import org.apache.pivot.wtk.text.TextNodeListener;
-
-/**
- * Text node view.
- */
-class TextAreaSkinTextNodeView extends TextAreaSkinNodeView implements TextNodeListener {
-
-    private final TextAreaSkin textAreaSkin;
-
-    private int start;
-    private int length = 0;
-    private GlyphVector glyphVector = null;
-    private TextAreaSkinTextNodeView next = null;
-
-    public TextAreaSkinTextNodeView(TextAreaSkin textAreaSkin, TextNode textNode) {
-        this(textAreaSkin, textNode, 0);
-    }
-
-    public TextAreaSkinTextNodeView(TextAreaSkin textAreaSkin, TextNode textNode, int start) {
-        super(textNode);
-        this.textAreaSkin = textAreaSkin;
-        this.start = start;
-    }
-
-    @Override
-    protected void attach() {
-        super.attach();
-
-        TextNode textNode = (TextNode)getNode();
-        textNode.getTextNodeListeners().add(this);
-    }
-
-    @Override
-    protected void detach() {
-        super.detach();
-
-        TextNode textNode = (TextNode)getNode();
-        textNode.getTextNodeListeners().remove(this);
-    }
-
-    @Override
-    public void invalidate() {
-        length = 0;
-        next = null;
-        glyphVector = null;
-
-        super.invalidate();
-    }
-
-    @Override
-    public void validate() {
-        if (!isValid()) {
-            TextNode textNode = (TextNode)getNode();
-            FontRenderContext fontRenderContext = Platform.getFontRenderContext();
-
-            int breakWidth = getBreakWidth();
-            CharacterIterator ci = textNode.getCharacterIterator(start);
-
-            float lineWidth = 0;
-            int lastWhitespaceIndex = -1;
-
-            Font effectiveFont = getEffectiveFont();
-            char c = ci.first();
-            while (c != CharacterIterator.DONE
-                && lineWidth < breakWidth) {
-                if (Character.isWhitespace(c)) {
-                    lastWhitespaceIndex = ci.getIndex();
-                }
-
-                int i = ci.getIndex();
-                Rectangle2D characterBounds = effectiveFont.getStringBounds(ci, i, i + 1, fontRenderContext);
-                lineWidth += characterBounds.getWidth();
-
-                c = ci.current();
-            }
-
-            int end;
-            if (textAreaSkin.getWrapText()) {
-                if (textNode.getCharacterCount() == 0) {
-                    end = start;
-                } else {
-                    if (lineWidth < breakWidth) {
-                        end = ci.getEndIndex();
-                    } else {
-                        if (lastWhitespaceIndex == -1) {
-                            end = ci.getIndex() - 1;
-                            if (end <= start) {
-                                end = start + 1;
-                            }
-                        } else {
-                            end = lastWhitespaceIndex + 1;
-                        }
-                    }
-                }
-            } else {
-                end = ci.getEndIndex();
-            }
-
-            glyphVector = getEffectiveFont().createGlyphVector(fontRenderContext,
-                textNode.getCharacterIterator(start, end));
-
-            if (end < ci.getEndIndex()) {
-                length = end - start;
-                next = new TextAreaSkinTextNodeView(textAreaSkin, textNode, end);
-            } else {
-                length = ci.getEndIndex() - start;
-            }
-
-            Rectangle2D textBounds = glyphVector.getLogicalBounds();
-            setSize((int)Math.ceil(textBounds.getWidth()),
-                (int)Math.ceil(textBounds.getHeight()));
-        }
-
-        super.validate();
-    }
-
-    @Override
-    protected void setSkinLocation(int skinX, int skinY) {
-    }
-
-    @Override
-    public void paint(Graphics2D graphics) {
-        if (glyphVector != null) {
-            TextArea textArea = (TextArea)textAreaSkin.getComponent();
-
-            FontRenderContext fontRenderContext = Platform.getFontRenderContext();
-            LineMetrics lm = getEffectiveFont().getLineMetrics("", fontRenderContext);
-            float ascent = lm.getAscent();
-            int strikethroughX = Math.round(lm.getAscent() + lm.getStrikethroughOffset());
-            int underlineX = Math.round(lm.getAscent() + lm.getUnderlineOffset());
-            boolean underline = getEffectiveUnderline();
-            boolean strikethrough = getEffectiveStrikethrough();
-
-            graphics.setFont(getEffectiveFont());
-
-            int selectionStart = textArea.getSelectionStart();
-            int selectionLength = textArea.getSelectionLength();
-            Span selectionRange = new Span(selectionStart, selectionStart + selectionLength - 1);
-
-            int documentOffset = getDocumentOffset();
-            Span characterRange = new Span(documentOffset, documentOffset + getCharacterCount() - 1);
-
-            int width = getWidth();
-            int height = getHeight();
-
-            if (selectionLength > 0
-                && characterRange.intersects(selectionRange)) {
-                // Determine the selection bounds
-                int x0;
-                if (selectionRange.start > characterRange.start) {
-                    Bounds leadingSelectionBounds = getCharacterBounds(selectionRange.start - documentOffset);
-                    x0 = leadingSelectionBounds.x;
-                } else {
-                    x0 = 0;
-                }
-
-                int x1;
-                if (selectionRange.end < characterRange.end) {
-                    Bounds trailingSelectionBounds = getCharacterBounds(selectionRange.end - documentOffset);
-                    x1 = trailingSelectionBounds.x + trailingSelectionBounds.width;
-                } else {
-                    x1 = width;
-                }
-
-                Rectangle selection = new Rectangle(x0, 0, x1 - x0, height);
-
-                // Paint the unselected text
-                Area unselectedArea = new Area();
-                unselectedArea.add(new Area(new Rectangle(0, 0, width, height)));
-                unselectedArea.subtract(new Area(selection));
-
-                Graphics2D textGraphics = (Graphics2D)graphics.create();
-                textGraphics.setColor(getEffectiveForegroundColor());
-                textGraphics.clip(unselectedArea);
-                textGraphics.drawGlyphVector(glyphVector, 0, ascent);
-                if (underline) {
-                    textGraphics.drawLine(x0, underlineX, x1 - x0, underlineX);
-                }
-                if (strikethrough) {
-                    textGraphics.drawLine(x0, strikethroughX, x1 - x0, strikethroughX);
-                }
-                textGraphics.dispose();
-
-                // Paint the selection
-                Color selectionColor;
-                if (textArea.isFocused()) {
-                    selectionColor = textAreaSkin.getSelectionColor();
-                } else {
-                    selectionColor = textAreaSkin.getInactiveSelectionColor();
-                }
-
-                Graphics2D selectedTextGraphics = (Graphics2D)graphics.create();
-                selectedTextGraphics.setColor(textArea.isFocused() &&
-                    textArea.isEditable() ? selectionColor : textAreaSkin.getInactiveSelectionColor());
-                selectedTextGraphics.clip(selection.getBounds());
-                selectedTextGraphics.drawGlyphVector(glyphVector, 0, ascent);
-                if (underline) {
-                    selectedTextGraphics.drawLine(0, underlineX, width, underlineX);
-                }
-                if (strikethrough) {
-                    selectedTextGraphics.drawLine(0, strikethroughX, width, strikethroughX);
-                }
-                selectedTextGraphics.dispose();
-            } else {
-                // Draw the text
-                graphics.setColor(getEffectiveForegroundColor());
-                graphics.drawGlyphVector(glyphVector, 0, ascent);
-                if (underline) {
-                    graphics.drawLine(0, underlineX, width, underlineX);
-                }
-                if (strikethrough) {
-                    graphics.drawLine(0, strikethroughX, width, strikethroughX);
-                }
-            }
-        }
-    }
-
-    @Override
-    public int getOffset() {
-        return super.getOffset() + start;
-    }
-
-    @Override
-    public int getCharacterCount() {
-        return length;
-    }
-
-    @Override
-    public TextAreaSkinNodeView getNext() {
-        return next;
-    }
-
-    @Override
-    public int getInsertionPoint(int x, int y) {
-        FontRenderContext fontRenderContext = Platform.getFontRenderContext();
-        LineMetrics lm = getEffectiveFont().getLineMetrics("", fontRenderContext);
-        float ascent = lm.getAscent();
-
-        int n = glyphVector.getNumGlyphs();
-        int i = 0;
-
-        while (i < n) {
-            Shape glyphBounds = glyphVector.getGlyphLogicalBounds(i);
-
-            if (glyphBounds.contains(x, y - ascent)) {
-                Rectangle2D glyphBounds2D = glyphBounds.getBounds2D();
-
-                if (x - glyphBounds2D.getX() > glyphBounds2D.getWidth() / 2
-                    && i < n - 1) {
-                    // The user clicked on the right half of the character; select
-                    // the next character
-                    i++;
-                }
-
-                break;
-            }
-
-            i++;
-        }
-
-        return i;
-    }
-
-    private Font getEffectiveFont() {
-        Font font = null;
-        // run up the tree until we find an element's style to apply
-        Element element = getNode().getParent();
-        while (element != null) {
-            font = element.getFont();
-            if (font != null) {
-                break;
-            }
-
-            element = element.getParent();
-        }
-        // if we find nothing, use the default font
-        if (element == null) {
-            font = textAreaSkin.getFont();
-        }
-        return font;
-    }
-
-    private Color getEffectiveForegroundColor() {
-        Color foregroundColor = null;
-        // run up the tree until we find an element's style to apply
-        Element element = getNode().getParent();
-        while (element != null) {
-            foregroundColor = element.getForegroundColor();
-            if (foregroundColor != null) {
-                break;
-            }
-
-            element = element.getParent();
-        }
-        // if we find nothing, use the default color
-        if (element == null) {
-            foregroundColor = textAreaSkin.getColor();
-        }
-        return foregroundColor;
-    }
-
-    private boolean getEffectiveUnderline() {
-        // run up the tree until we find an element's style to apply
-        Element element = getNode().getParent();
-        while (element != null) {
-            if (element.isUnderline()) {
-                return true;
-            }
-
-            element = element.getParent();
-        }
-        return false;
-    }
-
-    private boolean getEffectiveStrikethrough() {
-        // run up the tree until we find an element's style to apply
-        Element element = getNode().getParent();
-        while (element != null) {
-            if (element.isStrikethrough()) {
-                return true;
-            }
-
-            element = element.getParent();
-        }
-        return false;
-    }
-
-    @Override
-    public int getNextInsertionPoint(int x, int from, FocusTraversalDirection direction) {
-        int offset = -1;
-
-        if (from == -1) {
-            int n = glyphVector.getNumGlyphs();
-            int i = 0;
-
-            while (i < n) {
-                Shape glyphBounds = glyphVector.getGlyphLogicalBounds(i);
-                Rectangle2D glyphBounds2D = glyphBounds.getBounds2D();
-
-                float glyphX = (float)glyphBounds2D.getX();
-                float glyphWidth = (float)glyphBounds2D.getWidth();
-
-                if (x >= glyphX && x < glyphX + glyphWidth) {
-                    if (x - glyphX > glyphWidth / 2
-                        && i < n - 1) {
-                        // The x position falls within the right half of the character;
-                        // select the next character
-                        i++;
-                    }
-
-                    offset = i;
-                    break;
-                }
-
-                i++;
-            }
-        }
-
-        return offset;
-    }
-
-    @Override
-    public int getRowIndex(int offset) {
-        return -1;
-    }
-
-    @Override
-    public int getRowCount() {
-        return 0;
-    }
-
-    @Override
-    public Bounds getCharacterBounds(int offset) {
-        Shape glyphBounds = glyphVector.getGlyphLogicalBounds(offset);
-        Rectangle2D glyphBounds2D = glyphBounds.getBounds2D();
-
-        return new Bounds((int)Math.floor(glyphBounds2D.getX()), 0,
-            (int)Math.ceil(glyphBounds2D.getWidth()), getHeight());
-    }
-
-    @Override
-    public void charactersInserted(TextNode textNode, int index, int count) {
-        invalidate();
-    }
-
-    @Override
-    public void charactersRemoved(TextNode textNode, int index, String characters) {
-        invalidate();
-    }
-
-    @Override
-    public String toString() {
-        TextNode textNode = (TextNode)getNode();
-        String text = textNode.getText();
-        return "[" + text.substring(start, start + length) + "]";
-    }
+/*
+ * 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.wtk.skin;
+
+import java.awt.Color;
+import java.awt.Font;
+import java.awt.Graphics2D;
+import java.awt.Rectangle;
+import java.awt.Shape;
+import java.awt.font.FontRenderContext;
+import java.awt.font.GlyphVector;
+import java.awt.font.LineMetrics;
+import java.awt.geom.Area;
+import java.awt.geom.Rectangle2D;
+import java.text.CharacterIterator;
+
+import org.apache.pivot.wtk.Bounds;
+import org.apache.pivot.wtk.FocusTraversalDirection;
+import org.apache.pivot.wtk.Platform;
+import org.apache.pivot.wtk.Span;
+import org.apache.pivot.wtk.TextArea;
+import org.apache.pivot.wtk.text.Element;
+import org.apache.pivot.wtk.text.TextNode;
+import org.apache.pivot.wtk.text.TextNodeListener;
+
+/**
+ * Text node view.
+ */
+class TextAreaSkinTextNodeView extends TextAreaSkinNodeView implements TextNodeListener {
+
+    private final TextAreaSkin textAreaSkin;
+
+    private int start;
+    private int length = 0;
+    private GlyphVector glyphVector = null;
+    private TextAreaSkinTextNodeView next = null;
+
+    public TextAreaSkinTextNodeView(TextAreaSkin textAreaSkin, TextNode textNode) {
+        this(textAreaSkin, textNode, 0);
+    }
+
+    public TextAreaSkinTextNodeView(TextAreaSkin textAreaSkin, TextNode textNode, int start) {
+        super(textNode);
+        this.textAreaSkin = textAreaSkin;
+        this.start = start;
+    }
+
+    @Override
+    protected void attach() {
+        super.attach();
+
+        TextNode textNode = (TextNode)getNode();
+        textNode.getTextNodeListeners().add(this);
+    }
+
+    @Override
+    protected void detach() {
+        super.detach();
+
+        TextNode textNode = (TextNode)getNode();
+        textNode.getTextNodeListeners().remove(this);
+    }
+
+    @Override
+    public void invalidate() {
+        length = 0;
+        next = null;
+        glyphVector = null;
+
+        super.invalidate();
+    }
+
+    @Override
+    public void validate() {
+        if (!isValid()) {
+            TextNode textNode = (TextNode)getNode();
+            FontRenderContext fontRenderContext = Platform.getFontRenderContext();
+
+            int breakWidth = getBreakWidth();
+            CharacterIterator ci = textNode.getCharacterIterator(start);
+
+            float lineWidth = 0;
+            int lastWhitespaceIndex = -1;
+
+            Font effectiveFont = getEffectiveFont();
+            char c = ci.first();
+            while (c != CharacterIterator.DONE
+                && lineWidth < breakWidth) {
+                if (Character.isWhitespace(c)) {
+                    lastWhitespaceIndex = ci.getIndex();
+                }
+
+                int i = ci.getIndex();
+                Rectangle2D characterBounds = effectiveFont.getStringBounds(ci, i, i + 1, fontRenderContext);
+                lineWidth += characterBounds.getWidth();
+
+                c = ci.current();
+            }
+
+            int end;
+            if (textAreaSkin.getWrapText()) {
+                if (textNode.getCharacterCount() == 0) {
+                    end = start;
+                } else {
+                    if (lineWidth < breakWidth) {
+                        end = ci.getEndIndex();
+                    } else {
+                        if (lastWhitespaceIndex == -1) {
+                            end = ci.getIndex() - 1;
+                            if (end <= start) {
+                                end = start + 1;
+                            }
+                        } else {
+                            end = lastWhitespaceIndex + 1;
+                        }
+                    }
+                }
+            } else {
+                end = ci.getEndIndex();
+            }
+
+            glyphVector = getEffectiveFont().createGlyphVector(fontRenderContext,
+                textNode.getCharacterIterator(start, end));
+
+            if (end < ci.getEndIndex()) {
+                length = end - start;
+                next = new TextAreaSkinTextNodeView(textAreaSkin, textNode, end);
+            } else {
+                length = ci.getEndIndex() - start;
+            }
+
+            Rectangle2D textBounds = glyphVector.getLogicalBounds();
+            setSize((int)Math.ceil(textBounds.getWidth()),
+                (int)Math.ceil(textBounds.getHeight()));
+        }
+
+        super.validate();
+    }
+
+    @Override
+    protected void setSkinLocation(int skinX, int skinY) {
+    }
+
+    @Override
+    public void paint(Graphics2D graphics) {
+        if (glyphVector != null) {
+            TextArea textArea = (TextArea)textAreaSkin.getComponent();
+
+            FontRenderContext fontRenderContext = Platform.getFontRenderContext();
+            LineMetrics lm = getEffectiveFont().getLineMetrics("", fontRenderContext);
+            float ascent = lm.getAscent();
+            int strikethroughX = Math.round(lm.getAscent() + lm.getStrikethroughOffset());
+            int underlineX = Math.round(lm.getAscent() + lm.getUnderlineOffset());
+            boolean underline = getEffectiveUnderline();
+            boolean strikethrough = getEffectiveStrikethrough();
+
+            graphics.setFont(getEffectiveFont());
+
+            int selectionStart = textArea.getSelectionStart();
+            int selectionLength = textArea.getSelectionLength();
+            Span selectionRange = new Span(selectionStart, selectionStart + selectionLength - 1);
+
+            int documentOffset = getDocumentOffset();
+            Span characterRange = new Span(documentOffset, documentOffset + getCharacterCount() - 1);
+
+            int width = getWidth();
+            int height = getHeight();
+
+            if (selectionLength > 0
+                && characterRange.intersects(selectionRange)) {
+                // Determine the selection bounds
+                int x0;
+                if (selectionRange.start > characterRange.start) {
+                    Bounds leadingSelectionBounds = getCharacterBounds(selectionRange.start - documentOffset);
+                    x0 = leadingSelectionBounds.x;
+                } else {
+                    x0 = 0;
+                }
+
+                int x1;
+                if (selectionRange.end < characterRange.end) {
+                    Bounds trailingSelectionBounds = getCharacterBounds(selectionRange.end - documentOffset);
+                    x1 = trailingSelectionBounds.x + trailingSelectionBounds.width;
+                } else {
+                    x1 = width;
+                }
+
+                Rectangle selection = new Rectangle(x0, 0, x1 - x0, height);
+
+                // Paint the unselected text
+                Area unselectedArea = new Area();
+                unselectedArea.add(new Area(new Rectangle(0, 0, width, height)));
+                unselectedArea.subtract(new Area(selection));
+
+                Graphics2D textGraphics = (Graphics2D)graphics.create();
+                textGraphics.setColor(getEffectiveForegroundColor());
+                textGraphics.clip(unselectedArea);
+                textGraphics.drawGlyphVector(glyphVector, 0, ascent);
+                if (underline) {
+                    textGraphics.drawLine(x0, underlineX, x1 - x0, underlineX);
+                }
+                if (strikethrough) {
+                    textGraphics.drawLine(x0, strikethroughX, x1 - x0, strikethroughX);
+                }
+                textGraphics.dispose();
+
+                // Paint the selection
+                Color selectionColor;
+                if (textArea.isFocused()) {
+                    selectionColor = textAreaSkin.getSelectionColor();
+                } else {
+                    selectionColor = textAreaSkin.getInactiveSelectionColor();
+                }
+
+                Graphics2D selectedTextGraphics = (Graphics2D)graphics.create();
+                selectedTextGraphics.setColor(textArea.isFocused() &&
+                    textArea.isEditable() ? selectionColor : textAreaSkin.getInactiveSelectionColor());
+                selectedTextGraphics.clip(selection.getBounds());
+                selectedTextGraphics.drawGlyphVector(glyphVector, 0, ascent);
+                if (underline) {
+                    selectedTextGraphics.drawLine(0, underlineX, width, underlineX);
+                }
+                if (strikethrough) {
+                    selectedTextGraphics.drawLine(0, strikethroughX, width, strikethroughX);
+                }
+                selectedTextGraphics.dispose();
+            } else {
+                // Draw the text
+                graphics.setColor(getEffectiveForegroundColor());
+                graphics.drawGlyphVector(glyphVector, 0, ascent);
+                if (underline) {
+                    graphics.drawLine(0, underlineX, width, underlineX);
+                }
+                if (strikethrough) {
+                    graphics.drawLine(0, strikethroughX, width, strikethroughX);
+                }
+            }
+        }
+    }
+
+    @Override
+    public int getOffset() {
+        return super.getOffset() + start;
+    }
+
+    @Override
+    public int getCharacterCount() {
+        return length;
+    }
+
+    @Override
+    public TextAreaSkinNodeView getNext() {
+        return next;
+    }
+
+    @Override
+    public int getInsertionPoint(int x, int y) {
+        FontRenderContext fontRenderContext = Platform.getFontRenderContext();
+        LineMetrics lm = getEffectiveFont().getLineMetrics("", fontRenderContext);
+        float ascent = lm.getAscent();
+
+        int n = glyphVector.getNumGlyphs();
+        int i = 0;
+
+        while (i < n) {
+            Shape glyphBounds = glyphVector.getGlyphLogicalBounds(i);
+
+            if (glyphBounds.contains(x, y - ascent)) {
+                Rectangle2D glyphBounds2D = glyphBounds.getBounds2D();
+
+                if (x - glyphBounds2D.getX() > glyphBounds2D.getWidth() / 2
+                    && i < n - 1) {
+                    // The user clicked on the right half of the character; select
+                    // the next character
+                    i++;
+                }
+
+                break;
+            }
+
+            i++;
+        }
+
+        return i;
+    }
+
+    private Font getEffectiveFont() {
+        Font font = null;
+        // run up the tree until we find an element's style to apply
+        Element element = getNode().getParent();
+        while (element != null) {
+            font = element.getFont();
+            if (font != null) {
+                break;
+            }
+
+            element = element.getParent();
+        }
+        // if we find nothing, use the default font
+        if (element == null) {
+            font = textAreaSkin.getFont();
+        }
+        return font;
+    }
+
+    private Color getEffectiveForegroundColor() {
+        Color foregroundColor = null;
+        // run up the tree until we find an element's style to apply
+        Element element = getNode().getParent();
+        while (element != null) {
+            foregroundColor = element.getForegroundColor();
+            if (foregroundColor != null) {
+                break;
+            }
+
+            element = element.getParent();
+        }
+        // if we find nothing, use the default color
+        if (element == null) {
+            foregroundColor = textAreaSkin.getColor();
+        }
+        return foregroundColor;
+    }
+
+    private boolean getEffectiveUnderline() {
+        // run up the tree until we find an element's style to apply
+        Element element = getNode().getParent();
+        while (element != null) {
+            if (element.isUnderline()) {
+                return true;
+            }
+
+            element = element.getParent();
+        }
+        return false;
+    }
+
+    private boolean getEffectiveStrikethrough() {
+        // run up the tree until we find an element's style to apply
+        Element element = getNode().getParent();
+        while (element != null) {
+            if (element.isStrikethrough()) {
+                return true;
+            }
+
+            element = element.getParent();
+        }
+        return false;
+    }
+
+    @Override
+    public int getNextInsertionPoint(int x, int from, FocusTraversalDirection direction) {
+        int offset = -1;
+
+        if (from == -1) {
+            int n = glyphVector.getNumGlyphs();
+            int i = 0;
+
+            while (i < n) {
+                Shape glyphBounds = glyphVector.getGlyphLogicalBounds(i);
+                Rectangle2D glyphBounds2D = glyphBounds.getBounds2D();
+
+                float glyphX = (float)glyphBounds2D.getX();
+                float glyphWidth = (float)glyphBounds2D.getWidth();
+
+                if (x >= glyphX && x < glyphX + glyphWidth) {
+                    if (x - glyphX > glyphWidth / 2
+                        && i < n - 1) {
+                        // The x position falls within the right half of the character;
+                        // select the next character
+                        i++;
+                    }
+
+                    offset = i;
+                    break;
+                }
+
+                i++;
+            }
+        }
+
+        return offset;
+    }
+
+    @Override
+    public int getRowIndex(int offset) {
+        return -1;
+    }
+
+    @Override
+    public int getRowCount() {
+        return 0;
+    }
+
+    @Override
+    public Bounds getCharacterBounds(int offset) {
+        Shape glyphBounds = glyphVector.getGlyphLogicalBounds(offset);
+        Rectangle2D glyphBounds2D = glyphBounds.getBounds2D();
+
+        return new Bounds((int)Math.floor(glyphBounds2D.getX()), 0,
+            (int)Math.ceil(glyphBounds2D.getWidth()), getHeight());
+    }
+
+    @Override
+    public void charactersInserted(TextNode textNode, int index, int count) {
+        invalidate();
+    }
+
+    @Override
+    public void charactersRemoved(TextNode textNode, int index, String characters) {
+        invalidate();
+    }
+
+    @Override
+    public String toString() {
+        TextNode textNode = (TextNode)getNode();
+        String text = textNode.getText();
+        return "[" + text.substring(start, start + length) + "]";
+    }
 }
\ No newline at end of file

Propchange: pivot/trunk/wtk/src/org/apache/pivot/wtk/skin/TextAreaSkinTextNodeView.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: pivot/trunk/wtk/src/org/apache/pivot/wtk/skin/TextAreaSkinVerticalElementView.java
URL: http://svn.apache.org/viewvc/pivot/trunk/wtk/src/org/apache/pivot/wtk/skin/TextAreaSkinVerticalElementView.java?rev=980482&r1=980481&r2=980482&view=diff
==============================================================================
--- pivot/trunk/wtk/src/org/apache/pivot/wtk/skin/TextAreaSkinVerticalElementView.java (original)
+++ pivot/trunk/wtk/src/org/apache/pivot/wtk/skin/TextAreaSkinVerticalElementView.java Thu Jul 29 15:46:23 2010
@@ -1,212 +1,212 @@
-/*
- * 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.wtk.skin;
-
-import org.apache.pivot.collections.Sequence;
-import org.apache.pivot.wtk.Bounds;
-import org.apache.pivot.wtk.FocusTraversalDirection;
-import org.apache.pivot.wtk.text.Element;
-import org.apache.pivot.wtk.text.Node;
-
-/**
- * Some of the classes in the text hierarchy are very similar in layout ie. they lay their children out vertically. This class groups that functionality.
- */
-abstract class TextAreaSkinVerticalElementView extends TextAreaSkinElementView {
-    protected final TextAreaSkin textAreaSkin;
-
-    public TextAreaSkinVerticalElementView(TextAreaSkin textAreaSkin, Element element) {
-        super(element);
-        this.textAreaSkin = textAreaSkin;
-    }
-
-    @Override
-    protected void attach() {
-        super.attach();
-
-        // Attach child node views
-        Element element = (Element)getNode();
-        for (Node node : element) {
-            add(textAreaSkin.createNodeView(node));
-        }
-    }
-
-    protected void verticalValidate() {
-        // TODO At some point, we may want to optimize this method by deferring layout of
-        // non-visible views. If so, we should not recycle views but rather recreate them
-        // (as is done in ParagraphView). This way, we avoid thread contention over the
-        // existing views (e.g. trying to paint one while modifying its size/location, etc.).
-        // Any invalid node views are simply replaced (in the queued callback, when the
-        // thread has finished processing the new ones). This allows the definition of
-        // validate() to remain as-is. Of course, if we redefine NodeView to implement
-        // ConstrainedVisual, this may no longer be an issue.
-        // Note that, if anything happens to invalidate the existence of the new views before
-        // they are added to the document view, we need to make sure they are disposed (i.e.
-        // detached).
-
-        int breakWidth = getBreakWidth();
-
-        int width = 0;
-        int height = 0;
-
-        for (TextAreaSkinNodeView nodeView : this) {
-            nodeView.setBreakWidth(breakWidth);
-            nodeView.validate();
-
-            nodeView.setLocation(0, height);
-
-            width = Math.max(width, nodeView.getWidth());
-            height += nodeView.getHeight();
-        }
-
-        setSize(width, height);
-    }
-
-    @Override
-    protected void setSkinLocation(int skinX, int skinY) {
-        for (TextAreaSkinNodeView nodeView : this) {
-            nodeView.setSkinLocation(skinX, skinY + nodeView.getY());
-        }
-    }
-
-    @Override
-    public TextAreaSkinNodeView getNext() {
-        return null;
-    }
-
-    @Override
-    public int getInsertionPoint(int x, int y) {
-        int offset = -1;
-
-        for (int i = 0, n = getLength(); i < n; i++) {
-            TextAreaSkinNodeView nodeView = get(i);
-            Bounds nodeViewBounds = nodeView.getBounds();
-
-            if (y >= nodeViewBounds.y
-                && y < nodeViewBounds.y + nodeViewBounds.height) {
-                offset = nodeView.getInsertionPoint(x - nodeView.getX(), y - nodeView.getY())
-                    + nodeView.getOffset();
-                break;
-            }
-        }
-
-        return offset;
-    }
-
-    @Override
-    public int getNextInsertionPoint(int x, int from, FocusTraversalDirection direction) {
-        int offset = -1;
-
-        if (getLength() > 0) {
-            if (from == -1) {
-                int i = (direction == FocusTraversalDirection.FORWARD) ? 0 : getLength() - 1;
-                TextAreaSkinNodeView nodeView = get(i);
-                offset = nodeView.getNextInsertionPoint(x - nodeView.getX(), -1, direction);
-
-                if (offset != -1) {
-                    offset += nodeView.getOffset();
-                }
-            } else {
-                // Find the node view that contains the offset
-                int n = getLength();
-                int i = 0;
-
-                while (i < n) {
-                    TextAreaSkinNodeView nodeView = get(i);
-                    int nodeViewOffset = nodeView.getOffset();
-                    int characterCount = nodeView.getCharacterCount();
-
-                    if (from >= nodeViewOffset
-                        && from < nodeViewOffset + characterCount) {
-                        break;
-                    }
-
-                    i++;
-                }
-
-                if (i < n) {
-                    TextAreaSkinNodeView nodeView = get(i);
-                    offset = nodeView.getNextInsertionPoint(x - nodeView.getX(),
-                        from - nodeView.getOffset(), direction);
-
-                    if (offset == -1) {
-                        // Move to the next or previous node view
-                        if (direction == FocusTraversalDirection.FORWARD) {
-                            nodeView = (i < n - 1) ? get(i + 1) : null;
-                        } else {
-                            nodeView = (i > 0) ? get(i - 1) : null;
-                        }
-
-                        if (nodeView != null) {
-                            offset = nodeView.getNextInsertionPoint(x - nodeView.getX(), -1, direction);
-                        }
-                    }
-
-                    if (offset != -1) {
-                        offset += nodeView.getOffset();
-                    }
-                }
-            }
-        }
-
-        return offset;
-    }
-
-    @Override
-    public int getRowIndex(int offset) {
-        int rowIndex = 0;
-
-        for (TextAreaSkinNodeView nodeView : this) {
-            int nodeViewOffset = nodeView.getOffset();
-            int characterCount = nodeView.getCharacterCount();
-
-            if (offset >= nodeViewOffset
-                && offset < nodeViewOffset + characterCount) {
-                rowIndex += nodeView.getRowIndex(offset - nodeView.getOffset());
-                break;
-            }
-
-            rowIndex += nodeView.getRowCount();
-        }
-
-        return rowIndex;
-    }
-
-    @Override
-    public int getRowCount() {
-        int rowCount = 0;
-
-        for (TextAreaSkinNodeView nodeView : this) {
-            rowCount += nodeView.getRowCount();
-        }
-
-        return rowCount;
-    }
-
-    @Override
-    public void nodeInserted(Element element, int index) {
-        super.nodeInserted(element, index);
-
-        insert(textAreaSkin.createNodeView(element.get(index)), index);
-    }
-
-    @Override
-    public void nodesRemoved(Element element, int index, Sequence<Node> nodes) {
-        remove(index, nodes.getLength());
-
-        super.nodesRemoved(element, index, nodes);
-    }
-}
+/*
+ * 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.wtk.skin;
+
+import org.apache.pivot.collections.Sequence;
+import org.apache.pivot.wtk.Bounds;
+import org.apache.pivot.wtk.FocusTraversalDirection;
+import org.apache.pivot.wtk.text.Element;
+import org.apache.pivot.wtk.text.Node;
+
+/**
+ * Some of the classes in the text hierarchy are very similar in layout ie. they lay their children out vertically. This class groups that functionality.
+ */
+abstract class TextAreaSkinVerticalElementView extends TextAreaSkinElementView {
+    protected final TextAreaSkin textAreaSkin;
+
+    public TextAreaSkinVerticalElementView(TextAreaSkin textAreaSkin, Element element) {
+        super(element);
+        this.textAreaSkin = textAreaSkin;
+    }
+
+    @Override
+    protected void attach() {
+        super.attach();
+
+        // Attach child node views
+        Element element = (Element)getNode();
+        for (Node node : element) {
+            add(textAreaSkin.createNodeView(node));
+        }
+    }
+
+    protected void verticalValidate() {
+        // TODO At some point, we may want to optimize this method by deferring layout of
+        // non-visible views. If so, we should not recycle views but rather recreate them
+        // (as is done in ParagraphView). This way, we avoid thread contention over the
+        // existing views (e.g. trying to paint one while modifying its size/location, etc.).
+        // Any invalid node views are simply replaced (in the queued callback, when the
+        // thread has finished processing the new ones). This allows the definition of
+        // validate() to remain as-is. Of course, if we redefine NodeView to implement
+        // ConstrainedVisual, this may no longer be an issue.
+        // Note that, if anything happens to invalidate the existence of the new views before
+        // they are added to the document view, we need to make sure they are disposed (i.e.
+        // detached).
+
+        int breakWidth = getBreakWidth();
+
+        int width = 0;
+        int height = 0;
+
+        for (TextAreaSkinNodeView nodeView : this) {
+            nodeView.setBreakWidth(breakWidth);
+            nodeView.validate();
+
+            nodeView.setLocation(0, height);
+
+            width = Math.max(width, nodeView.getWidth());
+            height += nodeView.getHeight();
+        }
+
+        setSize(width, height);
+    }
+
+    @Override
+    protected void setSkinLocation(int skinX, int skinY) {
+        for (TextAreaSkinNodeView nodeView : this) {
+            nodeView.setSkinLocation(skinX, skinY + nodeView.getY());
+        }
+    }
+
+    @Override
+    public TextAreaSkinNodeView getNext() {
+        return null;
+    }
+
+    @Override
+    public int getInsertionPoint(int x, int y) {
+        int offset = -1;
+
+        for (int i = 0, n = getLength(); i < n; i++) {
+            TextAreaSkinNodeView nodeView = get(i);
+            Bounds nodeViewBounds = nodeView.getBounds();
+
+            if (y >= nodeViewBounds.y
+                && y < nodeViewBounds.y + nodeViewBounds.height) {
+                offset = nodeView.getInsertionPoint(x - nodeView.getX(), y - nodeView.getY())
+                    + nodeView.getOffset();
+                break;
+            }
+        }
+
+        return offset;
+    }
+
+    @Override
+    public int getNextInsertionPoint(int x, int from, FocusTraversalDirection direction) {
+        int offset = -1;
+
+        if (getLength() > 0) {
+            if (from == -1) {
+                int i = (direction == FocusTraversalDirection.FORWARD) ? 0 : getLength() - 1;
+                TextAreaSkinNodeView nodeView = get(i);
+                offset = nodeView.getNextInsertionPoint(x - nodeView.getX(), -1, direction);
+
+                if (offset != -1) {
+                    offset += nodeView.getOffset();
+                }
+            } else {
+                // Find the node view that contains the offset
+                int n = getLength();
+                int i = 0;
+
+                while (i < n) {
+                    TextAreaSkinNodeView nodeView = get(i);
+                    int nodeViewOffset = nodeView.getOffset();
+                    int characterCount = nodeView.getCharacterCount();
+
+                    if (from >= nodeViewOffset
+                        && from < nodeViewOffset + characterCount) {
+                        break;
+                    }
+
+                    i++;
+                }
+
+                if (i < n) {
+                    TextAreaSkinNodeView nodeView = get(i);
+                    offset = nodeView.getNextInsertionPoint(x - nodeView.getX(),
+                        from - nodeView.getOffset(), direction);
+
+                    if (offset == -1) {
+                        // Move to the next or previous node view
+                        if (direction == FocusTraversalDirection.FORWARD) {
+                            nodeView = (i < n - 1) ? get(i + 1) : null;
+                        } else {
+                            nodeView = (i > 0) ? get(i - 1) : null;
+                        }
+
+                        if (nodeView != null) {
+                            offset = nodeView.getNextInsertionPoint(x - nodeView.getX(), -1, direction);
+                        }
+                    }
+
+                    if (offset != -1) {
+                        offset += nodeView.getOffset();
+                    }
+                }
+            }
+        }
+
+        return offset;
+    }
+
+    @Override
+    public int getRowIndex(int offset) {
+        int rowIndex = 0;
+
+        for (TextAreaSkinNodeView nodeView : this) {
+            int nodeViewOffset = nodeView.getOffset();
+            int characterCount = nodeView.getCharacterCount();
+
+            if (offset >= nodeViewOffset
+                && offset < nodeViewOffset + characterCount) {
+                rowIndex += nodeView.getRowIndex(offset - nodeView.getOffset());
+                break;
+            }
+
+            rowIndex += nodeView.getRowCount();
+        }
+
+        return rowIndex;
+    }
+
+    @Override
+    public int getRowCount() {
+        int rowCount = 0;
+
+        for (TextAreaSkinNodeView nodeView : this) {
+            rowCount += nodeView.getRowCount();
+        }
+
+        return rowCount;
+    }
+
+    @Override
+    public void nodeInserted(Element element, int index) {
+        super.nodeInserted(element, index);
+
+        insert(textAreaSkin.createNodeView(element.get(index)), index);
+    }
+
+    @Override
+    public void nodesRemoved(Element element, int index, Sequence<Node> nodes) {
+        remove(index, nodes.getLength());
+
+        super.nodesRemoved(element, index, nodes);
+    }
+}

Propchange: pivot/trunk/wtk/src/org/apache/pivot/wtk/skin/TextAreaSkinVerticalElementView.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: pivot/trunk/wtk/src/org/apache/pivot/wtk/text/BlockListener.java
URL: http://svn.apache.org/viewvc/pivot/trunk/wtk/src/org/apache/pivot/wtk/text/BlockListener.java?rev=980482&r1=980481&r2=980482&view=diff
==============================================================================
--- pivot/trunk/wtk/src/org/apache/pivot/wtk/text/BlockListener.java (original)
+++ pivot/trunk/wtk/src/org/apache/pivot/wtk/text/BlockListener.java Thu Jul 29 15:46:23 2010
@@ -1,41 +1,41 @@
-/*
- * 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.wtk.text;
-
-import org.apache.pivot.wtk.HorizontalAlignment;
-
-/**
- * Block listener interface.
- */
-public interface BlockListener {
-
-    public class Adapter implements BlockListener {
-        @Override
-        public void horizontalAlignmentChanged(Block block,
-            HorizontalAlignment previousHorizontalAlignment) {
-        }
-    }
-
-    /**
-     * Called when the horizontal alignment has changed.
-     *
-     * @param block
-     * @param previousHorizontalAlignment
-     */
-    public void horizontalAlignmentChanged(Block block,
-        HorizontalAlignment previousHorizontalAlignment);
-}
+/*
+ * 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.wtk.text;
+
+import org.apache.pivot.wtk.HorizontalAlignment;
+
+/**
+ * Block listener interface.
+ */
+public interface BlockListener {
+
+    public class Adapter implements BlockListener {
+        @Override
+        public void horizontalAlignmentChanged(Block block,
+            HorizontalAlignment previousHorizontalAlignment) {
+        }
+    }
+
+    /**
+     * Called when the horizontal alignment has changed.
+     *
+     * @param block
+     * @param previousHorizontalAlignment
+     */
+    public void horizontalAlignmentChanged(Block block,
+        HorizontalAlignment previousHorizontalAlignment);
+}

Propchange: pivot/trunk/wtk/src/org/apache/pivot/wtk/text/BlockListener.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: pivot/trunk/wtk/src/org/apache/pivot/wtk/text/BulletedListListener.java
URL: http://svn.apache.org/viewvc/pivot/trunk/wtk/src/org/apache/pivot/wtk/text/BulletedListListener.java?rev=980482&r1=980481&r2=980482&view=diff
==============================================================================
--- pivot/trunk/wtk/src/org/apache/pivot/wtk/text/BulletedListListener.java (original)
+++ pivot/trunk/wtk/src/org/apache/pivot/wtk/text/BulletedListListener.java Thu Jul 29 15:46:23 2010
@@ -1,38 +1,38 @@
-/*
- * 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.wtk.text;
-
-
-/**
- * BulletedList listener interface.
- */
-public interface BulletedListListener {
-
-    public class Adapter implements BulletedListListener {
-        @Override
-        public void styleChanged(BulletedList bulletedList, BulletedList.Style previousStyle) {
-        }
-    }
-
-    /**
-     * Called when the list style has changed.
-     *
-     * @param bulletedList
-     * @param previousStyle
-     */
-    public void styleChanged(BulletedList bulletedList, BulletedList.Style previousStyle);
-}
+/*
+ * 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.wtk.text;
+
+
+/**
+ * BulletedList listener interface.
+ */
+public interface BulletedListListener {
+
+    public class Adapter implements BulletedListListener {
+        @Override
+        public void styleChanged(BulletedList bulletedList, BulletedList.Style previousStyle) {
+        }
+    }
+
+    /**
+     * Called when the list style has changed.
+     *
+     * @param bulletedList
+     * @param previousStyle
+     */
+    public void styleChanged(BulletedList bulletedList, BulletedList.Style previousStyle);
+}

Propchange: pivot/trunk/wtk/src/org/apache/pivot/wtk/text/BulletedListListener.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: pivot/trunk/wtk/src/org/apache/pivot/wtk/text/ComponentNode.java
URL: http://svn.apache.org/viewvc/pivot/trunk/wtk/src/org/apache/pivot/wtk/text/ComponentNode.java?rev=980482&r1=980481&r2=980482&view=diff
==============================================================================
--- pivot/trunk/wtk/src/org/apache/pivot/wtk/text/ComponentNode.java (original)
+++ pivot/trunk/wtk/src/org/apache/pivot/wtk/text/ComponentNode.java Thu Jul 29 15:46:23 2010
@@ -1,106 +1,106 @@
-/*
- * 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.wtk.text;
-
-import org.apache.pivot.util.ListenerList;
-import org.apache.pivot.wtk.Component;
-
-/**
- * Node representing a live pivot component.
- */
-public class ComponentNode extends Node {
-
-    private static class ComponentNodeListenerList extends ListenerList<ComponentNodeListener> implements
-        ComponentNodeListener {
-        @Override
-        public void componentChanged(ComponentNode componentNode, Component previousComponent) {
-            for (ComponentNodeListener listener : this) {
-                listener.componentChanged(componentNode, previousComponent);
-            }
-        }
-    }
-
-    private Component component = null;
-
-    private ComponentNodeListenerList componentNodeListeners = new ComponentNodeListenerList();
-
-    public ComponentNode() {
-    }
-
-    public ComponentNode(ComponentNode componentNode) {
-        setComponent(componentNode.getComponent());
-    }
-
-    public ComponentNode(Component component) {
-        setComponent(component);
-    }
-
-    public Component getComponent() {
-        return component;
-    }
-
-    public void setComponent(Component component) {
-        Component previousComponent = this.component;
-
-        if (previousComponent != component) {
-            this.component = component;
-            componentNodeListeners.componentChanged(this, previousComponent);
-        }
-    }
-
-    @Override
-    public char getCharacterAt(int offset) {
-        return 0x00;
-    }
-
-    @Override
-    public int getCharacterCount() {
-        return 1;
-    }
-
-    @Override
-    public void insertRange(Node range, int offset) {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public Node removeRange(int offset, int span) {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public Node getRange(int offset, int characterCount) {
-        if (offset < 0 || offset > 1) {
-            throw new IndexOutOfBoundsException();
-        }
-
-        if (characterCount != 1) {
-            throw new IllegalArgumentException("Invalid characterCount.");
-        }
-
-        return new ComponentNode(this);
-    }
-
-    @Override
-    public Node duplicate(boolean recursive) {
-        return new ComponentNode(this);
-    }
-
-    public ListenerList<ComponentNodeListener> getComponentNodeListeners() {
-        return componentNodeListeners;
-    }
-}
+/*
+ * 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.wtk.text;
+
+import org.apache.pivot.util.ListenerList;
+import org.apache.pivot.wtk.Component;
+
+/**
+ * Node representing a live pivot component.
+ */
+public class ComponentNode extends Node {
+
+    private static class ComponentNodeListenerList extends ListenerList<ComponentNodeListener> implements
+        ComponentNodeListener {
+        @Override
+        public void componentChanged(ComponentNode componentNode, Component previousComponent) {
+            for (ComponentNodeListener listener : this) {
+                listener.componentChanged(componentNode, previousComponent);
+            }
+        }
+    }
+
+    private Component component = null;
+
+    private ComponentNodeListenerList componentNodeListeners = new ComponentNodeListenerList();
+
+    public ComponentNode() {
+    }
+
+    public ComponentNode(ComponentNode componentNode) {
+        setComponent(componentNode.getComponent());
+    }
+
+    public ComponentNode(Component component) {
+        setComponent(component);
+    }
+
+    public Component getComponent() {
+        return component;
+    }
+
+    public void setComponent(Component component) {
+        Component previousComponent = this.component;
+
+        if (previousComponent != component) {
+            this.component = component;
+            componentNodeListeners.componentChanged(this, previousComponent);
+        }
+    }
+
+    @Override
+    public char getCharacterAt(int offset) {
+        return 0x00;
+    }
+
+    @Override
+    public int getCharacterCount() {
+        return 1;
+    }
+
+    @Override
+    public void insertRange(Node range, int offset) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Node removeRange(int offset, int span) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Node getRange(int offset, int characterCount) {
+        if (offset < 0 || offset > 1) {
+            throw new IndexOutOfBoundsException();
+        }
+
+        if (characterCount != 1) {
+            throw new IllegalArgumentException("Invalid characterCount.");
+        }
+
+        return new ComponentNode(this);
+    }
+
+    @Override
+    public Node duplicate(boolean recursive) {
+        return new ComponentNode(this);
+    }
+
+    public ListenerList<ComponentNodeListener> getComponentNodeListeners() {
+        return componentNodeListeners;
+    }
+}

Propchange: pivot/trunk/wtk/src/org/apache/pivot/wtk/text/ComponentNode.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: pivot/trunk/wtk/src/org/apache/pivot/wtk/text/ComponentNodeListener.java
URL: http://svn.apache.org/viewvc/pivot/trunk/wtk/src/org/apache/pivot/wtk/text/ComponentNodeListener.java?rev=980482&r1=980481&r2=980482&view=diff
==============================================================================
--- pivot/trunk/wtk/src/org/apache/pivot/wtk/text/ComponentNodeListener.java (original)
+++ pivot/trunk/wtk/src/org/apache/pivot/wtk/text/ComponentNodeListener.java Thu Jul 29 15:46:23 2010
@@ -1,26 +1,26 @@
-/*
- * 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.wtk.text;
-
-import org.apache.pivot.wtk.Component;
-
-/**
- * Component node listener interface.
- */
-public interface ComponentNodeListener {
-    public void componentChanged(ComponentNode componentNode, Component previousComponent);
-}
+/*
+ * 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.wtk.text;
+
+import org.apache.pivot.wtk.Component;
+
+/**
+ * Component node listener interface.
+ */
+public interface ComponentNodeListener {
+    public void componentChanged(ComponentNode componentNode, Component previousComponent);
+}

Propchange: pivot/trunk/wtk/src/org/apache/pivot/wtk/text/ComponentNodeListener.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: pivot/trunk/wtk/src/org/apache/pivot/wtk/text/NumberedListListener.java
URL: http://svn.apache.org/viewvc/pivot/trunk/wtk/src/org/apache/pivot/wtk/text/NumberedListListener.java?rev=980482&r1=980481&r2=980482&view=diff
==============================================================================
--- pivot/trunk/wtk/src/org/apache/pivot/wtk/text/NumberedListListener.java (original)
+++ pivot/trunk/wtk/src/org/apache/pivot/wtk/text/NumberedListListener.java Thu Jul 29 15:46:23 2010
@@ -1,37 +1,37 @@
-/*
- * 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.wtk.text;
-
-/**
- * NumberedList listener interface.
- */
-public interface NumberedListListener {
-
-    public class Adapter implements NumberedListListener {
-        @Override
-        public void styleChanged(NumberedList numberedList, NumberedList.Style previousStyle) {
-        }
-    }
-
-    /**
-     * Called when the list style has changed.
-     *
-     * @param numberedList
-     * @param previousStyle
-     */
-    public void styleChanged(NumberedList numberedList, NumberedList.Style previousStyle);
-}
+/*
+ * 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.wtk.text;
+
+/**
+ * NumberedList listener interface.
+ */
+public interface NumberedListListener {
+
+    public class Adapter implements NumberedListListener {
+        @Override
+        public void styleChanged(NumberedList numberedList, NumberedList.Style previousStyle) {
+        }
+    }
+
+    /**
+     * Called when the list style has changed.
+     *
+     * @param numberedList
+     * @param previousStyle
+     */
+    public void styleChanged(NumberedList numberedList, NumberedList.Style previousStyle);
+}

Propchange: pivot/trunk/wtk/src/org/apache/pivot/wtk/text/NumberedListListener.java
------------------------------------------------------------------------------
    svn:eol-style = native