コード例 #1
0
ファイル: dependencyproperty.cpp プロジェクト: lewing/moon
//
// Everything inside of a ( ) resolves to a DependencyProperty, if there is a
// '.' after the property, we get the object, and continue resolving from there
// if there is a [n] after the property, we convert the property to a collection
// and grab the nth item.
//
// Dependency properties can be specified as (PropertyName) of the current object
// or they can be specified as (DependencyObject.PropertyName).
//
// Returns NULL on any error
//
DependencyProperty *
resolve_property_path (DependencyObject **o, PropertyPath *propertypath, GHashTable *promoted_values)
{
	g_return_val_if_fail (o != NULL, NULL);
	g_return_val_if_fail (propertypath != NULL, NULL);
	g_return_val_if_fail (propertypath->path != NULL || propertypath->property != NULL, NULL);
	
	if (propertypath->property)
		return propertypath->property;

	const char *path = propertypath->path;
	if (propertypath->expanded_path)
		path = propertypath->expanded_path;

	const char *inend = path + strlen (path);
	register const char *inptr = path;
	const char *start, *prop = path;
	bool expression_found = false;
	DependencyProperty *res = NULL;
	DependencyObject *lu = *o;
	Collection *collection;
	char *p, *name = NULL;
	Value *value = NULL;
	Type *type = NULL;
	int index;
	bool paren_open = false;
	bool tick_open = false;
	bool cloned = false;

	while (inptr < inend) {
		switch (*inptr++) {
		case '(':
			paren_open = true;
			break;
		case ')':
			paren_open = false;
			break;
		case '\'':
			// Ticks are only legal in expanded paths, so we should just fail here
			if (!propertypath->expanded_path) {
				g_warning ("The ' character is not legal in property paths.");
				break;
			}

			tick_open = !tick_open;
			break;
		case '.':
			if (tick_open)
				continue;

			// resolve the dependency property
			if (res) {
				DependencyObject *new_lu;

				// make sure that we are getting what we expect
				if (!(value = lu->GetValue (res)))
					goto error;

				if (!(new_lu = value->AsDependencyObject ()))
					goto error;

				if (!cloned && !g_hash_table_lookup (promoted_values, value) && !value->Is (lu->GetDeployment (), Type::UIELEMENT)) {
					// we need to clone the value here so that we deep copy any
					// DO subclasses (such as brushes, etc) that we're promoting
					// from a shared space (Styles, default values)
					Value *cloned_value = Value::Clone (value);
					
					DependencyObject *cloned_do = cloned_value->AsDependencyObject();
					if (cloned_do != NULL) {
						new_lu = cloned_do;
						lu->SetValue (res, cloned_value);
						delete cloned_value;
						
						cloned_value = lu->GetValue (res);
						g_hash_table_insert (promoted_values, cloned_value, cloned_value);
					}
				}

				lu = new_lu;
			}
			
			expression_found = false;
			prop = inptr;
			break;
		case '[':
			// Need to be a little more loving
			if (*inptr == '\0')
				break;
			
			index = strtol (inptr, &p, 10);
			if (*p != ']' || *(p + 1) != '.')
				break;
			
			inptr = p + 2;
			prop = inptr;

			if (expression_found) {
				expression_found = false;
				if (!(value = lu->GetValue (res)))
					goto error;
			}
			
			if (value == NULL)
				goto error;
			
			if (!(collection = value->AsCollection ()))
				goto error;

			if (!(value = collection->GetValueAt (index)))
				goto error;
			
			if (!(lu = value->AsDependencyObject ()))
				goto error;
			
			break;
		
		default:
			bool explicit_type = false;
			expression_found = true;
			start = inptr - 1;

			while (inptr < inend && (*inptr != '.' || tick_open) && (!paren_open || *inptr != ')') && *inptr != '[') {
				if (*inptr == '\'') {
					tick_open = !tick_open;
					if (!tick_open) {
						inptr++;
						break;
					}
				}
				inptr++;
			}

			if (inptr == start)
				goto error;

			if (*inptr == '.') {
				// we found a type name, now we need to find the property name
				if ((inptr - start) == 11 && !g_ascii_strncasecmp (start, "TextElement", 11)) {
					// Some Beta versions of Blend had a bug where they would save the TextBlock
					// properties as TextElement instead. Since Silverlight 1.0 works around this
					// bug, we should too. Fixes http://silverlight.timovil.com and
					// http://election.msn.com/podium08.aspx.
					type = Type::Find (lu->GetDeployment (), "TextBlock");
					explicit_type = true;
				} else {
					const char *s = inptr;
					if (*(inptr -1) == '\'' && !tick_open) {
						s = inptr - 1;
					}
					name = g_strndup (start, s - start);
					type = lookup_type (lu, name);
					explicit_type = true;
					if (!type)
						type = lu->GetType ();
					g_free (name);
				}
				
				inptr++;
				start = inptr;
				while (inptr < inend && (!paren_open || *inptr != ')') && (*inptr != '.' || tick_open)) {
					if (*inptr == '\'') {
						tick_open = !tick_open;
						if (!tick_open) {
							inptr++;
							break;
						}
					}
					inptr++;
				}
				
				if (inptr == start)
					goto error;
			} else {
				type = lu->GetType ();
				explicit_type = false;
			}
			
			if ((*inptr != ')' && paren_open) || !type)
				goto error;

			name = g_strndup (start, inptr - start);
			if (!(res = DependencyProperty::GetDependencyProperty (type, name)) && lu)
				res = DependencyProperty::GetDependencyProperty (lu->GetType (), name);

			if (!res) {
				g_free (name);
				goto error;
			}

			if (!res->IsAttached () && !lu->Is (type->GetKind ())) {
				// We try to be gracefull here and do something smart...
				if (!(res = DependencyProperty::GetDependencyProperty (lu->GetType (), name))) {
					g_free (name);
					goto error;
				}
			}
			
			if (res->IsAttached () && explicit_type && !paren_open)
				goto error;
			
			g_free (name);
			break;
		}
	}
	
	*o = lu;
	return res;
	
 error:
	*o = NULL;	
	return NULL;
}
コード例 #2
0
bool
ResourceDictionary::AddWithError (const char* key, Value *value, MoonError *error)
{
	if (!key) {
		MoonError::FillIn (error, MoonError::ARGUMENT_NULL, "key was null");
		return false;
	}

	Value *v = NULL;
	gpointer orig_key;

	gboolean exists = g_hash_table_lookup_extended (hash, key,
							&orig_key, (gpointer*)&v);

	if (exists) {
		MoonError::FillIn (error, MoonError::ARGUMENT, "An item with the same key has already been added");
		return false;
	}

	v = new Value (*value);
	
	from_resource_dictionary_api = true;
	bool result = Collection::AddWithError (v, error) != -1;
	from_resource_dictionary_api = false;
	if (result) {
		g_hash_table_insert (hash, g_strdup (key), v);

		v->Weaken (GetDeployment ());

		EmitChanged (CollectionChangedActionAdd, v, NULL, key);

		if (!strncmp (key, INTERNAL_TYPE_KEY_MAGIC_COOKIE, sizeof (INTERNAL_TYPE_KEY_MAGIC_COOKIE) - 1)
		    && v->Is (GetDeployment (), Type::STYLE)) {
			DependencyObject *p = GetParent();
			if (!p)
				return result;

			Style *style = v->AsStyle();

			if (p->Is (Type::APPLICATION)) {
				// we modified the application's resources, so we need to traverse all layers

				CollectionIterator *iterator = p->GetDeployment()->GetSurface()->GetLayers()->GetIterator();
				while (iterator->Next (NULL)) {
					Value *v = iterator->GetCurrent(NULL);
					FrameworkElement *fwe = v->AsFrameworkElement();

					fwe->StyleResourceChanged (key, style);
				}

				delete iterator;
			}
			else if (p->Is (Type::FRAMEWORKELEMENT)) {
				// just traverse down from this frameworkelement
				((FrameworkElement*)p)->StyleResourceChanged (key, style);
			}
		}

	} else {
		delete v;
	}
	return result;
}