Modified: pivot/trunk/wtk/src/org/apache/pivot/wtk/skin/RulerSkin.java
URL: 
http://svn.apache.org/viewvc/pivot/trunk/wtk/src/org/apache/pivot/wtk/skin/RulerSkin.java?rev=1913470&r1=1913469&r2=1913470&view=diff
==============================================================================
--- pivot/trunk/wtk/src/org/apache/pivot/wtk/skin/RulerSkin.java (original)
+++ pivot/trunk/wtk/src/org/apache/pivot/wtk/skin/RulerSkin.java Tue Oct 31 
19:15:47 2023
@@ -1,557 +1,557 @@
-/*
- * 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.font.FontRenderContext;
-import java.awt.font.GlyphVector;
-import java.awt.font.LineMetrics;
-import java.awt.geom.Rectangle2D;
-import java.text.StringCharacterIterator;
-
-import org.apache.pivot.collections.Dictionary;
-import org.apache.pivot.collections.Sequence;
-import org.apache.pivot.util.Utils;
-import org.apache.pivot.wtk.Borders;
-import org.apache.pivot.wtk.Component;
-import org.apache.pivot.wtk.CSSColor;
-import org.apache.pivot.wtk.GraphicsUtilities;
-import org.apache.pivot.wtk.Insets;
-import org.apache.pivot.wtk.Orientation;
-import org.apache.pivot.wtk.Platform;
-import org.apache.pivot.wtk.Ruler;
-import org.apache.pivot.wtk.RulerListener;
-import org.apache.pivot.wtk.Theme;
-
-public class RulerSkin extends ComponentSkin implements RulerListener {
-    private static final int MAJOR_SIZE = 10;
-    private static final int MINOR_SIZE = 8;
-    private static final int REGULAR_SIZE = 5;
-
-    private Color color;
-    private Color backgroundColor;
-    private int markerSpacing;
-    private Insets markerInsets;
-    private boolean flip;
-    private Borders borders;
-    private int majorDivision;
-    private int minorDivision;
-    private boolean showMajorNumbers;
-    private boolean showMinorNumbers;
-    private Font font;
-    private float charWidth, charHeight, descent;
-
-    public RulerSkin() {
-        // For now the default colors are not from the Theme.
-        setColor(Color.BLACK);
-        setBackgroundColor(CSSColor.LightYellow.getColor());
-
-        markerSpacing = 5;
-        markerInsets = new Insets(0);
-        flip = false;
-        borders = Borders.ALL;
-        majorDivision = 4;
-        minorDivision = 2;
-        showMajorNumbers = false;
-        showMinorNumbers = false;
-
-        Theme theme = currentTheme();
-        setFont(theme.getFont());
-    }
-
-    @Override
-    public void install(Component component) {
-        super.install(component);
-
-        Ruler ruler = (Ruler) component;
-        ruler.getRulerListeners().add(this);
-    }
-
-    @Override
-    public void layout() {
-        // No-op
-    }
-
-    @Override
-    public int getPreferredHeight(int width) {
-        Ruler ruler = (Ruler) getComponent();
-        Orientation orientation = ruler.getOrientation();
-
-        // Give a little extra height if showing numbers
-        return (orientation == Orientation.HORIZONTAL)
-              ? ((showMajorNumbers || showMinorNumbers)
-                 ? ((int) Math.ceil(charHeight) + MAJOR_SIZE + 5) : MAJOR_SIZE 
* 2) : 0;
-    }
-
-    @Override
-    public int getPreferredWidth(int height) {
-        Ruler ruler = (Ruler) getComponent();
-        Orientation orientation = ruler.getOrientation();
-
-        // Give a little extra width if showing numbers
-        return (orientation == Orientation.VERTICAL)
-              ? ((showMajorNumbers || showMinorNumbers)
-                 ? ((int) Math.ceil(charWidth) + MAJOR_SIZE + 5) : MAJOR_SIZE 
* 2) : 0;
-    }
-
-    private void showNumber(Graphics2D graphics, FontRenderContext 
fontRenderContext, int number,
-            int x, int y) {
-        String num = Integer.toString(number);
-
-        StringCharacterIterator line;
-        GlyphVector glyphVector;
-        Rectangle2D textBounds;
-        float width, height;
-        float fx, fy;
-
-        Ruler ruler = (Ruler) getComponent();
-        Orientation orientation = ruler.getOrientation();
-
-        switch (orientation) {
-            case HORIZONTAL:
-                // Draw the whole number just off the tip of the line given by 
(x,y)
-                line = new StringCharacterIterator(num);
-                glyphVector = font.createGlyphVector(fontRenderContext, line);
-                textBounds = glyphVector.getLogicalBounds();
-                width = (float) textBounds.getWidth();
-                height = (float) textBounds.getHeight();
-                fx = (float) x - (width / 2.0f);
-                if (flip) {
-                    fy = (float) (y - 2);
-                } else {
-                    fy = (float) (y - 1) + height;
-                }
-                graphics.drawGlyphVector(glyphVector, fx, fy);
-                break;
-            case VERTICAL:
-                // Draw the number one digit at a time, vertically just off 
the tip of the line
-                if (flip) {
-                    fx = (float) (x - 1) - charWidth;
-                } else {
-                    fx = (float) (x + 3);
-                }
-                int numDigits = num.length();
-                float heightAdjust = (numDigits % 2 == 1) ? charHeight / 2.0f 
: 0.0f;
-                for (int i = 0; i < numDigits; i++) {
-                    line = new StringCharacterIterator(num.substring(i, i + 
1));
-                    glyphVector = font.createGlyphVector(fontRenderContext, 
line);
-                    int midDigit = (numDigits + 1) / 2;
-                    if (i <= midDigit) {
-                        fy = (float) y + heightAdjust - descent - (float) 
(midDigit - i - 1) * charHeight;
-                    } else {
-                        fy = (float) y + heightAdjust - descent + (float) (i - 
midDigit - 1) * charHeight;
-                    }
-                    graphics.drawGlyphVector(glyphVector, fx, fy);
-                }
-                break;
-            default:
-                break;
-        }
-    }
-
-    @Override
-    public void paint(Graphics2D graphics) {
-        int width = getWidth();
-        int height = getHeight();
-
-        int top = markerInsets.top;
-        int left = markerInsets.left;
-        int bottom = height - markerInsets.bottom;
-        int right = width - markerInsets.right;
-
-        Ruler ruler = (Ruler) getComponent();
-
-        graphics.setColor(backgroundColor);
-        graphics.fillRect(0, 0, width, height);
-
-        graphics.setColor(color);
-        GraphicsUtilities.drawBorders(graphics, borders, 0, 0, height - 1, 
width - 1);
-
-        height -= markerInsets.getHeight();
-        width -= markerInsets.getWidth();
-
-        FontRenderContext fontRenderContext = showMajorNumbers || 
showMinorNumbers
-            ? GraphicsUtilities.prepareForText(graphics, font, color) : null;
-
-        int start, end2, end3, end4;
-
-        Orientation orientation = ruler.getOrientation();
-        switch (orientation) {
-            case HORIZONTAL:
-                start = flip ? bottom - 1 : top;
-                end2 = flip ? (start - (MAJOR_SIZE - 1)) : (MAJOR_SIZE - 1);
-                end3 = flip ? (start - (MINOR_SIZE - 1)) : (MINOR_SIZE - 1);
-                end4 = flip ? (start - (REGULAR_SIZE - 1)) : (REGULAR_SIZE - 
1);
-
-                for (int i = 0, n = right / markerSpacing + 1; i < n; i++) {
-                    int x = i * markerSpacing + left;
-
-                    if (majorDivision != 0 && i % majorDivision == 0) {
-                        graphics.drawLine(x, start, x, end2);
-                        // Don't show any numbers at 0 -- make a style for 
this?
-                        if (showMajorNumbers && i > 0) {
-                            showNumber(graphics, fontRenderContext, i, x, 
end2);
-                        }
-                    } else if (minorDivision != 0 && i % minorDivision == 0) {
-                        graphics.drawLine(x, start, x, end3);
-                        if (showMinorNumbers && i > 0) {
-                            // Show the minor numbers at the same y point as 
the major
-                            showNumber(graphics, fontRenderContext, i, x, 
end2);
-                        }
-                    } else {
-                        graphics.drawLine(x, start, x, end4);
-                    }
-                }
-                break;
-
-            case VERTICAL:
-                start = flip ? right - 1 : left;
-                end2 = flip ? (start - (MAJOR_SIZE - 1)) : (MAJOR_SIZE - 1);
-                end3 = flip ? (start - (MINOR_SIZE - 1)) : (MINOR_SIZE - 1);
-                end4 = flip ? (start - (REGULAR_SIZE - 1)) : (REGULAR_SIZE - 
1);
-
-                for (int i = 0, n = bottom / markerSpacing + 1; i < n; i++) {
-                    int y = i * markerSpacing + top;
-
-                    if (majorDivision != 0 && i % majorDivision == 0) {
-                        graphics.drawLine(start, y, end2, y);
-                        // Don't show any numbers at 0 -- make a style for 
this?
-                        if (showMajorNumbers && i > 0) {
-                            showNumber(graphics, fontRenderContext, i, end2, 
y);
-                        }
-                    } else if (minorDivision != 0 && i % minorDivision == 0) {
-                        graphics.drawLine(start, y, end3, y);
-                        if (showMinorNumbers && i > 0) {
-                            showNumber(graphics, fontRenderContext, i, end3, 
y);
-                        }
-                    } else {
-                        graphics.drawLine(start, y, end4, y);
-                    }
-                }
-                break;
-
-            default:
-                break;
-        }
-    }
-
-    @Override
-    public void orientationChanged(Ruler ruler) {
-        invalidateComponent();
-    }
-
-    /**
-     * @return The interval at which the "major" (that is, the long)
-     * markers are drawn.
-     */
-    public final int getMajorDivision() {
-        return majorDivision;
-    }
-
-    /**
-     * Set the major division interval.
-     *
-     * @param major The number of markers interval at which to draw
-     * a "major" (long) marker.  Can be zero to not draw any major
-     * markers.
-     */
-    public final void setMajorDivision(int major) {
-        Utils.checkNonNegative(major, "majorDivision");
-
-        // TODO: check for sanity of major vs. minor here??
-        this.majorDivision = major;
-        repaintComponent();
-    }
-
-    public final void setMajorDivision(Number major) {
-        Utils.checkNull(major, "majorDivision");
-
-        setMajorDivision(major.intValue());
-    }
-
-    /**
-     * @return The interval at which the "minor" (that is, the slightly
-     * longer than normal) markers are drawn.
-     */
-    public final int getMinorDivision() {
-        return minorDivision;
-    }
-
-    /**
-     * Set the minor division interval.
-     *
-     * @param minor The number of markers interval at which to draw
-     * a "minor" (slightly longer than normal) marker.  Can be zero
-     * to not draw any minor markers.
-     */
-    public final void setMinorDivision(int minor) {
-        Utils.checkNonNegative(minor, "minorDivision");
-
-        // TODO: check for sanity of major vs. minor here??
-        this.minorDivision = minor;
-        repaintComponent();
-    }
-
-    public final void setMinorDivision(Number minor) {
-        Utils.checkNull(minor, "minorDivision");
-
-        setMinorDivision(minor.intValue());
-    }
-
-    /**
-     * @return The number of pixels interval at which to draw markers.
-     */
-    public final int getMarkerSpacing() {
-        return markerSpacing;
-    }
-
-    /**
-     * Set the number of pixels interval at which to draw the markers.
-     *
-     * @param spacing The number of pixels between markers (must be {@code >= 
1}).
-     */
-    public final void setMarkerSpacing(int spacing) {
-        Utils.checkPositive(spacing, "markerSpacing");
-
-        this.markerSpacing = spacing;
-        invalidateComponent();
-    }
-
-    public final void setMarkerSpacing(Number spacing) {
-        Utils.checkNull(spacing, "markerSpacing");
-
-        setMarkerSpacing(spacing.intValue());
-    }
-
-    /**
-     * @return Whether the ruler is "flipped", that is the markers
-     * start from the inside rather than the outside.
-     */
-    public final boolean getFlip() {
-        return flip;
-    }
-
-    public final void setFlip(boolean flip) {
-        this.flip = flip;
-    }
-
-    /**
-     * @return Whether to display numbers at each major division.
-     */
-    public final boolean getShowMajorNumbers() {
-        return showMajorNumbers;
-    }
-
-    /**
-     * Sets the flag to say whether to show numbers at each major division.
-     *
-     * @param showMajorNumbers Whether numbers should be shown for major 
divisions.
-     */
-    public final void setShowMajorNumbers(boolean showMajorNumbers) {
-        this.showMajorNumbers = showMajorNumbers;
-        invalidateComponent();
-    }
-
-    /**
-     * @return Whether to display numbers at each minor division.
-     */
-    public final boolean getShowMinorNumbers() {
-        return showMinorNumbers;
-    }
-
-    /**
-     * Sets the flag to say whether to show numbers at each minor division.
-     *
-     * @param showMinorNumbers Whether numbers should be shown for minor 
divisions.
-     */
-    public final void setShowMinorNumbers(boolean showMinorNumbers) {
-        this.showMinorNumbers = showMinorNumbers;
-        invalidateComponent();
-    }
-
-    /**
-     * @return The border configuration for this ruler.
-     */
-    public final Borders getBorders() {
-        return borders;
-    }
-
-    public final void setBorders(Borders borders) {
-        Utils.checkNull(borders, "borders");
-
-        this.borders = borders;
-        repaintComponent();
-    }
-
-    /**
-     * @return The insets for the markers (on each edge).
-     */
-    public final Insets getMarkerInsets() {
-        return markerInsets;
-    }
-
-    public final void setMarkerInsets(Insets insets) {
-        Utils.checkNull(insets, "markerInsets");
-
-        this.markerInsets = insets;
-        repaintComponent();
-    }
-
-    public final void setMarkerInsets(Dictionary<String, ?> insets) {
-        setMarkerInsets(new Insets(insets));
-    }
-
-    public final void setMarkerInsets(Sequence<?> insets) {
-        setMarkerInsets(new Insets(insets));
-    }
-
-    public final void setMarkerInsets(int insets) {
-        setMarkerInsets(new Insets(insets));
-    }
-
-    public final void setMarkerInsets(Number insets) {
-        setMarkerInsets(new Insets(insets));
-    }
-
-    public final void setMarkerInsets(String insets) {
-        setMarkerInsets(Insets.decode(insets));
-    }
-
-    /**
-     * Returns the foreground color for the markers of the ruler.
-     *
-     * @return The foreground (marker) color.
-     */
-    public final Color getColor() {
-        return color;
-    }
-
-    /**
-     * Sets the foreground color for the markers of the ruler.
-     *
-     * @param color The foreground (that is, the marker) color.
-     */
-    public final void setColor(Color color) {
-        Utils.checkNull(color, "color");
-
-        this.color = color;
-        repaintComponent();
-    }
-
-    /**
-     * Sets the foreground color for the markers of the ruler.
-     *
-     * @param color Any of the {@linkplain GraphicsUtilities#decodeColor color
-     * values recognized by Pivot}.
-     */
-    public final void setColor(String color) {
-        setColor(GraphicsUtilities.decodeColor(color, "color"));
-    }
-
-    public final void setColor(int color) {
-        Theme theme = currentTheme();
-        setColor(theme.getColor(color));
-    }
-
-    /**
-     * Returns the background color of the ruler.
-     *
-     * @return The current background color.
-     */
-    public final Color getBackgroundColor() {
-        return backgroundColor;
-    }
-
-    /**
-     * Sets the background color of the ruler.
-     *
-     * @param backgroundColor New background color value (can be {@code null}
-     * for a transparent background).
-     */
-    public final void setBackgroundColor(Color backgroundColor) {
-        this.backgroundColor = backgroundColor;
-        repaintComponent();
-    }
-
-    /**
-     * Sets the background color of the ruler.
-     *
-     * @param backgroundColor Any of the
-     * {@linkplain GraphicsUtilities#decodeColor color values recognized by
-     * Pivot}.
-     */
-    public final void setBackgroundColor(String backgroundColor) {
-        setBackgroundColor(GraphicsUtilities.decodeColor(backgroundColor, 
"backgroundColor"));
-    }
-
-    public final void setBackgroundColor(int backgroundColor) {
-        Theme theme = currentTheme();
-        setBackgroundColor(theme.getColor(backgroundColor));
-    }
-
-    /**
-     * @return The font used to format division numbers (if enabled).
-     */
-    public final Font getFont() {
-        return font;
-    }
-
-    /**
-     * Sets the font used in rendering the Ruler's text.
-     *
-     * @param font The new font to use.
-     */
-    public final void setFont(Font font) {
-        Utils.checkNull(font, "font");
-
-        // The font we will use is the same name and style, but a 11 pt type
-        this.font = font.deriveFont(11.0f);
-
-        // Make some size calculations for the drawing code
-        FontRenderContext fontRenderContext = Platform.getFontRenderContext();
-        GlyphVector glyphVector = 
this.font.createGlyphVector(fontRenderContext, "0");
-        Rectangle2D textBounds = glyphVector.getLogicalBounds();
-        this.charWidth = (float) textBounds.getWidth();
-        // Since we're just drawing numbers, the line spacing can be just the 
ascent value for the font
-        LineMetrics lm = this.font.getLineMetrics("0", fontRenderContext);
-        this.charHeight = lm.getAscent();
-        this.descent = lm.getDescent();
-
-        invalidateComponent();
-    }
-
-    /**
-     * Sets the font used in rendering the Ruler's text.
-     *
-     * @param font A {@link ComponentSkin#decodeFont(String) font 
specification}
-     */
-    public final void setFont(String font) {
-        setFont(decodeFont(font));
-    }
-
-    /**
-     * Sets the font used in rendering the Ruler's text.
-     *
-     * @param font A dictionary {@link Theme#deriveFont describing a font}
-     */
-    public final void setFont(Dictionary<String, ?> font) {
-        setFont(Theme.deriveFont(font));
-    }
-
-}
+/*
+ * 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.font.FontRenderContext;
+import java.awt.font.GlyphVector;
+import java.awt.font.LineMetrics;
+import java.awt.geom.Rectangle2D;
+import java.text.StringCharacterIterator;
+
+import org.apache.pivot.collections.Dictionary;
+import org.apache.pivot.collections.Sequence;
+import org.apache.pivot.util.Utils;
+import org.apache.pivot.wtk.Borders;
+import org.apache.pivot.wtk.Component;
+import org.apache.pivot.wtk.CSSColor;
+import org.apache.pivot.wtk.GraphicsUtilities;
+import org.apache.pivot.wtk.Insets;
+import org.apache.pivot.wtk.Orientation;
+import org.apache.pivot.wtk.Platform;
+import org.apache.pivot.wtk.Ruler;
+import org.apache.pivot.wtk.RulerListener;
+import org.apache.pivot.wtk.Theme;
+
+public class RulerSkin extends ComponentSkin implements RulerListener {
+    private static final int MAJOR_SIZE = 10;
+    private static final int MINOR_SIZE = 8;
+    private static final int REGULAR_SIZE = 5;
+
+    private Color color;
+    private Color backgroundColor;
+    private int markerSpacing;
+    private Insets markerInsets;
+    private boolean flip;
+    private Borders borders;
+    private int majorDivision;
+    private int minorDivision;
+    private boolean showMajorNumbers;
+    private boolean showMinorNumbers;
+    private Font font;
+    private float charWidth, charHeight, descent;
+
+    public RulerSkin() {
+        // For now the default colors are not from the Theme.
+        setColor(Color.BLACK);
+        setBackgroundColor(CSSColor.LightYellow.getColor());
+
+        markerSpacing = 5;
+        markerInsets = new Insets(0);
+        flip = false;
+        borders = Borders.ALL;
+        majorDivision = 4;
+        minorDivision = 2;
+        showMajorNumbers = false;
+        showMinorNumbers = false;
+
+        Theme theme = currentTheme();
+        setFont(theme.getFont());
+    }
+
+    @Override
+    public void install(Component component) {
+        super.install(component);
+
+        Ruler ruler = (Ruler) component;
+        ruler.getRulerListeners().add(this);
+    }
+
+    @Override
+    public void layout() {
+        // No-op
+    }
+
+    @Override
+    public int getPreferredHeight(int width) {
+        Ruler ruler = (Ruler) getComponent();
+        Orientation orientation = ruler.getOrientation();
+
+        // Give a little extra height if showing numbers
+        return (orientation == Orientation.HORIZONTAL)
+              ? ((showMajorNumbers || showMinorNumbers)
+                 ? ((int) Math.ceil(charHeight) + MAJOR_SIZE + 5) : MAJOR_SIZE 
* 2) : 0;
+    }
+
+    @Override
+    public int getPreferredWidth(int height) {
+        Ruler ruler = (Ruler) getComponent();
+        Orientation orientation = ruler.getOrientation();
+
+        // Give a little extra width if showing numbers
+        return (orientation == Orientation.VERTICAL)
+              ? ((showMajorNumbers || showMinorNumbers)
+                 ? ((int) Math.ceil(charWidth) + MAJOR_SIZE + 5) : MAJOR_SIZE 
* 2) : 0;
+    }
+
+    private void showNumber(Graphics2D graphics, FontRenderContext 
fontRenderContext, int number,
+            int x, int y) {
+        String num = Integer.toString(number);
+
+        StringCharacterIterator line;
+        GlyphVector glyphVector;
+        Rectangle2D textBounds;
+        float width, height;
+        float fx, fy;
+
+        Ruler ruler = (Ruler) getComponent();
+        Orientation orientation = ruler.getOrientation();
+
+        switch (orientation) {
+            case HORIZONTAL:
+                // Draw the whole number just off the tip of the line given by 
(x,y)
+                line = new StringCharacterIterator(num);
+                glyphVector = font.createGlyphVector(fontRenderContext, line);
+                textBounds = glyphVector.getLogicalBounds();
+                width = (float) textBounds.getWidth();
+                height = (float) textBounds.getHeight();
+                fx = (float) x - (width / 2.0f);
+                if (flip) {
+                    fy = (float) (y - 2);
+                } else {
+                    fy = (float) (y - 1) + height;
+                }
+                graphics.drawGlyphVector(glyphVector, fx, fy);
+                break;
+            case VERTICAL:
+                // Draw the number one digit at a time, vertically just off 
the tip of the line
+                if (flip) {
+                    fx = (float) (x - 1) - charWidth;
+                } else {
+                    fx = (float) (x + 3);
+                }
+                int numDigits = num.length();
+                float heightAdjust = (numDigits % 2 == 1) ? charHeight / 2.0f 
: 0.0f;
+                for (int i = 0; i < numDigits; i++) {
+                    line = new StringCharacterIterator(num.substring(i, i + 
1));
+                    glyphVector = font.createGlyphVector(fontRenderContext, 
line);
+                    int midDigit = (numDigits + 1) / 2;
+                    if (i <= midDigit) {
+                        fy = (float) y + heightAdjust - descent - (float) 
(midDigit - i - 1) * charHeight;
+                    } else {
+                        fy = (float) y + heightAdjust - descent + (float) (i - 
midDigit - 1) * charHeight;
+                    }
+                    graphics.drawGlyphVector(glyphVector, fx, fy);
+                }
+                break;
+            default:
+                break;
+        }
+    }
+
+    @Override
+    public void paint(Graphics2D graphics) {
+        int width = getWidth();
+        int height = getHeight();
+
+        int top = markerInsets.top;
+        int left = markerInsets.left;
+        int bottom = height - markerInsets.bottom;
+        int right = width - markerInsets.right;
+
+        Ruler ruler = (Ruler) getComponent();
+
+        graphics.setColor(backgroundColor);
+        graphics.fillRect(0, 0, width, height);
+
+        graphics.setColor(color);
+        GraphicsUtilities.drawBorders(graphics, borders, 0, 0, height - 1, 
width - 1);
+
+        height -= markerInsets.getHeight();
+        width -= markerInsets.getWidth();
+
+        FontRenderContext fontRenderContext = showMajorNumbers || 
showMinorNumbers
+            ? GraphicsUtilities.prepareForText(graphics, font, color) : null;
+
+        int start, end2, end3, end4;
+
+        Orientation orientation = ruler.getOrientation();
+        switch (orientation) {
+            case HORIZONTAL:
+                start = flip ? bottom - 1 : top;
+                end2 = flip ? (start - (MAJOR_SIZE - 1)) : (MAJOR_SIZE - 1);
+                end3 = flip ? (start - (MINOR_SIZE - 1)) : (MINOR_SIZE - 1);
+                end4 = flip ? (start - (REGULAR_SIZE - 1)) : (REGULAR_SIZE - 
1);
+
+                for (int i = 0, n = right / markerSpacing + 1; i < n; i++) {
+                    int x = i * markerSpacing + left;
+
+                    if (majorDivision != 0 && i % majorDivision == 0) {
+                        graphics.drawLine(x, start, x, end2);
+                        // Don't show any numbers at 0 -- make a style for 
this?
+                        if (showMajorNumbers && i > 0) {
+                            showNumber(graphics, fontRenderContext, i, x, 
end2);
+                        }
+                    } else if (minorDivision != 0 && i % minorDivision == 0) {
+                        graphics.drawLine(x, start, x, end3);
+                        if (showMinorNumbers && i > 0) {
+                            // Show the minor numbers at the same y point as 
the major
+                            showNumber(graphics, fontRenderContext, i, x, 
end2);
+                        }
+                    } else {
+                        graphics.drawLine(x, start, x, end4);
+                    }
+                }
+                break;
+
+            case VERTICAL:
+                start = flip ? right - 1 : left;
+                end2 = flip ? (start - (MAJOR_SIZE - 1)) : (MAJOR_SIZE - 1);
+                end3 = flip ? (start - (MINOR_SIZE - 1)) : (MINOR_SIZE - 1);
+                end4 = flip ? (start - (REGULAR_SIZE - 1)) : (REGULAR_SIZE - 
1);
+
+                for (int i = 0, n = bottom / markerSpacing + 1; i < n; i++) {
+                    int y = i * markerSpacing + top;
+
+                    if (majorDivision != 0 && i % majorDivision == 0) {
+                        graphics.drawLine(start, y, end2, y);
+                        // Don't show any numbers at 0 -- make a style for 
this?
+                        if (showMajorNumbers && i > 0) {
+                            showNumber(graphics, fontRenderContext, i, end2, 
y);
+                        }
+                    } else if (minorDivision != 0 && i % minorDivision == 0) {
+                        graphics.drawLine(start, y, end3, y);
+                        if (showMinorNumbers && i > 0) {
+                            showNumber(graphics, fontRenderContext, i, end3, 
y);
+                        }
+                    } else {
+                        graphics.drawLine(start, y, end4, y);
+                    }
+                }
+                break;
+
+            default:
+                break;
+        }
+    }
+
+    @Override
+    public void orientationChanged(Ruler ruler) {
+        invalidateComponent();
+    }
+
+    /**
+     * @return The interval at which the "major" (that is, the long)
+     * markers are drawn.
+     */
+    public final int getMajorDivision() {
+        return majorDivision;
+    }
+
+    /**
+     * Set the major division interval.
+     *
+     * @param major The number of markers interval at which to draw
+     * a "major" (long) marker.  Can be zero to not draw any major
+     * markers.
+     */
+    public final void setMajorDivision(int major) {
+        Utils.checkNonNegative(major, "majorDivision");
+
+        // TODO: check for sanity of major vs. minor here??
+        this.majorDivision = major;
+        repaintComponent();
+    }
+
+    public final void setMajorDivision(Number major) {
+        Utils.checkNull(major, "majorDivision");
+
+        setMajorDivision(major.intValue());
+    }
+
+    /**
+     * @return The interval at which the "minor" (that is, the slightly
+     * longer than normal) markers are drawn.
+     */
+    public final int getMinorDivision() {
+        return minorDivision;
+    }
+
+    /**
+     * Set the minor division interval.
+     *
+     * @param minor The number of markers interval at which to draw
+     * a "minor" (slightly longer than normal) marker.  Can be zero
+     * to not draw any minor markers.
+     */
+    public final void setMinorDivision(int minor) {
+        Utils.checkNonNegative(minor, "minorDivision");
+
+        // TODO: check for sanity of major vs. minor here??
+        this.minorDivision = minor;
+        repaintComponent();
+    }
+
+    public final void setMinorDivision(Number minor) {
+        Utils.checkNull(minor, "minorDivision");
+
+        setMinorDivision(minor.intValue());
+    }
+
+    /**
+     * @return The number of pixels interval at which to draw markers.
+     */
+    public final int getMarkerSpacing() {
+        return markerSpacing;
+    }
+
+    /**
+     * Set the number of pixels interval at which to draw the markers.
+     *
+     * @param spacing The number of pixels between markers (must be {@code >= 
1}).
+     */
+    public final void setMarkerSpacing(int spacing) {
+        Utils.checkPositive(spacing, "markerSpacing");
+
+        this.markerSpacing = spacing;
+        invalidateComponent();
+    }
+
+    public final void setMarkerSpacing(Number spacing) {
+        Utils.checkNull(spacing, "markerSpacing");
+
+        setMarkerSpacing(spacing.intValue());
+    }
+
+    /**
+     * @return Whether the ruler is "flipped", that is the markers
+     * start from the inside rather than the outside.
+     */
+    public final boolean getFlip() {
+        return flip;
+    }
+
+    public final void setFlip(boolean flip) {
+        this.flip = flip;
+    }
+
+    /**
+     * @return Whether to display numbers at each major division.
+     */
+    public final boolean getShowMajorNumbers() {
+        return showMajorNumbers;
+    }
+
+    /**
+     * Sets the flag to say whether to show numbers at each major division.
+     *
+     * @param showMajorNumbers Whether numbers should be shown for major 
divisions.
+     */
+    public final void setShowMajorNumbers(boolean showMajorNumbers) {
+        this.showMajorNumbers = showMajorNumbers;
+        invalidateComponent();
+    }
+
+    /**
+     * @return Whether to display numbers at each minor division.
+     */
+    public final boolean getShowMinorNumbers() {
+        return showMinorNumbers;
+    }
+
+    /**
+     * Sets the flag to say whether to show numbers at each minor division.
+     *
+     * @param showMinorNumbers Whether numbers should be shown for minor 
divisions.
+     */
+    public final void setShowMinorNumbers(boolean showMinorNumbers) {
+        this.showMinorNumbers = showMinorNumbers;
+        invalidateComponent();
+    }
+
+    /**
+     * @return The border configuration for this ruler.
+     */
+    public final Borders getBorders() {
+        return borders;
+    }
+
+    public final void setBorders(Borders borders) {
+        Utils.checkNull(borders, "borders");
+
+        this.borders = borders;
+        repaintComponent();
+    }
+
+    /**
+     * @return The insets for the markers (on each edge).
+     */
+    public final Insets getMarkerInsets() {
+        return markerInsets;
+    }
+
+    public final void setMarkerInsets(Insets insets) {
+        Utils.checkNull(insets, "markerInsets");
+
+        this.markerInsets = insets;
+        repaintComponent();
+    }
+
+    public final void setMarkerInsets(Dictionary<String, ?> insets) {
+        setMarkerInsets(new Insets(insets));
+    }
+
+    public final void setMarkerInsets(Sequence<?> insets) {
+        setMarkerInsets(new Insets(insets));
+    }
+
+    public final void setMarkerInsets(int insets) {
+        setMarkerInsets(new Insets(insets));
+    }
+
+    public final void setMarkerInsets(Number insets) {
+        setMarkerInsets(new Insets(insets));
+    }
+
+    public final void setMarkerInsets(String insets) {
+        setMarkerInsets(Insets.decode(insets));
+    }
+
+    /**
+     * Returns the foreground color for the markers of the ruler.
+     *
+     * @return The foreground (marker) color.
+     */
+    public final Color getColor() {
+        return color;
+    }
+
+    /**
+     * Sets the foreground color for the markers of the ruler.
+     *
+     * @param color The foreground (that is, the marker) color.
+     */
+    public final void setColor(Color color) {
+        Utils.checkNull(color, "color");
+
+        this.color = color;
+        repaintComponent();
+    }
+
+    /**
+     * Sets the foreground color for the markers of the ruler.
+     *
+     * @param color Any of the {@linkplain GraphicsUtilities#decodeColor color
+     * values recognized by Pivot}.
+     */
+    public final void setColor(String color) {
+        setColor(GraphicsUtilities.decodeColor(color, "color"));
+    }
+
+    public final void setColor(int color) {
+        Theme theme = currentTheme();
+        setColor(theme.getColor(color));
+    }
+
+    /**
+     * Returns the background color of the ruler.
+     *
+     * @return The current background color.
+     */
+    public final Color getBackgroundColor() {
+        return backgroundColor;
+    }
+
+    /**
+     * Sets the background color of the ruler.
+     *
+     * @param backgroundColor New background color value (can be {@code null}
+     * for a transparent background).
+     */
+    public final void setBackgroundColor(Color backgroundColor) {
+        this.backgroundColor = backgroundColor;
+        repaintComponent();
+    }
+
+    /**
+     * Sets the background color of the ruler.
+     *
+     * @param backgroundColor Any of the
+     * {@linkplain GraphicsUtilities#decodeColor color values recognized by
+     * Pivot}.
+     */
+    public final void setBackgroundColor(String backgroundColor) {
+        setBackgroundColor(GraphicsUtilities.decodeColor(backgroundColor, 
"backgroundColor"));
+    }
+
+    public final void setBackgroundColor(int backgroundColor) {
+        Theme theme = currentTheme();
+        setBackgroundColor(theme.getColor(backgroundColor));
+    }
+
+    /**
+     * @return The font used to format division numbers (if enabled).
+     */
+    public final Font getFont() {
+        return font;
+    }
+
+    /**
+     * Sets the font used in rendering the Ruler's text.
+     *
+     * @param font The new font to use.
+     */
+    public final void setFont(Font font) {
+        Utils.checkNull(font, "font");
+
+        // The font we will use is the same name and style, but a 11 pt type
+        this.font = font.deriveFont(11.0f);
+
+        // Make some size calculations for the drawing code
+        FontRenderContext fontRenderContext = Platform.getFontRenderContext();
+        GlyphVector glyphVector = 
this.font.createGlyphVector(fontRenderContext, "0");
+        Rectangle2D textBounds = glyphVector.getLogicalBounds();
+        this.charWidth = (float) textBounds.getWidth();
+        // Since we're just drawing numbers, the line spacing can be just the 
ascent value for the font
+        LineMetrics lm = this.font.getLineMetrics("0", fontRenderContext);
+        this.charHeight = lm.getAscent();
+        this.descent = lm.getDescent();
+
+        invalidateComponent();
+    }
+
+    /**
+     * Sets the font used in rendering the Ruler's text.
+     *
+     * @param font A {@link ComponentSkin#decodeFont(String) font 
specification}
+     */
+    public final void setFont(String font) {
+        setFont(decodeFont(font));
+    }
+
+    /**
+     * Sets the font used in rendering the Ruler's text.
+     *
+     * @param font A dictionary {@link Theme#deriveFont describing a font}
+     */
+    public final void setFont(Dictionary<String, ?> font) {
+        setFont(Theme.deriveFont(font));
+    }
+
+}

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

