New test.
[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,2006 Novell, Inc (http://www.novell.com)
10 //
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.
29 //
30
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;
37
38 namespace System.Drawing
39 {
40         public class ColorConverter : TypeConverter
41         {
42                 static StandardValuesCollection cached;
43                 static object creatingCached = new object ();
44
45                 public ColorConverter () { }
46
47                 public override bool CanConvertFrom (ITypeDescriptorContext context, Type sourceType)
48                 {
49                         if (sourceType == typeof (string))
50                                 return true;
51
52                         return base.CanConvertFrom (context, sourceType);
53                 }
54
55                 public override bool CanConvertTo (ITypeDescriptorContext context, Type destinationType)
56                 {
57                         if (destinationType == typeof (InstanceDescriptor))
58                                 return true;
59
60                         return base.CanConvertTo (context, destinationType);
61                 }
62
63                 public override object ConvertFrom (ITypeDescriptorContext context,
64                                                     CultureInfo culture,
65                                                     object value)
66                 {
67                         string s = value as string;
68                         if (s == null)
69                                 return base.ConvertFrom (context, culture, value);
70
71                         s = s.Trim ();
72
73                         if (s.Length == 0) {
74                                 return Color.Empty;
75                         }
76
77                         object named = Color.NamedColors [s];
78                         if (named != null)
79                                 return (Color) named;
80
81                         named = Color.SystemColors [s];
82                         if (named != null)
83                                 return (Color) named;
84
85                         String numSeparator = culture.TextInfo.ListSeparator;
86
87                         Int32Converter converter = new Int32Converter ();
88
89                         object result = null;
90
91                         if (s.IndexOf (numSeparator) == -1) {
92                                 if ((s.Length == 8 && (s.StartsWith ("0x") || s.StartsWith ("0X"))) 
93                                         || (s.Length == 7 && s.StartsWith ("#"))) {
94                                         result = Color.FromArgb (-16777216 | (int) converter.
95                                                 ConvertFromString (context, culture, s));
96                                 } 
97                                 else if ((s.Length == 5 && (s.StartsWith ("0x") || s.StartsWith ("0X"))) 
98                                         || (s.Length == 4 && s.StartsWith ("#"))) {
99                                         int i = (int) converter.ConvertFromString (context, culture, s);
100                                         i = ((i & 0xf00) << 12) | ((i & 0xf00) << 8) |
101                                                 ((i & 0xf0) << 8) | ((i & 0xf0) << 4) |
102                                                 ((i & 0xf) << 4) | (i & 0xf);
103                                         result = Color.FromArgb ( -16777216 | i );
104                                 } else if (s.StartsWith ("#") && (s.Length > 9) && !s.StartsWith ("#0x")) {
105                                         throw new Exception (Locale.GetText ("{0} isn't a valid color (integer too large).", s));
106                                 }
107                         }
108
109                         if (result == null) {
110                                 String [] components = s.Split (numSeparator.ToCharArray ());
111
112                                 // MS seems to convert the indivual component to int before
113                                 // checking the number of components
114                                 int[] numComponents = new int[components.Length];
115                                 for (int i = 0; i < numComponents.Length; i++) {
116                                         numComponents[i] = (int) converter.ConvertFrom (context,
117                                                 culture, components[i]);
118                                 }
119
120                                 switch (components.Length) {
121                                         case 1:
122                                                 result = Color.FromArgb (numComponents[0]);
123                                                 break;
124                                         case 3:
125                                                 result = Color.FromArgb (numComponents[0], numComponents[1],
126                                                         numComponents[2]);
127                                                 break;
128                                         case 4:
129                                                 result = Color.FromArgb (numComponents[0], numComponents[1],
130                                                         numComponents[2], numComponents[3]);
131                                                 break;
132                                         default:
133                                                 throw new ArgumentException (s + " is not a valid color value.");
134                                 }
135                         } 
136
137                         if (result != null) {
138                                 Color resultColor = (Color) result;
139
140                                 // Look for a named or system color with those values
141                                 foreach (Color c in Color.NamedColors.Values) {
142                                         if (c == resultColor)
143                                                 return c;
144                                 }
145
146                                 foreach (Color c in Color.SystemColors.Values) {
147                                         if (c == resultColor)
148                                                 return c;
149                                 }
150                         }
151
152                         return result;
153                 }
154
155                 public override object ConvertTo (ITypeDescriptorContext context,
156                                                   CultureInfo culture,
157                                                   object value,
158                                                   Type destinationType)
159                 {
160                         if ((destinationType == typeof (string)) && (value is Color)) {
161                                 Color color = (Color) value;
162
163                                 if (color == Color.Empty) {
164                                         return string.Empty;
165                                 }
166
167                                 if (color.IsKnownColor) {
168                                         return color.Name;
169                                 }
170
171                                 if (color.IsNamedColor)
172                                         return color.Name;
173
174                                 String numSeparator = culture.TextInfo.ListSeparator;
175
176                                 StringBuilder sb = new StringBuilder ();
177                                 if (color.A != 255) {
178                                         sb.Append (color.A);
179                                         sb.Append (numSeparator);
180                                         sb.Append (" ");
181                                 }
182                                 sb.Append (color.R);
183                                 sb.Append (numSeparator);
184                                 sb.Append (" ");
185
186                                 sb.Append (color.G);
187                                 sb.Append (numSeparator);
188                                 sb.Append (" ");
189
190                                 sb.Append (color.B);
191                                 return sb.ToString ();
192                         }
193                         
194                         if (destinationType == typeof (InstanceDescriptor) && value is Color) {
195                                 Color c = (Color)value;
196                                 if (c.IsKnownColor){
197                                         return new InstanceDescriptor (typeof (SystemColors).GetProperty (c.Name), null);
198                                 } else {
199                                         MethodInfo met = typeof(Color).GetMethod ("FromArgb", new Type[] { typeof(int), typeof(int), typeof(int), typeof(int) } );
200                                         return new InstanceDescriptor (met, new object[] {c.A, c.R, c.G, c.B });
201                                 }
202                         }
203
204                         return base.ConvertTo (context, culture, value, destinationType);
205                 }
206
207                 public override StandardValuesCollection GetStandardValues (ITypeDescriptorContext context)
208                 {
209                         lock (creatingCached) {
210                                 if (cached != null)
211                                         return cached;
212                         
213                                 ICollection named = (ICollection) Color.NamedColors.Values;
214                                 ICollection system = (ICollection) Color.SystemColors.Values;
215                                 Array colors = Array.CreateInstance (typeof (Color), named.Count + system.Count);
216                                 named.CopyTo (colors, 0);
217                                 system.CopyTo (colors, named.Count);
218                                 Array.Sort (colors, 0, colors.Length, new CompareColors ());
219                                 cached = new StandardValuesCollection (colors);
220                         }
221
222                         return cached;
223                 }
224
225                 public override bool GetStandardValuesSupported (ITypeDescriptorContext context)
226                 {
227                         return true;
228                 }
229
230                 class CompareColors : IComparer
231                 {
232                         public int Compare (object x, object y)
233                         {
234                                 return String.Compare (((Color) x).Name, ((Color) y).Name);
235                         }
236                 }
237         }
238 }