org.apache.myfaces.trinidad.convert.RGBColorFormat Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of trinidad-api Show documentation
Show all versions of trinidad-api Show documentation
Public API for the Apache MyFaces Trinidad project
/*
* 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.myfaces.trinidad.convert;
import java.awt.Color;
import java.text.FieldPosition;
import java.text.ParsePosition;
import org.apache.myfaces.trinidad.logging.TrinidadLogger;
/**
* Format for colors.
*
* Time Format Syntax:
*
* To specify the time format use a color pattern string.
* In this pattern, all ASCII letters are reserved as pattern letters,
* which are defined as the following:
*
*
* Symbol Meaning Presentation Example
* ------ ------- ------------ -------
* r red component (Number) 242
* g green component (Number) 242
* b blue component (Number) 242
* a alpha component (Number) 255
* R red component (Hex) F2
* G green component (Hex) F2
* B blue component (Hex) F2
* A alpha component (Hex) FF
* ' escape for text (Delimiter)
* '' single quote (Literal) '
*
*
*
* Examples:
*
*
* Format Pattern Result
* -------------- -------
* "#RRGGBB" ->> #6609CC
* "rrr,ggg,bbb" ->> 102,009,204
* "t" ->> Transparent (when alpha is zero)
*
*
*
* @version $Name: $ ($Revision: adfrt/faces/adf-faces-api/src/main/java/oracle/adf/view/faces/convert/RGBColorFormat.java#0 $) $Date: 10-nov-2005.19:09:13 $
* @todo This class needs to be part of the public API - need to move it to
* place where our public API exists, once we have figured it out.
*/
class RGBColorFormat extends ColorFormat
{
/**
* Creates a RGBColorFormat with the specified pattern.
*
* @param pattern the color format pattern
*/
public RGBColorFormat(
String pattern)
{
if (pattern == null)
throw new IllegalArgumentException();
_pattern = pattern;
}
/**
* Returns the value as a Color.
*/
@Override
public Object parseObject(
String text,
ParsePosition pos)
{
// do not attempt to parse null color string
if (text == null)
return null;
int start = pos.getIndex();
int oldStart = start;
boolean inQuote = false; // inQuote set true when hits 1st single quote
char prevCh = 0;
int count = 0;
int interQuoteCount = 1; // Number of chars between quotes
int[] rgba = new int[_FIELD_COUNT];
rgba[_ALPHA_FIELD] = 255; // default alpha to full (opaque)
for (int i=0; i < _pattern.length(); i++)
{
char ch = _pattern.charAt(i);
if (inQuote)
{
if (ch == '\'')
{
// ends with 2nd single quote
inQuote = false;
// two consecutive quotes outside a quote means we have
// a quote literal we need to match.
if (count == 0)
{
if (start >= text.length() || ch != text.charAt(start))
{
pos.setIndex(oldStart);
pos.setErrorIndex(start);
return null;
}
start++;
}
count = 0;
interQuoteCount = 0;
}
else
{
// pattern uses text following from 1st single quote.
if (start >= text.length() || ch != text.charAt(start))
{
// Check for cases like: 'at' in pattern vs "xt"
// in time text, where 'a' doesn't match with 'x'.
// If fail to match, return null.
pos.setIndex(oldStart); // left unchanged
pos.setErrorIndex(start);
return null;
}
count++;
start++;
}
}
else // !inQuote
{
if (ch == '\'')
{
inQuote = true;
if (count > 0) // handle cases like: e'at'
{
int startOffset = start;
start = _subParse(rgba, text, start, prevCh, count);
if (start < 0)
{
pos.setIndex(oldStart);
pos.setErrorIndex(startOffset);
return null;
}
count = 0;
}
if (interQuoteCount == 0)
{
// This indicates two consecutive quotes inside a quote,
// for example, 'o''clock'. We need to parse this as
// representing a single quote within the quote.
int startOffset = start;
if (start >= text.length() || ch != text.charAt(start))
{
pos.setIndex(oldStart);
pos.setErrorIndex(startOffset);
return null;
}
start++;
count = 1; // Make it look like we never left
}
}
else if (ch >= 'a' && ch <= 'z' || ch >= 'A' && ch <= 'Z')
{
// ch is a color pattern
if (ch != prevCh && count > 0) // e.g., rrr
{
int startOffset = start;
start = _subParse(rgba, text, start, prevCh, count);
if (start < 0)
{
pos.setIndex(oldStart);
pos.setErrorIndex(startOffset);
return null;
}
prevCh = ch;
count = 1;
}
else
{
if (ch != prevCh)
prevCh = ch;
count++;
}
}
else if (count > 0)
{
// handle cases like: "rrr,ggg,bbb", "RR.GG.BB", "r g b", etc
// where ch = ',', '.' or ' ', repectively.
int startOffset = start;
start = _subParse(rgba, text, start, prevCh, count);
if ( start < 0 )
{
pos.setIndex(oldStart);
pos.setErrorIndex(startOffset);
return null;
}
if (start >= text.length() || ch != text.charAt(start))
{
// handle cases like: 'RR g' in pattern vs. "FFx20"
// in color text, where ' ' doesn't match with 'x'.
pos.setIndex(oldStart);
pos.setErrorIndex(start);
return null;
}
start++;
count = 0;
prevCh = 0;
}
else // any other unquoted characters
{
if (start >= text.length() || ch != text.charAt(start))
{
// handle cases like: 'RR g' in pattern vs. "FF,,,20"
// in color text, where " " doesn't match with ",,,".
pos.setIndex(oldStart);
pos.setErrorIndex(start);
return null;
}
start++;
}
interQuoteCount++;
}
}
// Parse the last item in the pattern
if (count > 0)
{
int startOffset = start;
start = _subParse(rgba, text, start, prevCh, count);
if (start < 0)
{
pos.setIndex(oldStart);
pos.setErrorIndex(startOffset);
return null;
}
}
pos.setIndex(start);
return new Color(rgba[_RED_FIELD],
rgba[_GREEN_FIELD],
rgba[_BLUE_FIELD],
rgba[_ALPHA_FIELD]);
}
@Override
public StringBuffer format(
Color color,
StringBuffer toAppendTo,
FieldPosition pos)
{
// initialize
pos.setBeginIndex(0);
pos.setEndIndex(0);
// do not attempt to format null color
if (color == null)
return toAppendTo;
boolean inQuote = false; // true when between single quotes
char prevCh = 0; // previous pattern character
int count = 0; // number of time prevCh repeated
for (int i=0; i < _pattern.length(); ++i)
{
char ch = _pattern.charAt(i);
// Use subFormat() to format a repeated pattern character
// when a different pattern or non-pattern character is seen
if (ch != prevCh && count > 0)
{
toAppendTo = _subFormat(color, prevCh, count, toAppendTo);
count = 0;
}
if (ch == '\'')
{
// Consecutive single quotes are a single quote literal,
// either outside of quotes or between quotes
if ((i+1) < _pattern.length() &&
_pattern.charAt(i+1) == '\'')
{
toAppendTo.append('\'');
++i;
}
else
{
inQuote = !inQuote;
}
}
else if (!inQuote &&
(ch >= 'a' && ch <= 'z' || ch >= 'A' && ch <= 'Z'))
{
// ch is a date-time pattern character to be interpreted
// by subFormat(); count the number of times it is repeated
prevCh = ch;
++count;
}
else
{
// Append quoted characters and unquoted non-pattern characters
toAppendTo.append(ch);
}
}
// Format the last item in the pattern, if any
if (count > 0)
{
toAppendTo = _subFormat(color, prevCh, count, toAppendTo);
}
return toAppendTo;
}
public int length()
{
int size = 0;
boolean inQuote = false; // true when between single quotes
char prevCh = 0; // previous pattern character
int count = 0; // number of time prevCh repeated
for (int i=0; i < _pattern.length(); ++i)
{
char ch = _pattern.charAt(i);
// Use subFormat() to format a repeated pattern character
// when a different pattern or non-pattern character is seen
if (ch != prevCh && count > 0)
{
size += _subLength(prevCh);
count = 0;
}
if (ch == '\'')
{
// Consecutive single quotes are a single quote literal,
// either outside of quotes or between quotes
if ((i+1) < _pattern.length() &&
_pattern.charAt(i+1) == '\'')
{
size++;
++i;
}
else
{
inQuote = !inQuote;
}
}
else if (!inQuote &&
(ch >= 'a' && ch <= 'z' || ch >= 'A' && ch <= 'Z'))
{
// ch is a date-time pattern character to be interpreted
// by subFormat(); count the number of times it is repeated
prevCh = ch;
++count;
}
else
{
// Append quoted characters and unquoted non-pattern characters
size++;
}
}
// Format the last item in the pattern, if any
if (count > 0)
{
size += _subLength(prevCh);
}
return size;
}
// Private member function that does the real length calculations.
private int _subLength(
char ch)
{
switch (ch)
{
case 'r':
case 'g':
case 'b':
case 'a':
return 3;
case 'R':
case 'G':
case 'B':
case 'A':
return 2;
default:
throw new IllegalArgumentException(_LOG.getMessage(
"ILLEGAL_PATTERN_CHARACTER", ch));
}
}
// Private member function that does the real color parsing.
private int _subParse(
int[] rgba,
String text,
int start,
char ch,
int count)
{
switch (ch)
{
case 'r':
return _subParseDecimal(rgba, _RED_FIELD, text, start, count);
case 'g':
return _subParseDecimal(rgba, _GREEN_FIELD, text, start, count);
case 'b':
return _subParseDecimal(rgba, _BLUE_FIELD, text, start, count);
case 'a':
return _subParseDecimal(rgba, _ALPHA_FIELD, text, start, count);
case 'R':
return _subParseHex(rgba, _RED_FIELD, text, start, count);
case 'G':
return _subParseHex(rgba, _GREEN_FIELD, text, start, count);
case 'B':
return _subParseHex(rgba, _BLUE_FIELD, text, start, count);
case 'A':
return _subParseHex(rgba, _ALPHA_FIELD, text, start, count);
default:
throw new IllegalArgumentException(_LOG.getMessage(
"ILLEGAL_PATTERN_CHARACTER", ch));
}
}
private int _subParseDecimal(
int[] rgba,
int field,
String text,
int start,
int count)
{
return _subParseBase(rgba, field, text, start, count, 3, 10);
}
private int _subParseHex(
int[] rgba,
int field,
String text,
int start,
int count)
{
return _subParseBase(rgba, field, text, start, count, 2, 16);
}
private int _subParseBase(
int[] rgba,
int field,
String text,
int start,
int minDigits,
int maxDigits,
int base)
{
int length = text.length();
int atLeast = start + minDigits;
// make sure the color string is long enough
if (atLeast > length)
return -start;
int index;
int end = Math.min(length, start + maxDigits);
int value = 0;
for(index=start; index < end; index++)
{
int digit = Character.digit(text.charAt(index), base);
if (digit == -1)
{
// did not consume sufficient characters in color string
if (index < atLeast)
return -start;
else
break;
}
value *= base;
value += digit;
}
rgba[field] = value;
return index;
}
// Private member function that does the real color formatting.
private StringBuffer _subFormat(
Color color,
char ch,
int count,
StringBuffer toAppendTo) throws IllegalArgumentException
{
switch (ch)
{
case 'r':
return _subFormatDecimal(color.getRed(), count, toAppendTo);
case 'g':
return _subFormatDecimal(color.getGreen(), count, toAppendTo);
case 'b':
return _subFormatDecimal(color.getBlue(), count, toAppendTo);
case 'a':
return _subFormatDecimal(color.getAlpha(), count, toAppendTo);
case 'R':
return _subFormatHex(color.getRed(), count, toAppendTo);
case 'G':
return _subFormatHex(color.getGreen(), count, toAppendTo);
case 'B':
return _subFormatHex(color.getBlue(), count, toAppendTo);
case 'A':
return _subFormatHex(color.getAlpha(), count, toAppendTo);
default:
throw new IllegalArgumentException(_LOG.getMessage(
"ILLEGAL_PATTERN_CHARACTER", ch));
}
}
private StringBuffer _subFormatDecimal(
int value,
int minDigits,
StringBuffer toAppendTo)
{
_prefixZeros(value, 10, minDigits, toAppendTo);
toAppendTo.append(value);
return toAppendTo;
}
private StringBuffer _subFormatHex(
int value,
int minDigits,
StringBuffer toAppendTo)
{
String hexString = Integer.toHexString(value);
int digits = hexString.length();
for (int i=0; i < minDigits - digits; i++)
toAppendTo.append('0');
toAppendTo.append(Integer.toHexString(value).toUpperCase());
return toAppendTo;
}
private StringBuffer _prefixZeros(
int value,
int base,
int minDigits,
StringBuffer toAppendTo)
{
if (value >= 0)
{
int digits = (value > 0)
? (int)Math.ceil(Math.log(value) / Math.log(base))
: 1;
while (minDigits > 0 && digits < minDigits)
{
toAppendTo.append('0');
minDigits--;
}
}
return toAppendTo;
}
private String _pattern;
private static final int _RED_FIELD = 0;
private static final int _GREEN_FIELD = 1;
private static final int _BLUE_FIELD = 2;
private static final int _ALPHA_FIELD = 3;
private static final int _FIELD_COUNT = 4;
private static final TrinidadLogger _LOG = TrinidadLogger.createTrinidadLogger(RGBColorFormat.class);
private static final long serialVersionUID = 1L;
}