2009-10-20 Chris Toshok <toshok@ximian.com>
[moon.git] / src / validators.cpp
blob694b4f2a15fdcc7626098800ccca65d8d3481c1e
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3 * validators.cpp:
5 * Contact:
6 * Moonlight List (moonlight-list@lists.ximian.com)
8 * Copyright 2008 Novell, Inc. (http://www.novell.com)
10 * See the LICENSE file included with the distribution for details.
13 #include <config.h>
15 #include <math.h>
17 #include "validators.h"
18 #include "thickness.h"
19 #include "cornerradius.h"
20 #include "style.h"
21 #include "frameworkelement.h"
22 #include "animation.h"
23 #include "propertypath.h"
24 #include "namescope.h"
26 bool
27 Validators::StyleValidator (DependencyObject* instance, DependencyProperty *property, Value *value, MoonError *error) {
28 Value *current = instance->GetValue (property);
29 if (current && !current->GetIsNull ()) {
30 MoonError::FillIn (error, MoonError::EXCEPTION, 1001,
31 g_strdup_printf ("Property 'Style' cannot be assigned to more than once\n"));
32 return false;
34 return true;
37 bool
38 Validators::AudioStreamIndexValidator (DependencyObject* instance, DependencyProperty *property, Value *value, MoonError *error)
40 // A value of -1 is converted to null. Any other value is left as-is
41 if (value && value->AsInt32() == -1)
42 value->SetIsNull (true);
44 return true;
47 bool
48 Validators::BalanceValidator (DependencyObject* instance, DependencyProperty *property, Value *value, MoonError *error)
50 if (value) {
51 if (value->AsDouble () > 1.0) {
52 *value = Value(1.0);
53 } else if (value->AsDouble () < -1.0) {
54 *value = Value(-1.0);
58 return true;
61 bool
62 Validators::VolumeValidator (DependencyObject* instance, DependencyProperty *property, Value *value, MoonError *error)
64 if (value) {
65 if (value->AsDouble () > 1.0) {
66 *value = Value (1.0);
67 } else if (value->AsDouble () < 0.0) {
68 *value = Value (0.0);
72 return true;
75 bool
76 Validators::CursorValidator (DependencyObject* instance, DependencyProperty *property, Value *value, MoonError *error)
78 // If the value is null, it means the default cursor has been set.
79 if (value->GetIsNull ())
80 *value = Value ((int) MouseCursorDefault);
82 return true;
85 bool
86 Validators::default_validator (DependencyObject* instance, DependencyProperty *property, Value *value, MoonError *error)
88 return true;
91 bool
92 Validators::PositiveIntValidator (DependencyObject* instance, DependencyProperty *property, Value *value, MoonError *error)
94 if (value->AsInt32() < 0) {
95 MoonError::FillIn (error, MoonError::ARGUMENT, 1001, "Value must be greater than or equal to zero");
96 return false;
98 return true;
101 bool
102 Validators::IntGreaterThanZeroValidator (DependencyObject* instance, DependencyProperty *property, Value *value, MoonError *error)
104 if (value->AsInt32() < 1) {
105 MoonError::FillIn (error, MoonError::ARGUMENT, 1001, "Value must be greater than zero");
106 return false;
108 return true;
111 bool
112 Validators::IsInputMethodEnabledValidator (DependencyObject* instance, DependencyProperty *property, Value *value, MoonError *error)
114 if (!instance->Is (Type::TEXTBOX)) {
115 MoonError::FillIn (error, MoonError::ARGUMENT, 1001, "Target object must be a TextBox");
116 return false;
118 return true;
121 bool
122 Validators::DoubleGreaterThanZeroValidator (DependencyObject* instance, DependencyProperty *property, Value *value, MoonError *error)
124 if (value->AsDouble () <= 0) {
125 MoonError::FillIn (error, MoonError::ARGUMENT, 1001, "Value must be greater than zero");
126 return false;
128 return true;
131 bool
132 Validators::NonNullValidator (DependencyObject* instance, DependencyProperty *property, Value *value, MoonError *error)
134 if (!value || value->GetIsNull ()) {
135 MoonError::FillIn (error, MoonError::ARGUMENT, 1001, "Value cannot be null");
136 return false;
139 return true;
142 bool
143 Validators::NotNullOrEmptyValidator (DependencyObject* instance, DependencyProperty *property, Value *value, MoonError *error)
145 if (!value || value->GetIsNull () || strlen (value->AsString ()) == 0) {
146 MoonError::FillIn (error, MoonError::EXCEPTION, 1001, "Value cannot be null");
147 return false;
150 return true;
153 bool
154 Validators::MediaAttributeCollectionValidator (DependencyObject* instance, DependencyProperty *property, Value *value, MoonError *error)
156 if (!value || value->GetIsNull ()) {
157 MoonError::FillIn (error, MoonError::EXCEPTION, 1001, "Value cannot be null");
158 return false;
160 return true;
163 bool
164 Validators::TemplateValidator (DependencyObject* instance, DependencyProperty *property, Value *value, MoonError *error)
166 #if false
167 // this causes DRT #438 to throw an exception and subsequently
168 // timeout.
169 if (!value || value->GetIsNull ()) {
170 MoonError::FillIn (error, MoonError::EXCEPTION, 1001, "Value cannot be null");
171 return false;
173 #endif
174 if (instance->Is(Type::USERCONTROL)) {
175 MoonError::FillIn (error, MoonError::INVALID_OPERATION, 1001, "Cannot set the template property on a UserControl");
176 return false;
178 return true;
181 bool
182 Validators::NameValidator (DependencyObject* instance, DependencyProperty *property, Value *value, MoonError *error)
184 NameScope *scope = instance->FindNameScope ();
185 if (scope && value) {
186 DependencyObject *o = scope->FindName (value->AsString ());
187 if (o && o != instance) {
188 MoonError::FillIn (error, MoonError::ARGUMENT, 2028,
189 g_strdup_printf ("The name already exists in the tree: %s (%p %p).",
190 value->AsString (), o, instance));
191 return false;
194 // TODO: Name validation
195 // This doesn't happen in 1.0 or 2.0b according to my tests, but according to the 2.0 docs
196 // names need to start with a '_' or letter. They can't start with a _. Also characters
197 // should be limited to a-z A-Z 0-9 and _. Once a newer beta actually enforces this
198 // I'll implement the validation method.
199 return true;
202 bool RangeCheck (double d)
204 bool b = (d > -(1E300)) && (d < (1E300));
205 return b;
208 bool
209 Validators::BorderThicknessValidator (DependencyObject* instance, DependencyProperty *property, Value *value, MoonError *error)
211 Thickness t = *value->AsThickness ();
213 if (!RangeCheck (t.left) || !RangeCheck (t.right) || !RangeCheck (t.top) || !RangeCheck (t.bottom)){
214 MoonError::FillIn (error, MoonError::EXCEPTION, 1001, "Value is out of range");
215 return false;
218 if (t.left < 0 || t.right < 0 || t.top < 0 || t.bottom < 0){
219 MoonError::FillIn (error, MoonError::ARGUMENT, 1001, "Value is out of range");
220 return false;
222 return true;
225 bool
226 Validators::CornerRadiusValidator (DependencyObject* instance, DependencyProperty *property, Value *value, MoonError *error)
228 CornerRadius t = *value->AsCornerRadius ();
230 if (!RangeCheck (t.topLeft) || !RangeCheck (t.topRight) || !RangeCheck (t.bottomLeft) || !RangeCheck (t.bottomRight)){
231 MoonError::FillIn (error, MoonError::EXCEPTION, 1001, "Value is out of range");
232 return false;
235 if (t.topLeft < 0 || t.topRight < 0 || t.bottomLeft < 0 || t.bottomRight < 0){
236 MoonError::FillIn (error, MoonError::ARGUMENT, 1001, "Value is out of range");
237 return false;
239 return true;
242 bool
243 Validators::BufferingTimeValidator (DependencyObject* instance, DependencyProperty *property, Value *value, MoonError *error)
245 if (value->AsTimeSpan () > 21427200000000000LL) {
246 MoonError::FillIn (error, MoonError::EXCEPTION, 1001, "Value is out of range");
247 return false;
250 return true;
253 bool
254 Validators::IsTimelineValidator (DependencyObject* instance, DependencyProperty *property, Value *value, MoonError *error)
256 if (!instance->Is (Type::TIMELINE)) {
257 MoonError::FillIn (error, MoonError::EXCEPTION, 1001, "Instance is not a Timeline");
258 return false;
261 return true;
264 bool
265 Validators::StoryboardTargetPropertyValidator (DependencyObject* instance, DependencyProperty *property, Value *value, MoonError *error)
267 if (!IsTimelineValidator (instance, property, value, error))
268 return false;
270 PropertyPath *existing = Storyboard::GetTargetProperty (instance);
272 if (existing && existing->property != NULL) {
273 // it was initialized using a DP, we only allow it to be overriden with another DP.
274 PropertyPath *new_path = value->AsPropertyPath();
275 if (new_path->property == NULL)
276 return false;
279 return true;
282 bool
283 Validators::IsSetterSealedValidator (DependencyObject* instance, DependencyProperty *property, Value *value, MoonError *error)
285 if (instance->Is (Type::SETTERBASE)) {
286 if (((SetterBase*) instance)->GetIsSealed ()) {
287 MoonError::FillIn (error, MoonError::UNAUTHORIZED_ACCESS, "Cannot modify a setter after it is used");
288 return false;
292 return true;
296 bool
297 Validators::ContentControlContentValidator (DependencyObject* instance, DependencyProperty *property, Value *value, MoonError *error)
299 if (value->Is (Type::FRAMEWORKELEMENT)) {
300 FrameworkElement *fwe = value->AsFrameworkElement();
302 if (fwe->GetLogicalParent () && fwe->GetLogicalParent ()->Is (Type::PANEL)) {
303 MoonError::FillIn (error, MoonError::ARGUMENT, "Content is already a child of another element");
304 return false;
308 return true;
311 bool
312 Validators::CrossDomainValidator (DependencyObject* instance, DependencyProperty *property, Value *value, MoonError *error)
314 if (instance->GetValueNoDefault (property)) {
315 MoonError::FillIn (error, MoonError::ARGUMENT, 1001,
316 g_strdup_printf ("Property 'ExternalCallersFromCrossDomain' cannot be changed.\n"));
317 return false;
319 return true;
322 bool
323 Validators::FloatValidator (DependencyObject *instance, DependencyProperty *property, Value *value, MoonError *error)
325 double d = value->AsDouble ();
327 switch (fpclassify (d)) {
328 case FP_SUBNORMAL:
329 case FP_INFINITE:
330 case FP_NAN:
331 MoonError::FillIn (error, MoonError::EXCEPTION, 1001, "Value is out of range");
332 return false;
333 default:
334 if ((float) d < -HUGE || (float) d > HUGE) {
335 MoonError::FillIn (error, MoonError::EXCEPTION, 1001, "Value is out of range");
336 return false;
340 return true;