Modified: pivot/trunk/wtk/src/org/apache/pivot/wtk/skin/TabPaneSkin.java
URL: 
http://svn.apache.org/viewvc/pivot/trunk/wtk/src/org/apache/pivot/wtk/skin/TabPaneSkin.java?rev=1913470&r1=1913469&r2=1913470&view=diff
==============================================================================
--- pivot/trunk/wtk/src/org/apache/pivot/wtk/skin/TabPaneSkin.java (original)
+++ pivot/trunk/wtk/src/org/apache/pivot/wtk/skin/TabPaneSkin.java Tue Oct 31 
19:15:47 2023
@@ -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.skin;
-
-import org.apache.pivot.wtk.BoxPane;
-import org.apache.pivot.wtk.TabPane;
-
-/**
- * Tab pane skin. Note that this class is abstract but only because in layout
- * method there are many things already defined that uses the original skin
- * implementation (TerraTabPaneSkin).
- */
-public abstract class TabPaneSkin extends ContainerSkin implements 
TabPane.Skin {
-
-    protected BoxPane buttonBoxPane = new BoxPane();
-
-    @Override
-    public boolean isVisible(final int index) {
-        return buttonBoxPane.get(index).isVisible();
-    }
-
-    @Override
-    public void setVisible(final int index, final boolean value) {
-        buttonBoxPane.get(index).setVisible(value);
-    }
-
-}
+/*
+ * 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.wtk.BoxPane;
+import org.apache.pivot.wtk.TabPane;
+
+/**
+ * Tab pane skin. Note that this class is abstract but only because in layout
+ * method there are many things already defined that uses the original skin
+ * implementation (TerraTabPaneSkin).
+ */
+public abstract class TabPaneSkin extends ContainerSkin implements 
TabPane.Skin {
+
+    protected BoxPane buttonBoxPane = new BoxPane();
+
+    @Override
+    public boolean isVisible(final int index) {
+        return buttonBoxPane.get(index).isVisible();
+    }
+
+    @Override
+    public void setVisible(final int index, final boolean value) {
+        buttonBoxPane.get(index).setVisible(value);
+    }
+
+}

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

