2006-08-07 Sebastien Pouliot <sebastien@ximian.com>
[mono.git] / mcs / class / System.Drawing / System.Drawing / ColorConverter.cs
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 Novell, Inc.  http://www.novell.com
10 //
11
12 //
13 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
14 //
15 // Permission is hereby granted, free of charge, to any person obtaining
16 // a copy of this software and associated documentation files (the
17 // "Software"), to deal in the Software without restriction, including
18 // without limitation the rights to use, copy, modify, merge, publish,
19 // distribute, sublicense, and/or sell copies of the Software, and to
20 // permit persons to whom the Software is furnished to do so, subject to
21 // the following conditions:
22 // 
23 // The above copyright notice and this permission notice shall be
24 // included in all copies or substantial portions of the Software.
25 // 
26 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
27 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
28 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
29 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
30 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
31 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
32 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
33 //
34
35 using System;
36 using System.Collections;
37 using System.ComponentModel;
38 using System.Globalization;
39 using System.Text;
40 using System.ComponentModel.Design.Serialization;
41 using System.Reflection;
42
43 namespace System.Drawing
44 {
45         public class ColorConverter : TypeConverter
46         {
47                 static StandardValuesCollection cached;
48                 static object creatingCached = new object ();
49
50                 public ColorConverter () { }
51
52                 public override bool CanConvertFrom (ITypeDescriptorContext context, Type sourceType)
53                 {
54                         if (sourceType == typeof (string))
55                                 return true;
56
57                         return base.CanConvertFrom (context, sourceType);
58                 }
59
60                 public override bool CanConvertTo (ITypeDescriptorContext context, Type destinationType)
61                 {
62                         if (destinationType == typeof (InstanceDescriptor))
63                                 return true;
64
65                         return base.CanConvertTo (context, destinationType);
66                 }
67
68                 public override object ConvertFrom (ITypeDescriptorContext context,
69                                                     CultureInfo culture,
70                                                     object value)
71                 {
72                         string s = value as string;
73                         if (s == null)
74                                 return base.ConvertFrom (context, culture, value);
75
76                         s = s.Trim ();
77
78                         if (s.Length == 0) {
79                                 return Color.Empty;
80                         }
81
82                         object named = Color.NamedColors [s];
83                         if (named != null)
84                                 return (Color) named;
85
86                         named = Color.SystemColors [s];
87                         if (named != null)
88                                 return (Color) named;
89
90                         String numSeparator = culture.TextInfo.ListSeparator;
91
92                         Int32Converter converter = new Int32Converter ();
93
94                         object result = null;
95
96                         if (s.IndexOf (numSeparator) == -1) {
97                                 if ((s.Length == 8 && (s.StartsWith ("0x") || s.StartsWith ("0X"))) 
98                                         || (s.Length == 7 && s.StartsWith ("#"))) {
99                                         result = Color.FromArgb (-16777216 | (int) converter.
100                                                 ConvertFromString (context, culture, s));
101                                 } 
102                                 else if ((s.Length == 5 && (s.StartsWith ("0x") || s.StartsWith ("0X"))) 
103                                         || (s.Length == 4 && s.StartsWith ("#"))) {
104                                         int i = (int) converter.ConvertFromString (context, culture, s);
105                                         i = ((i & 0xf00) << 12) | ((i & 0xf00) << 8) |
106                                                 ((i & 0xf0) << 8) | ((i & 0xf0) << 4) |
107                                                 ((i & 0xf) << 4) | (i & 0xf);
108                                         result = Color.FromArgb ( -16777216 | i );
109                                 }
110                         }
111
112                         if (result == null) {
113                                 String [] components = s.Split (numSeparator.ToCharArray ());
114
115                                 // MS seems to convert the indivual component to int before
116                                 // checking the number of components
117                                 int[] numComponents = new int[components.Length];
118                                 for (int i = 0; i < numComponents.Length; i++) {
119                                         numComponents[i] = (int) converter.ConvertFrom (context,
120                                                 culture, components[i]);
121                                 }
122
123                                 switch (components.Length) {
124                                         case 1:
125                                                 result = Color.FromArgb (numComponents[0]);
126                                                 break;
127                                         case 3:
128                                                 result = Color.FromArgb (numComponents[0], numComponents[1],
129                                                         numComponents[2]);
130                                                 break;
131                                         case 4:
132                                                 result = Color.FromArgb (numComponents[0], numComponents[1],
133                                                         numComponents[2], numComponents[3]);
134                                                 break;
135                                         default:
136                                                 throw new ArgumentException (s + " is not a valid color value.");
137                                 }
138                         } 
139
140                         if (result != null) {
141                                 Color resultColor = (Color) result;
142
143                                 // Look for a named or system color with those values
144                                 foreach (Color c in Color.NamedColors.Values) {
145                                         if (c == resultColor)
146                                                 return c;
147                                 }
148
149                                 foreach (Color c in Color.SystemColors.Values) {
150                                         if (c == resultColor)
151                                                 return c;
152                                 }
153                         }
154
155                         return result;
156                 }
157
158                 public override object ConvertTo (ITypeDescriptorContext context,
159                                                   CultureInfo culture,
160                                                   object value,
161                                                   Type destinationType)
162                 {
163                         if ((destinationType == typeof (string)) && (value is Color)) {
164                                 Color color = (Color) value;
165
166                                 if (color == Color.Empty) {
167                                         return string.Empty;
168                                 }
169
170                                 if (color.IsKnownColor) {
171                                         return color.Name;
172                                 }
173
174                                 if (color.IsNamedColor)
175                                         return color.Name;
176
177                                 String numSeparator = culture.TextInfo.ListSeparator;
178
179                                 StringBuilder sb = new StringBuilder ();
180                                 if (color.A != 255) {
181                                         sb.Append (color.A);
182                                         sb.Append (numSeparator);
183                                         sb.Append (" ");
184                                 }
185                                 sb.Append (color.R);
186                                 sb.Append (numSeparator);
187                                 sb.Append (" ");
188
189                                 sb.Append (color.G);
190                                 sb.Append (numSeparator);
191                                 sb.Append (" ");
192
193                                 sb.Append (color.B);
194                                 return sb.ToString ();
195                         }
196                         
197                         if (destinationType == typeof (InstanceDescriptor) && value is Color) {
198                                 Color c = (Color)value;
199                                 if (c.IsKnownColor){
200                                         return new InstanceDescriptor (typeof (SystemColors).GetProperty (c.Name), null);
201                                 } else {
202                                         MethodInfo met = typeof(Color).GetMethod ("FromArgb", new Type[] { typeof(int), typeof(int), typeof(int), typeof(int) } );
203                                         return new InstanceDescriptor (met, new object[] {c.A, c.R, c.G, c.B });
204                                 }
205                         }
206
207                         return base.ConvertTo (context, culture, value, destinationType);
208                 }
209
210                 public override StandardValuesCollection GetStandardValues (ITypeDescriptorContext context)
211                 {
212                         if (cached != null)
213                                 return cached;
214
215                         lock (creatingCached)
216                         {
217                                 if (cached != null)
218                                         return cached;
219                         
220                                 ICollection named = (ICollection) Color.NamedColors.Values;
221                                 ICollection system = (ICollection) Color.SystemColors.Values;
222                                 Array colors = Array.CreateInstance (typeof (Color), named.Count + system.Count);
223                                 named.CopyTo (colors, 0);
224                                 system.CopyTo (colors, named.Count);
225                                 Array.Sort (colors, 0, colors.Length, new CompareColors ());
226                                 cached = new StandardValuesCollection (colors);
227                         }
228
229                         return cached;
230                 }
231
232                 public override bool GetStandardValuesSupported (ITypeDescriptorContext context)
233                 {
234                         return true;
235                 }
236
237                 class CompareColors : IComparer
238                 {
239                         public int Compare (object x, object y)
240                         {
241                                 return String.Compare (((Color) x).Name, ((Color) y).Name);
242                         }
243                 }
244         }
245 }