ParameterHandlerPtr CompoundParameterHandler::handler( const ParameterPtr child, bool createIfMissing )
{
	HandlerMap::const_iterator it = m_handlers.find( child );
	if( it!=m_handlers.end() )
	{
		return it->second;
	}
	
	ParameterHandlerPtr h = 0;
	if( createIfMissing )
	{
		IECore::ConstBoolDataPtr noHostMapping = child->userData()->member<BoolData>( "noHostMapping" );
		if( !noHostMapping || !noHostMapping->readable() )
		{	
			h = ParameterHandler::create( child );
			if( !h )
			{
				IECore::msg( IECore::Msg::Warning, "Gaffer::CompoundParameterHandler", boost::format(  "Unable to create handler for parameter \"%s\" of type \"%s\"" ) % child->name() % child->typeName() );
			}
		}
	}
	
	m_handlers[child] = h;
	return h;
}
MStatus NumericParameterHandler<T>::doUpdate( IECore::ConstParameterPtr parameter, MPlug &plug ) const
{
	typename IECore::NumericParameter<T>::ConstPtr p = IECore::runTimeCast<const IECore::NumericParameter<T> >( parameter );
	if( !p )
	{
		return MS::kFailure;
	}

	MObject attribute = plug.attribute();
	MFnNumericAttribute fnNAttr( attribute );
	if( !fnNAttr.hasObj( attribute ) )
	{
		return MS::kFailure;
	}
	if( fnNAttr.unitType() != NumericTraits<T>::dataType() )
	{
		return MS::kFailure;
	}

	fnNAttr.setDefault( p->numericDefaultValue() );

	if( p->minValue()!=Imath::limits<T>::min() )
	{
		fnNAttr.setMin( p->minValue() );
	}
	else
	{
		// parameter has no min value
		if( fnNAttr.hasMin() )
		{
			// there is no way of unsetting a minimum value
			// in maya.
			return MS::kFailure;
		}
	}

	if( p->maxValue()!=Imath::limits<T>::max() )
	{
		fnNAttr.setMax( p->maxValue() );
	}
	else
	{
		// parameter has no max value
		if( fnNAttr.hasMax() )
		{
			// there is no way of unsetting a maximum value
			// in maya.
			return MS::kFailure;
		}
	}

	T v;
	MStatus result = plug.getValue( v );
	if( result )
	{
		IECore::ObjectPtr d = new IECore::TypedData<T>( v );
		if( !parameter->valueValid( d.get() ) )
		{
			return MS::kFailure;
		}
	}

	bool keyable = true;
	bool channelBox = true;

	const IECore::ConstCompoundObjectPtr userData = parameter->userData();
	assert( userData );

	const IECore::ConstCompoundObjectPtr maya = userData->member<const IECore::CompoundObject>("maya");
	if (maya)
	{
		const IECore::ConstBoolDataPtr keyableData = maya->member<const IECore::BoolData>("keyable");
		if (keyableData)
		{
			keyable = keyableData->readable();
		}

		const IECore::ConstBoolDataPtr channelBoxData = maya->member<const IECore::BoolData>("channelBox");
		if (channelBoxData)
		{
			channelBox = channelBoxData->readable();
		}
	}

	fnNAttr.setKeyable( keyable );

	// Calling setChannelBox(true) disables keying
	if (!keyable)
	{
		fnNAttr.setChannelBox( channelBox );
	}

	return finishUpdating( parameter, plug );
}