Modified: pivot/trunk/wtk/src/org/apache/pivot/wtk/skin/VFSBrowserSkin.java
URL: 
http://svn.apache.org/viewvc/pivot/trunk/wtk/src/org/apache/pivot/wtk/skin/VFSBrowserSkin.java?rev=1913470&r1=1913469&r2=1913470&view=diff
==============================================================================
--- pivot/trunk/wtk/src/org/apache/pivot/wtk/skin/VFSBrowserSkin.java (original)
+++ pivot/trunk/wtk/src/org/apache/pivot/wtk/skin/VFSBrowserSkin.java Tue Oct 
31 19:15:47 2023
@@ -1,35 +1,35 @@
-/*
- * 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.wtk.Component;
-import org.apache.pivot.wtk.VFSBrowser;
-import org.apache.pivot.wtk.VFSBrowserListener;
-
-/**
- * Abstract base class for Commons VFS browser skins.
- */
-public abstract class VFSBrowserSkin extends ContainerSkin implements 
VFSBrowser.Skin,
-    VFSBrowserListener {
-    @Override
-    public void install(final Component component) {
-        super.install(component);
-
-        VFSBrowser fileBrowser = (VFSBrowser) component;
-        fileBrowser.getFileBrowserListeners().add(this);
-    }
-}
+/*
+ * 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.wtk.Component;
+import org.apache.pivot.wtk.VFSBrowser;
+import org.apache.pivot.wtk.VFSBrowserListener;
+
+/**
+ * Abstract base class for Commons VFS browser skins.
+ */
+public abstract class VFSBrowserSkin extends ContainerSkin implements 
VFSBrowser.Skin,
+    VFSBrowserListener {
+    @Override
+    public void install(final Component component) {
+        super.install(component);
+
+        VFSBrowser fileBrowser = (VFSBrowser) component;
+        fileBrowser.getFileBrowserListeners().add(this);
+    }
+}

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

