2010-04-07 Jb Evain <jbevain@novell.com>
[mcs.git] / class / System.Drawing / System.Drawing / ColorConverter.cs
blob7cd02aeae199a75c7159196cbe6fb9c4594c8e60
1 //
2 // System.Drawing.ColorConverter
3 //
4 // Authors:
5 // Gonzalo Paniagua Javier (gonzalo@ximian.com)
6 // Ravindra (rkumar@novell.com)
7 //
8 // Copyright (C) 2002 Ximian, Inc. http://www.ximian.com
9 // Copyright (C) 2004,2006,2008 Novell, Inc (http://www.novell.com)
11 // Permission is hereby granted, free of charge, to any person obtaining
12 // a copy of this software and associated documentation files (the
13 // "Software"), to deal in the Software without restriction, including
14 // without limitation the rights to use, copy, modify, merge, publish,
15 // distribute, sublicense, and/or sell copies of the Software, and to
16 // permit persons to whom the Software is furnished to do so, subject to
17 // the following conditions:
18 //
19 // The above copyright notice and this permission notice shall be
20 // included in all copies or substantial portions of the Software.
21 //
22 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
26 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
27 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31 using System.Collections;
32 using System.ComponentModel;
33 using System.Globalization;
34 using System.Text;
35 using System.ComponentModel.Design.Serialization;
36 using System.Reflection;
38 namespace System.Drawing
40 public class ColorConverter : TypeConverter
42 static StandardValuesCollection cached;
43 static object creatingCached = new object ();
45 public ColorConverter () { }
47 public override bool CanConvertFrom (ITypeDescriptorContext context, Type sourceType)
49 if (sourceType == typeof (string))
50 return true;
52 return base.CanConvertFrom (context, sourceType);
55 public override bool CanConvertTo (ITypeDescriptorContext context, Type destinationType)
57 if (destinationType == typeof (InstanceDescriptor))
58 return true;
60 return base.CanConvertTo (context, destinationType);
63 internal static Color StaticConvertFromString (ITypeDescriptorContext context, string s, CultureInfo culture)
65 if (culture == null)
66 culture = CultureInfo.InvariantCulture;
68 s = s.Trim ();
70 if (s.Length == 0)
71 return Color.Empty;
73 // Try to process both NamedColor and SystemColors from the KnownColor enumeration
74 if (Char.IsLetter (s [0])) {
75 KnownColor kc;
76 try {
77 kc = (KnownColor) Enum.Parse (typeof (KnownColor), s, true);
79 catch (Exception e) {
80 // whatever happens MS throws an basic Exception
81 string msg = Locale.GetText ("Invalid color name '{0}'.", s);
82 throw new Exception (msg, new FormatException (msg, e));
84 return KnownColors.FromKnownColor (kc);
87 String numSeparator = culture.TextInfo.ListSeparator;
88 Color result = Color.Empty;
90 if (s.IndexOf (numSeparator) == -1) {
91 bool sharp = (s[0] == '#');
92 int start = sharp ? 1 : 0;
93 bool hex = false;
94 // deal with #hex, 0xhex and #0xhex
95 if ((s.Length > start + 1) && (s[start] == '0')) {
96 hex = ((s[start + 1] == 'x') || (s[start + 1] == 'X'));
97 if (hex)
98 start += 2;
101 if (sharp || hex) {
102 s = s.Substring (start);
103 int argb;
104 try {
105 argb = Int32.Parse (s, NumberStyles.HexNumber);
107 catch (Exception e) {
108 // whatever happens MS throws an basic Exception
109 string msg = Locale.GetText ("Invalid Int32 value '{0}'.", s);
110 throw new Exception (msg, e);
113 // note that the default alpha value for a 6 hex digit (i.e. when none are present) is
114 // 0xFF while shorter string defaults to 0xFF - unless both # an 0x are specified
115 if ((s.Length < 6) || ((s.Length == 6) && sharp && hex))
116 argb &= 0x00FFFFFF;
117 else if ((argb >> 24) == 0)
118 argb |= unchecked((int)0xFF000000);
119 result = Color.FromArgb (argb);
123 if (result.IsEmpty) {
124 Int32Converter converter = new Int32Converter ();
125 String [] components = s.Split (numSeparator.ToCharArray ());
127 // MS seems to convert the indivual component to int before
128 // checking the number of components
129 int[] numComponents = new int[components.Length];
130 for (int i = 0; i < numComponents.Length; i++) {
131 numComponents[i] = (int) converter.ConvertFrom (context,
132 culture, components[i]);
135 switch (components.Length) {
136 case 1:
137 result = Color.FromArgb (numComponents[0]);
138 break;
139 case 3:
140 result = Color.FromArgb (numComponents[0], numComponents[1],
141 numComponents[2]);
142 break;
143 case 4:
144 result = Color.FromArgb (numComponents[0], numComponents[1],
145 numComponents[2], numComponents[3]);
146 break;
147 default:
148 throw new ArgumentException (s + " is not a valid color value.");
152 if (!result.IsEmpty) {
153 // Look for a named or system color with those values
154 Color known = KnownColors.FindColorMatch (result);
155 if (!known.IsEmpty)
156 return known;
159 return result;
163 public override object ConvertFrom (ITypeDescriptorContext context,
164 CultureInfo culture,
165 object value)
167 string s = value as string;
168 if (s == null)
169 return base.ConvertFrom (context, culture, value);
171 return StaticConvertFromString (context, s, culture);
174 public override object ConvertTo (ITypeDescriptorContext context,
175 CultureInfo culture,
176 object value,
177 Type destinationType)
179 if (value is Color) {
180 Color color = (Color) value;
181 if (destinationType == typeof (string)) {
182 if (color == Color.Empty)
183 return string.Empty;
185 if (color.IsKnownColor || color.IsNamedColor)
186 return color.Name;
188 String numSeparator = culture.TextInfo.ListSeparator;
190 StringBuilder sb = new StringBuilder ();
191 if (color.A != 255) {
192 sb.Append (color.A);
193 sb.Append (numSeparator);
194 sb.Append (" ");
196 sb.Append (color.R);
197 sb.Append (numSeparator);
198 sb.Append (" ");
200 sb.Append (color.G);
201 sb.Append (numSeparator);
202 sb.Append (" ");
204 sb.Append (color.B);
205 return sb.ToString ();
206 } else if (destinationType == typeof (InstanceDescriptor)) {
207 if (color.IsEmpty) {
208 return new InstanceDescriptor (typeof (Color).GetField ("Empty"), null);
209 } else if (color.IsSystemColor) {
210 return new InstanceDescriptor (typeof (SystemColors).GetProperty (color.Name), null);
211 } else if (color.IsKnownColor){
212 return new InstanceDescriptor (typeof (Color).GetProperty (color.Name), null);
213 } else {
214 MethodInfo met = typeof(Color).GetMethod ("FromArgb", new Type[] { typeof(int), typeof(int), typeof(int), typeof(int) } );
215 return new InstanceDescriptor (met, new object[] {color.A, color.R, color.G, color.B });
220 return base.ConvertTo (context, culture, value, destinationType);
223 public override StandardValuesCollection GetStandardValues (ITypeDescriptorContext context)
225 lock (creatingCached) {
226 if (cached != null)
227 return cached;
228 #if TARGET_JVM
229 Color [] colors = new Color [KnownColors.Values.Length - 1];
230 Array.Copy (KnownColors.Values, 1, colors, 0, colors.Length);
231 #else
232 Array colors = Array.CreateInstance (typeof (Color), KnownColors.ArgbValues.Length - 1);
233 for (int i=1; i < KnownColors.ArgbValues.Length; i++) {
234 colors.SetValue (KnownColors.FromKnownColor ((KnownColor)i), i - 1);
236 #endif
238 Array.Sort (colors, 0, colors.Length, new CompareColors ());
239 cached = new StandardValuesCollection (colors);
242 return cached;
245 public override bool GetStandardValuesSupported (ITypeDescriptorContext context)
247 return true;
250 sealed class CompareColors : IComparer {
252 public int Compare (object x, object y)
254 return String.Compare (((Color) x).Name, ((Color) y).Name);