Modified: pivot/trunk/wtk/src/org/apache/pivot/wtk/util/ColorUtilities.java
URL: 
http://svn.apache.org/viewvc/pivot/trunk/wtk/src/org/apache/pivot/wtk/util/ColorUtilities.java?rev=1913470&r1=1913469&r2=1913470&view=diff
==============================================================================
--- pivot/trunk/wtk/src/org/apache/pivot/wtk/util/ColorUtilities.java (original)
+++ pivot/trunk/wtk/src/org/apache/pivot/wtk/util/ColorUtilities.java Tue Oct 
31 19:15:47 2023
@@ -1,299 +1,299 @@
-/*
- * 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.util;
-
-import java.awt.Color;
-
-import org.apache.pivot.util.Utils;
-import org.apache.pivot.wtk.Theme;
-import org.apache.pivot.wtk.CSSColor;
-import org.apache.pivot.wtk.GraphicsUtilities;
-
-
-/**
- * Utility methods for/on Colors.
- */
-public final class ColorUtilities {
-
-    /**
-     * Private constructor since this is a utility class (all static methods).
-     */
-    private ColorUtilities() {
-    }
-
-    /**
-     * Returns a brighter version of the specified color. Specifically, it
-     * increases the brightness (in the HSB color model) by the given
-     * {@code adjustment} factor (usually in the range ]0 .. 1[).
-     *
-     * @param color the color
-     * @param adjustment the adjustment factor
-     * @return the color brightened
-     */
-    public static Color brighten(final Color color, final float adjustment) {
-        return adjustBrightness(color, adjustment);
-    }
-
-    /**
-     * Returns a darker version of the specified color. Specifically, it
-     * decreases the brightness (in the HSB color model) by the given
-     * {@code adjustment} factor (usually in the range ]0 .. 1[).
-     *
-     * @param color the color
-     * @param adjustment the adjustment factor
-     * @return the color darkened
-     */
-    public static Color darken(final Color color, final float adjustment) {
-        return adjustBrightness(color, (adjustment * -1.0f));
-    }
-
-    /**
-     * Change the brightness of the given color, and returns the changed color.
-     *
-     * @param color the color
-     * @param adjustment the adjustment factor (usually in the range ]0 .. 1[)
-     * @return the new color
-     */
-    public static Color adjustBrightness(final Color color, final float 
adjustment) {
-        float[] hsb = Color.RGBtoHSB(color.getRed(), color.getGreen(), 
color.getBlue(), null);
-        hsb[2] = Math.min(Math.max(hsb[2] + adjustment, 0f), 1f);
-        int rgb = Color.HSBtoRGB(hsb[0], hsb[1], hsb[2]);
-        return new Color((color.getAlpha() << 24) | (rgb & 0xffffff), true);
-    }
-
-    /**
-     * Returns a numeric version of the difference of all color RGB components.
-     *
-     * @param color1 the first color
-     * @param color2 the second color
-     * @return the value of the difference
-     */
-    public static int colorDifferenceRGBTotal(final Color color1, final Color 
color2) {
-        return Math.abs(color1.getRed() - color2.getRed())
-            + Math.abs(color1.getGreen() - color2.getGreen())
-            + Math.abs(color1.getBlue() - color2.getBlue());
-    }
-
-    /**
-     * Returns a numeric version of the difference of all color RGB components.
-     *
-     * @param color1 the first color
-     * @param color2 the second color
-     * @return an array of three elements, containing a value of the difference
-     * for any channel (red, green, blue), with values in the usual RGB range
-     */
-    public static int[] colorDifferenceRGB(final Color color1, final Color 
color2) {
-        int[] difference = new int[3];
-
-        difference[0] = Math.abs(color1.getRed() - color2.getRed());
-        difference[1] = Math.abs(color1.getGreen() - color2.getGreen());
-        difference[2] = Math.abs(color1.getBlue() - color2.getBlue());
-
-        return difference;
-    }
-
-    /**
-     * Returns a Color by subtracting the given color from white.
-     *
-     * @param color the color to subtract
-     * @return a Color
-     */
-    public static Color colorDifferenceFromWhite(final Color color) {
-        int[] difference = new int[3];
-
-        difference[0] = 255 - color.getRed();
-        difference[1] = 255 - color.getGreen();
-        difference[2] = 255 - color.getBlue();
-
-        return new Color(difference[0], difference[1], difference[2]);
-    }
-
-    /**
-     * Returns a numeric version of the difference of all color in HSV
-     * components.
-     *
-     * @param color1 the first color
-     * @param color2 the second color
-     * @return an array of three elements, containing a value of the difference
-     * for any channel (hue, saturation, brightness), with values in the usual
-     * HSV range
-     */
-    public static float[] colorDifferenceHSV(final Color color1, final Color 
color2) {
-        float[] difference = new float[3];
-
-        float[] hsb1 = Color.RGBtoHSB(color1.getRed(), color1.getGreen(), 
color1.getBlue(), null);
-        float[] hsb2 = Color.RGBtoHSB(color2.getRed(), color2.getGreen(), 
color2.getBlue(), null);
-
-        difference[0] = Math.abs(hsb1[0] - hsb2[0]);
-        difference[1] = Math.abs(hsb1[1] - hsb2[1]);
-        difference[2] = Math.abs(hsb1[2] - hsb2[2]);
-
-        return difference;
-    }
-
-    /**
-     * @return A solid color from the given color value (that is, with the 
transparency removed
-     * from the original).
-     * @param original The original (potentially transparent) color.
-     */
-    public static Color toSolidColor(final Color original) {
-        return new Color(original.getRed(), original.getGreen(), 
original.getBlue());
-    }
-
-    /**
-     * Returns a modified version of the given Color.
-     * @param original The original color
-     * @param transparency The desired transparency (alpha) to set.
-     * @return An updated version of the color, with the given transparency.
-     */
-    public static Color toTransparentColor(final Color original, final int 
transparency) {
-        return new Color(original.getRed(), original.getGreen(), 
original.getBlue(), transparency);
-    }
-
-    /**
-     * Returns a modified version of the given Theme color.
-     * @param colorIndex Index into the Theme color palette of the color to 
modify.
-     * @param transparency The transparency value to set in the color.
-     * @return An updated version of the color, with the given transparency.
-     */
-    public static Color toTransparentColor(final int colorIndex, final int 
transparency) {
-        Theme theme = Theme.getTheme();
-        return toTransparentColor(theme.getColor(colorIndex), transparency);
-    }
-
-    /**
-     * Returns a modified version of the given {@link CSSColor}.
-     * @param original The original color.
-     * @param transparency The desired transparency (alpha) to set.
-     * @return An color value updated from the original with the given 
transparency.
-     */
-    public static Color toTransparentColor(final CSSColor original, final int 
transparency) {
-        return toTransparentColor(original.getColor(), transparency);
-    }
-
-    /**
-     * Returns a modified version of the given Color.
-     * <p> Deprecated in favor of new {@link #toTransparentColor(Color,int)} 
method (same functionality, nicer name).
-     * @param original The original color
-     * @param transparency The desired transparency (alpha) to set.
-     * @return An updated version of the color, with the given transparency.
-     */
-    @Deprecated
-    public static Color setTransparencyInColor(final Color original, final int 
transparency) {
-        return toTransparentColor(original, transparency);
-    }
-
-    /**
-     * Returns a modified version of the given Theme color.
-     * <p> Deprecated in favor of new {@link #toTransparentColor(int,int)} 
method (same functionality, nicer name).
-     * @param colorIndex Index into the Theme color palette of the color to 
modify.
-     * @param transparency The transparency value to set in the color.
-     * @return An updated version of the color, with the given transparency.
-     */
-    @Deprecated
-    public static Color setTransparencyInColor(final int colorIndex, final int 
transparency) {
-        return toTransparentColor(colorIndex, transparency);
-    }
-
-    /**
-     * Returns a modified version of the given {@link CSSColor}.
-     * <p> Deprecated in favor of new {@link 
#toTransparentColor(CSSColor,int)} method (same functionality, nicer name).
-     * @param original The original color.
-     * @param transparency The desired transparency (alpha) to set.
-     * @return An color value updated from the original with the given 
transparency.
-     */
-    @Deprecated
-    public static Color setTransparencyInColor(final CSSColor original, final 
int transparency) {
-        return toTransparentColor(original, transparency);
-    }
-
-    /**
-     * @return An encoded value for the given color in the form of:
-     * <code>#RRGGBB</code> or <code>0xRRGGBBTT</code> (where 
<code>"TT"</code> is the
-     * alpha transparency value of the color, if not solid),
-     * either of which is suitable for lookup in the
-     * {@link org.apache.pivot.wtk.GraphicsUtilities#decodeColor(String)} 
method.
-     * @param color The input color to convert.
-     */
-    public static String toStringValue(final Color color) {
-        int alpha = color.getAlpha();
-        if (alpha != 255) {
-            // A translucent color
-            return String.format("0x%02X%02X%02X%02X",
-                color.getRed(), color.getGreen(), color.getBlue(), alpha);
-        } else {
-            // A solid color
-            return String.format("#%02X%02X%02X",
-                color.getRed(), color.getGreen(), color.getBlue());
-        }
-    }
-
-    /**
-     * @return An encoded value for the given {@link CSSColor} in the form of:
-     * <code>#RRGGBB</code> only (since these are always solid colors by 
definition),
-     * which is suitable for lookup in the
-     * {@link org.apache.pivot.wtk.GraphicsUtilities#decodeColor(String)} 
method.
-     * @param color The input color to convert.
-     * @see #toStringValue(Color)
-     */
-    public static String toStringValue(final CSSColor color) {
-        return toStringValue(color.getColor());
-    }
-
-    /**
-     * Interpret an object as a color value.
-     *
-     * @param colorValue One of a {@link String} (interpreted by {@link 
GraphicsUtilities#decodeColor(String,String)}),
-     * a straight {@link Color}, one of our {@link CSSColor} values, or an 
integer index into the theme's
-     * color palette.
-     * @param description An optional description for the call to {@link 
Utils#checkNull} in case of a null input value.
-     * @param allowNull Whether or not to allow a null color.
-     * @return The real {@link Color} value.
-     * @throws IllegalArgumentException if the {@code colorValue} is {@code 
null} (unless {@code allowNull}
-     * is {@code true}), or of a type we don't recognize.
-     */
-    public static Color fromObject(final Object colorValue, final String 
description, final boolean allowNull) {
-        if (!allowNull) {
-            Utils.checkNull(colorValue, description);
-        }
-
-        Color color;
-
-        if (allowNull && colorValue == null) {
-            color = null;
-        } else if (colorValue instanceof Color) {
-            color = (Color) colorValue;
-        } else if (colorValue instanceof String) {
-            Color decodedColor = GraphicsUtilities.decodeColor((String) 
colorValue);
-            if (!allowNull) {
-                Utils.checkNull(decodedColor, description);
-            }
-            color = decodedColor;
-        } else if (colorValue instanceof CSSColor) {
-            color = ((CSSColor) colorValue).getColor();
-        } else if (colorValue instanceof Number) {
-            Theme theme = Theme.getTheme();
-            color = theme.getColor(((Number) colorValue).intValue());
-        } else {
-            throw new IllegalArgumentException("Object of type "
-                + colorValue.getClass().getName() + " cannot be converted to a 
Color.");
-        }
-
-        return color;
-    }
-
-}
+/*
+ * 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.util;
+
+import java.awt.Color;
+
+import org.apache.pivot.util.Utils;
+import org.apache.pivot.wtk.Theme;
+import org.apache.pivot.wtk.CSSColor;
+import org.apache.pivot.wtk.GraphicsUtilities;
+
+
+/**
+ * Utility methods for/on Colors.
+ */
+public final class ColorUtilities {
+
+    /**
+     * Private constructor since this is a utility class (all static methods).
+     */
+    private ColorUtilities() {
+    }
+
+    /**
+     * Returns a brighter version of the specified color. Specifically, it
+     * increases the brightness (in the HSB color model) by the given
+     * {@code adjustment} factor (usually in the range ]0 .. 1[).
+     *
+     * @param color the color
+     * @param adjustment the adjustment factor
+     * @return the color brightened
+     */
+    public static Color brighten(final Color color, final float adjustment) {
+        return adjustBrightness(color, adjustment);
+    }
+
+    /**
+     * Returns a darker version of the specified color. Specifically, it
+     * decreases the brightness (in the HSB color model) by the given
+     * {@code adjustment} factor (usually in the range ]0 .. 1[).
+     *
+     * @param color the color
+     * @param adjustment the adjustment factor
+     * @return the color darkened
+     */
+    public static Color darken(final Color color, final float adjustment) {
+        return adjustBrightness(color, (adjustment * -1.0f));
+    }
+
+    /**
+     * Change the brightness of the given color, and returns the changed color.
+     *
+     * @param color the color
+     * @param adjustment the adjustment factor (usually in the range ]0 .. 1[)
+     * @return the new color
+     */
+    public static Color adjustBrightness(final Color color, final float 
adjustment) {
+        float[] hsb = Color.RGBtoHSB(color.getRed(), color.getGreen(), 
color.getBlue(), null);
+        hsb[2] = Math.min(Math.max(hsb[2] + adjustment, 0f), 1f);
+        int rgb = Color.HSBtoRGB(hsb[0], hsb[1], hsb[2]);
+        return new Color((color.getAlpha() << 24) | (rgb & 0xffffff), true);
+    }
+
+    /**
+     * Returns a numeric version of the difference of all color RGB components.
+     *
+     * @param color1 the first color
+     * @param color2 the second color
+     * @return the value of the difference
+     */
+    public static int colorDifferenceRGBTotal(final Color color1, final Color 
color2) {
+        return Math.abs(color1.getRed() - color2.getRed())
+            + Math.abs(color1.getGreen() - color2.getGreen())
+            + Math.abs(color1.getBlue() - color2.getBlue());
+    }
+
+    /**
+     * Returns a numeric version of the difference of all color RGB components.
+     *
+     * @param color1 the first color
+     * @param color2 the second color
+     * @return an array of three elements, containing a value of the difference
+     * for any channel (red, green, blue), with values in the usual RGB range
+     */
+    public static int[] colorDifferenceRGB(final Color color1, final Color 
color2) {
+        int[] difference = new int[3];
+
+        difference[0] = Math.abs(color1.getRed() - color2.getRed());
+        difference[1] = Math.abs(color1.getGreen() - color2.getGreen());
+        difference[2] = Math.abs(color1.getBlue() - color2.getBlue());
+
+        return difference;
+    }
+
+    /**
+     * Returns a Color by subtracting the given color from white.
+     *
+     * @param color the color to subtract
+     * @return a Color
+     */
+    public static Color colorDifferenceFromWhite(final Color color) {
+        int[] difference = new int[3];
+
+        difference[0] = 255 - color.getRed();
+        difference[1] = 255 - color.getGreen();
+        difference[2] = 255 - color.getBlue();
+
+        return new Color(difference[0], difference[1], difference[2]);
+    }
+
+    /**
+     * Returns a numeric version of the difference of all color in HSV
+     * components.
+     *
+     * @param color1 the first color
+     * @param color2 the second color
+     * @return an array of three elements, containing a value of the difference
+     * for any channel (hue, saturation, brightness), with values in the usual
+     * HSV range
+     */
+    public static float[] colorDifferenceHSV(final Color color1, final Color 
color2) {
+        float[] difference = new float[3];
+
+        float[] hsb1 = Color.RGBtoHSB(color1.getRed(), color1.getGreen(), 
color1.getBlue(), null);
+        float[] hsb2 = Color.RGBtoHSB(color2.getRed(), color2.getGreen(), 
color2.getBlue(), null);
+
+        difference[0] = Math.abs(hsb1[0] - hsb2[0]);
+        difference[1] = Math.abs(hsb1[1] - hsb2[1]);
+        difference[2] = Math.abs(hsb1[2] - hsb2[2]);
+
+        return difference;
+    }
+
+    /**
+     * @return A solid color from the given color value (that is, with the 
transparency removed
+     * from the original).
+     * @param original The original (potentially transparent) color.
+     */
+    public static Color toSolidColor(final Color original) {
+        return new Color(original.getRed(), original.getGreen(), 
original.getBlue());
+    }
+
+    /**
+     * Returns a modified version of the given Color.
+     * @param original The original color
+     * @param transparency The desired transparency (alpha) to set.
+     * @return An updated version of the color, with the given transparency.
+     */
+    public static Color toTransparentColor(final Color original, final int 
transparency) {
+        return new Color(original.getRed(), original.getGreen(), 
original.getBlue(), transparency);
+    }
+
+    /**
+     * Returns a modified version of the given Theme color.
+     * @param colorIndex Index into the Theme color palette of the color to 
modify.
+     * @param transparency The transparency value to set in the color.
+     * @return An updated version of the color, with the given transparency.
+     */
+    public static Color toTransparentColor(final int colorIndex, final int 
transparency) {
+        Theme theme = Theme.getTheme();
+        return toTransparentColor(theme.getColor(colorIndex), transparency);
+    }
+
+    /**
+     * Returns a modified version of the given {@link CSSColor}.
+     * @param original The original color.
+     * @param transparency The desired transparency (alpha) to set.
+     * @return An color value updated from the original with the given 
transparency.
+     */
+    public static Color toTransparentColor(final CSSColor original, final int 
transparency) {
+        return toTransparentColor(original.getColor(), transparency);
+    }
+
+    /**
+     * Returns a modified version of the given Color.
+     * <p> Deprecated in favor of new {@link #toTransparentColor(Color,int)} 
method (same functionality, nicer name).
+     * @param original The original color
+     * @param transparency The desired transparency (alpha) to set.
+     * @return An updated version of the color, with the given transparency.
+     */
+    @Deprecated
+    public static Color setTransparencyInColor(final Color original, final int 
transparency) {
+        return toTransparentColor(original, transparency);
+    }
+
+    /**
+     * Returns a modified version of the given Theme color.
+     * <p> Deprecated in favor of new {@link #toTransparentColor(int,int)} 
method (same functionality, nicer name).
+     * @param colorIndex Index into the Theme color palette of the color to 
modify.
+     * @param transparency The transparency value to set in the color.
+     * @return An updated version of the color, with the given transparency.
+     */
+    @Deprecated
+    public static Color setTransparencyInColor(final int colorIndex, final int 
transparency) {
+        return toTransparentColor(colorIndex, transparency);
+    }
+
+    /**
+     * Returns a modified version of the given {@link CSSColor}.
+     * <p> Deprecated in favor of new {@link 
#toTransparentColor(CSSColor,int)} method (same functionality, nicer name).
+     * @param original The original color.
+     * @param transparency The desired transparency (alpha) to set.
+     * @return An color value updated from the original with the given 
transparency.
+     */
+    @Deprecated
+    public static Color setTransparencyInColor(final CSSColor original, final 
int transparency) {
+        return toTransparentColor(original, transparency);
+    }
+
+    /**
+     * @return An encoded value for the given color in the form of:
+     * <code>#RRGGBB</code> or <code>0xRRGGBBTT</code> (where 
<code>"TT"</code> is the
+     * alpha transparency value of the color, if not solid),
+     * either of which is suitable for lookup in the
+     * {@link org.apache.pivot.wtk.GraphicsUtilities#decodeColor(String)} 
method.
+     * @param color The input color to convert.
+     */
+    public static String toStringValue(final Color color) {
+        int alpha = color.getAlpha();
+        if (alpha != 255) {
+            // A translucent color
+            return String.format("0x%02X%02X%02X%02X",
+                color.getRed(), color.getGreen(), color.getBlue(), alpha);
+        } else {
+            // A solid color
+            return String.format("#%02X%02X%02X",
+                color.getRed(), color.getGreen(), color.getBlue());
+        }
+    }
+
+    /**
+     * @return An encoded value for the given {@link CSSColor} in the form of:
+     * <code>#RRGGBB</code> only (since these are always solid colors by 
definition),
+     * which is suitable for lookup in the
+     * {@link org.apache.pivot.wtk.GraphicsUtilities#decodeColor(String)} 
method.
+     * @param color The input color to convert.
+     * @see #toStringValue(Color)
+     */
+    public static String toStringValue(final CSSColor color) {
+        return toStringValue(color.getColor());
+    }
+
+    /**
+     * Interpret an object as a color value.
+     *
+     * @param colorValue One of a {@link String} (interpreted by {@link 
GraphicsUtilities#decodeColor(String,String)}),
+     * a straight {@link Color}, one of our {@link CSSColor} values, or an 
integer index into the theme's
+     * color palette.
+     * @param description An optional description for the call to {@link 
Utils#checkNull} in case of a null input value.
+     * @param allowNull Whether or not to allow a null color.
+     * @return The real {@link Color} value.
+     * @throws IllegalArgumentException if the {@code colorValue} is {@code 
null} (unless {@code allowNull}
+     * is {@code true}), or of a type we don't recognize.
+     */
+    public static Color fromObject(final Object colorValue, final String 
description, final boolean allowNull) {
+        if (!allowNull) {
+            Utils.checkNull(colorValue, description);
+        }
+
+        Color color;
+
+        if (allowNull && colorValue == null) {
+            color = null;
+        } else if (colorValue instanceof Color) {
+            color = (Color) colorValue;
+        } else if (colorValue instanceof String) {
+            Color decodedColor = GraphicsUtilities.decodeColor((String) 
colorValue);
+            if (!allowNull) {
+                Utils.checkNull(decodedColor, description);
+            }
+            color = decodedColor;
+        } else if (colorValue instanceof CSSColor) {
+            color = ((CSSColor) colorValue).getColor();
+        } else if (colorValue instanceof Number) {
+            Theme theme = Theme.getTheme();
+            color = theme.getColor(((Number) colorValue).intValue());
+        } else {
+            throw new IllegalArgumentException("Object of type "
+                + colorValue.getClass().getName() + " cannot be converted to a 
Color.");
+        }
+
+        return color;
+    }
+
+}

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

Modified: 
pivot/trunk/wtk/src/org/apache/pivot/wtk/util/TextAreaOutputStream.java
URL: 
http://svn.apache.org/viewvc/pivot/trunk/wtk/src/org/apache/pivot/wtk/util/TextAreaOutputStream.java?rev=1913470&r1=1913469&r2=1913470&view=diff
==============================================================================
--- pivot/trunk/wtk/src/org/apache/pivot/wtk/util/TextAreaOutputStream.java 
(original)
+++ pivot/trunk/wtk/src/org/apache/pivot/wtk/util/TextAreaOutputStream.java Tue 
Oct 31 19:15:47 2023
@@ -1,187 +1,187 @@
-/*
- * 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.util;
-
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.OutputStream;
-import java.io.PrintStream;
-import java.io.UnsupportedEncodingException;
-import java.nio.charset.Charset;
-import org.apache.pivot.wtk.ApplicationContext;
-import org.apache.pivot.wtk.Bounds;
-import org.apache.pivot.wtk.TextArea;
-
-/**
- * Creates an {@link OutputStream} that outputs to a {@link TextArea}
- * (in the EDT thread, using callbacks) for display.
- * <p> Can be used with the {@link org.apache.pivot.util.Console} class for 
output (using the
- * {@link #toPrintStream} method).
- */
-public final class TextAreaOutputStream extends OutputStream {
-    /** The TextArea we are going to stream to. */
-    private TextArea textArea;
-
-    /** Default line buffer size (can be overridden through a constructor). */
-    private static final int DEFAULT_BUFFER_SIZE = 2_048;
-
-    /** Buffer size to use for incoming lines of text. */
-    private int lineBufferSize;
-
-    /** The charset to use for converting incoming bytes to characters. */
-    private Charset incomingCharset;
-
-    /** The buffered line for this stream. */
-    private ByteArrayOutputStream lineBuffer;
-
-    /**
-     * Simple constructor given the {@link TextArea} to stream to; uses the 
system
-     * default charset for conversion, and the default buffer size.
-     *
-     * @param textAreaToUse The TextArea to use for output.
-     */
-    public TextAreaOutputStream(final TextArea textAreaToUse) {
-        this(textAreaToUse, null, DEFAULT_BUFFER_SIZE);
-    }
-
-    /**
-     * Constructor given the {@link TextArea} to stream to, and the
-     * non-default line buffer size to use; uses the system default charset.
-     *
-     * @param textAreaToUse The TextArea to use for output.
-     * @param lineBufferSizeToUse The non-default size for the input line 
buffer.
-     */
-    public TextAreaOutputStream(final TextArea textAreaToUse, final int 
lineBufferSizeToUse) {
-        this(textAreaToUse, null, lineBufferSizeToUse);
-    }
-
-    /**
-     * Constructor given the {@link TextArea} to stream to, and the charset to 
use
-     * for decoding the incoming bytes into characters; uses the default line 
buffer size.
-     *
-     * @param textAreaToUse The TextArea to use for output.
-     * @param charsetToUse The charset used to convert incoming bytes to 
characters
-     * (can be {@code null} to use the platform standard charset).
-     */
-    public TextAreaOutputStream(final TextArea textAreaToUse, final Charset 
charsetToUse) {
-        this(textAreaToUse, charsetToUse, DEFAULT_BUFFER_SIZE);
-    }
-
-    /**
-     * Constructor given the {@link TextArea} to stream to, the charset to use
-     * for decoding the incoming bytes into characters, and the line buffer 
size to use.
-     *
-     * @param textAreaToUse The TextArea to use for output.
-     * @param charsetToUse The charset used to convert incoming bytes to 
characters
-     * (can be {@code null} to use the platform standard charset).
-     * @param lineBufferSizeToUse The size for the input line buffer.
-     */
-    public TextAreaOutputStream(final TextArea textAreaToUse, final Charset 
charsetToUse,
-        final int lineBufferSizeToUse) {
-        textArea        = textAreaToUse;
-        incomingCharset = (charsetToUse == null) ? Charset.defaultCharset() : 
charsetToUse;
-        lineBufferSize  = lineBufferSizeToUse;
-        lineBuffer      = new ByteArrayOutputStream(lineBufferSize);
-    }
-
-    /**
-     * @throws IOException if this stream is already closed.
-     */
-    private void checkIfOpen() throws IOException {
-        if (textArea == null || lineBuffer == null) {
-            throw new IOException("TextAreaOutputStream is closed.");
-        }
-    }
-
-    /**
-     * Flush the (byte) line buffer if there is anything cached.
-     * @param addNewLine Add a newline ('\n') character after any buffered 
text.
-     */
-    private void flushLineBuffer(final boolean addNewLine) {
-        final String text;
-
-        if (lineBuffer.size() > 0) {
-            byte[] bytes = lineBuffer.toByteArray();
-            text = new String(bytes, incomingCharset);
-            lineBuffer.reset();
-        } else {
-            text = "";
-        }
-
-        // Do the actual text manipulation (including scrolling) on the event 
thread
-        if (!text.isEmpty() || addNewLine) {
-            ApplicationContext.queueCallback(() -> {
-                int length    = textArea.getCharacterCount();
-                int newLength = length;
-
-                if (!text.isEmpty()) {
-                    textArea.insertText(text, length);
-                    newLength += text.length();
-                }
-
-                if (addNewLine) {
-                    textArea.insertText("\n", newLength++);
-                }
-
-                final int lastCharPos = newLength;
-
-                // In order to allow time for the skin to render the latest 
additions,
-                // queue the actual scrolling until that is done
-                ApplicationContext.queueCallback(() -> {
-                    Bounds lastCharBounds = 
textArea.getCharacterBounds(lastCharPos);
-                    textArea.scrollAreaToVisible(lastCharBounds);
-                });
-            });
-        }
-    }
-
-    @Override
-    public void close() throws IOException {
-        flush();
-        textArea        = null;
-        incomingCharset = null;
-        lineBuffer      = null;
-    }
-
-    @Override
-    public void flush() throws IOException {
-        checkIfOpen();
-        flushLineBuffer(false);
-    }
-
-    @Override
-    public void write(final int b) throws IOException {
-        if (b == '\n') {
-            flushLineBuffer(true);
-        } else if (b != '\r') {
-            lineBuffer.write(b);
-        }
-    }
-
-    /**
-     * @return A new {@link PrintStream} using this object as the basis (and 
the
-     * same charset specified by one of the constructors).
-     */
-    public PrintStream toPrintStream() {
-        try {
-            return new PrintStream(this, false, incomingCharset.name());
-        } catch (UnsupportedEncodingException uee) {
-            throw new RuntimeException("Impossible unsupported encoding 
error!", uee);
-        }
-    }
-
-}
+/*
+ * 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.util;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.PrintStream;
+import java.io.UnsupportedEncodingException;
+import java.nio.charset.Charset;
+import org.apache.pivot.wtk.ApplicationContext;
+import org.apache.pivot.wtk.Bounds;
+import org.apache.pivot.wtk.TextArea;
+
+/**
+ * Creates an {@link OutputStream} that outputs to a {@link TextArea}
+ * (in the EDT thread, using callbacks) for display.
+ * <p> Can be used with the {@link org.apache.pivot.util.Console} class for 
output (using the
+ * {@link #toPrintStream} method).
+ */
+public final class TextAreaOutputStream extends OutputStream {
+    /** The TextArea we are going to stream to. */
+    private TextArea textArea;
+
+    /** Default line buffer size (can be overridden through a constructor). */
+    private static final int DEFAULT_BUFFER_SIZE = 2_048;
+
+    /** Buffer size to use for incoming lines of text. */
+    private int lineBufferSize;
+
+    /** The charset to use for converting incoming bytes to characters. */
+    private Charset incomingCharset;
+
+    /** The buffered line for this stream. */
+    private ByteArrayOutputStream lineBuffer;
+
+    /**
+     * Simple constructor given the {@link TextArea} to stream to; uses the 
system
+     * default charset for conversion, and the default buffer size.
+     *
+     * @param textAreaToUse The TextArea to use for output.
+     */
+    public TextAreaOutputStream(final TextArea textAreaToUse) {
+        this(textAreaToUse, null, DEFAULT_BUFFER_SIZE);
+    }
+
+    /**
+     * Constructor given the {@link TextArea} to stream to, and the
+     * non-default line buffer size to use; uses the system default charset.
+     *
+     * @param textAreaToUse The TextArea to use for output.
+     * @param lineBufferSizeToUse The non-default size for the input line 
buffer.
+     */
+    public TextAreaOutputStream(final TextArea textAreaToUse, final int 
lineBufferSizeToUse) {
+        this(textAreaToUse, null, lineBufferSizeToUse);
+    }
+
+    /**
+     * Constructor given the {@link TextArea} to stream to, and the charset to 
use
+     * for decoding the incoming bytes into characters; uses the default line 
buffer size.
+     *
+     * @param textAreaToUse The TextArea to use for output.
+     * @param charsetToUse The charset used to convert incoming bytes to 
characters
+     * (can be {@code null} to use the platform standard charset).
+     */
+    public TextAreaOutputStream(final TextArea textAreaToUse, final Charset 
charsetToUse) {
+        this(textAreaToUse, charsetToUse, DEFAULT_BUFFER_SIZE);
+    }
+
+    /**
+     * Constructor given the {@link TextArea} to stream to, the charset to use
+     * for decoding the incoming bytes into characters, and the line buffer 
size to use.
+     *
+     * @param textAreaToUse The TextArea to use for output.
+     * @param charsetToUse The charset used to convert incoming bytes to 
characters
+     * (can be {@code null} to use the platform standard charset).
+     * @param lineBufferSizeToUse The size for the input line buffer.
+     */
+    public TextAreaOutputStream(final TextArea textAreaToUse, final Charset 
charsetToUse,
+        final int lineBufferSizeToUse) {
+        textArea        = textAreaToUse;
+        incomingCharset = (charsetToUse == null) ? Charset.defaultCharset() : 
charsetToUse;
+        lineBufferSize  = lineBufferSizeToUse;
+        lineBuffer      = new ByteArrayOutputStream(lineBufferSize);
+    }
+
+    /**
+     * @throws IOException if this stream is already closed.
+     */
+    private void checkIfOpen() throws IOException {
+        if (textArea == null || lineBuffer == null) {
+            throw new IOException("TextAreaOutputStream is closed.");
+        }
+    }
+
+    /**
+     * Flush the (byte) line buffer if there is anything cached.
+     * @param addNewLine Add a newline ('\n') character after any buffered 
text.
+     */
+    private void flushLineBuffer(final boolean addNewLine) {
+        final String text;
+
+        if (lineBuffer.size() > 0) {
+            byte[] bytes = lineBuffer.toByteArray();
+            text = new String(bytes, incomingCharset);
+            lineBuffer.reset();
+        } else {
+            text = "";
+        }
+
+        // Do the actual text manipulation (including scrolling) on the event 
thread
+        if (!text.isEmpty() || addNewLine) {
+            ApplicationContext.queueCallback(() -> {
+                int length    = textArea.getCharacterCount();
+                int newLength = length;
+
+                if (!text.isEmpty()) {
+                    textArea.insertText(text, length);
+                    newLength += text.length();
+                }
+
+                if (addNewLine) {
+                    textArea.insertText("\n", newLength++);
+                }
+
+                final int lastCharPos = newLength;
+
+                // In order to allow time for the skin to render the latest 
additions,
+                // queue the actual scrolling until that is done
+                ApplicationContext.queueCallback(() -> {
+                    Bounds lastCharBounds = 
textArea.getCharacterBounds(lastCharPos);
+                    textArea.scrollAreaToVisible(lastCharBounds);
+                });
+            });
+        }
+    }
+
+    @Override
+    public void close() throws IOException {
+        flush();
+        textArea        = null;
+        incomingCharset = null;
+        lineBuffer      = null;
+    }
+
+    @Override
+    public void flush() throws IOException {
+        checkIfOpen();
+        flushLineBuffer(false);
+    }
+
+    @Override
+    public void write(final int b) throws IOException {
+        if (b == '\n') {
+            flushLineBuffer(true);
+        } else if (b != '\r') {
+            lineBuffer.write(b);
+        }
+    }
+
+    /**
+     * @return A new {@link PrintStream} using this object as the basis (and 
the
+     * same charset specified by one of the constructors).
+     */
+    public PrintStream toPrintStream() {
+        try {
+            return new PrintStream(this, false, incomingCharset.name());
+        } catch (UnsupportedEncodingException uee) {
+            throw new RuntimeException("Impossible unsupported encoding 
error!", uee);
+        }
+    }
+
+}

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

Propchange: pivot/trunk/wtk/src/org/apache/pivot/wtk/util/package.html
------------------------------------------------------------------------------
    svn:eol-style = native


Reply via email to