void Composite::Visit(void* instance, Visitor& visitor) const { if (!instance) { return; } DynArray< Field >::ConstIterator itr = m_Fields.Begin(); DynArray< Field >::ConstIterator end = m_Fields.End(); for ( ; itr != end; ++itr ) { const Field* field = &*itr; if ( !visitor.VisitField( instance, field ) ) { continue; } DataPtr data = field->CreateData(); data->ConnectField( instance, field ); data->Accept( visitor ); data->Disconnect(); } }
DataPtr Field::ShouldSerialize( void* instance ) const { // never write discard fields if ( m_Flags & FieldFlags::Discard ) { return NULL; } ObjectPtr object = Registry::GetInstance()->CreateInstance( m_DataClass ); DataPtr data = ThrowCast< Data >( object ); data->ConnectField( instance, this ); // always write force fields if ( m_Flags & FieldFlags::Force ) { return data; } // check for empty/null/invalid state if ( !data->ShouldSerialize() ) { return NULL; } // don't write field at the default value DataPtr defaultData = CreateDefaultData(); if ( defaultData.ReferencesObject() && defaultData->Equals(data) ) { return NULL; } return data; }
void Composite::Copy( void* source, void* destination ) const { if ( source != destination ) { #pragma TODO("This should be inside a virtual function (like CopyTo) instead of a type check conditional") if ( IsType( GetClass<Data>() ) ) { Data* src = static_cast<Data*>(source); Data* dest = static_cast<Data*>(destination); dest->Set( src ); } else { DynArray< Field >::ConstIterator itr = m_Fields.Begin(); DynArray< Field >::ConstIterator end = m_Fields.End(); for ( ; itr != end; ++itr ) { const Field* field = &*itr; // create data objects DataPtr lhs = field->CreateData(); DataPtr rhs = field->CreateData(); // connnect lhs->ConnectField(destination, field); rhs->ConnectField(source, field); // for normal data types, run overloaded assignement operator via data's vtable // for reference container types, this deep copies containers (which is bad for // non-cloneable (FieldFlags::Share) reference containers) bool result = lhs->Set(rhs, field->m_Flags & FieldFlags::Share ? DataFlags::Shallow : 0); HELIUM_ASSERT(result); // disconnect lhs->Disconnect(); rhs->Disconnect(); } } } }
bool Composite::Equals(void* a, void* b) const { if (a == b) { return true; } if (!a || !b) { return false; } DynArray< Field >::ConstIterator itr = m_Fields.Begin(); DynArray< Field >::ConstIterator end = m_Fields.End(); for ( ; itr != end; ++itr ) { const Field* field = &*itr; // create data objects DataPtr aData = field->CreateData(); DataPtr bData = field->CreateData(); // connnect aData->ConnectField(a, field); bData->ConnectField(b, field); bool equality = aData->Equals( bData ); // disconnect aData->Disconnect(); bData->Disconnect(); if ( !equality ) { return false; } } return true; }
DataPtr Field::CreateData(void* instance) const { DataPtr data = CreateData(); if ( data.ReferencesObject() ) { if ( instance ) { data->ConnectField( instance, this ); } } return data; }
void ReflectValueInterpreter::InterpretField(const Field* field, const std::vector<Reflect::Object*>& instances, Container* parent) { if (field->m_Flags & FieldFlags::Hide) { return; } // // Create the ui we are generating // ContainerPtr container = CreateControl<Container>(); bool readOnly = ( field->m_Flags & FieldFlags::ReadOnly ) == FieldFlags::ReadOnly; // // Parse // tstring fieldUI; field->GetProperty( TXT( "UIScript" ), fieldUI ); bool result = Script::Parse(fieldUI, this, parent->GetCanvas(), container, field->m_Flags); if (!result) { if ( field->m_DataClass == Reflect::GetClass<EnumerationData>() ) { ChoicePtr choice = CreateControl<Choice>(); const Reflect::Enumeration* enumeration = Reflect::ReflectionCast< Enumeration >( field->m_Type ); std::vector< ChoiceItem > items; items.resize( enumeration->m_Elements.GetSize() ); DynArray< EnumerationElement >::ConstIterator itr = enumeration->m_Elements.Begin(); DynArray< EnumerationElement >::ConstIterator end = enumeration->m_Elements.End(); for ( size_t index=0; itr != end; ++itr, ++index ) { ChoiceItem& item = items[index]; item.m_Key = itr->m_Name; item.m_Data = itr->m_Name; } choice->a_HelpText.Set( field->GetProperty( TXT( "HelpText" ) ) ); choice->a_Items.Set( items ); choice->a_IsDropDown.Set( true ); choice->a_IsReadOnly.Set( readOnly ); container->AddChild(choice); } else { if ( field->m_DataClass == Reflect::GetClass<BoolData>() ) { CheckBoxPtr checkBox = CreateControl<CheckBox>(); checkBox->a_IsReadOnly.Set( readOnly ); checkBox->a_HelpText.Set( field->GetProperty( TXT( "HelpText" ) ) ); container->AddChild( checkBox ); } else { ValuePtr value = CreateControl<Value>(); value->a_IsReadOnly.Set( readOnly ); value->a_HelpText.Set( field->GetProperty( TXT( "HelpText" ) ) ); container->AddChild( value ); } } } // // Setup label // LabelPtr label = NULL; { V_Control::const_iterator itr = container->GetChildren().begin(); V_Control::const_iterator end = container->GetChildren().end(); for( ; itr != end; ++itr ) { Label* label = Reflect::SafeCast<Label>( *itr ); if (label) { break; } } } if (!label.ReferencesObject()) { label = CreateControl<Label>(); tstring temp; field->GetProperty( TXT( "UIName" ), temp ); if ( temp.empty() ) { bool converted = Helium::ConvertString( field->m_Name, temp ); HELIUM_ASSERT( converted ); } label->BindText( temp ); label->a_HelpText.Set( field->GetProperty( TXT( "HelpText" ) ) ); container->InsertChild(0, label); } // // Bind data // std::vector<Data*> ser; { std::vector<Reflect::Object*>::const_iterator itr = instances.begin(); std::vector<Reflect::Object*>::const_iterator end = instances.end(); for ( ; itr != end; ++itr ) { DataPtr s = field->CreateData(); if (!s->IsClass(Reflect::GetClass<ContainerData>())) { s->ConnectField(*itr, field); ser.push_back(s); m_Datas.push_back(s); } } } Helium::SmartPtr< MultiStringFormatter<Data> > data = new MultiStringFormatter<Data>( ser ); container->Bind( data ); // // Set default // DataPtr defaultData = field->CreateDefaultData(); if (defaultData.ReferencesObject()) { tstringstream defaultStream; *defaultData >> defaultStream; container->a_Default.Set( defaultStream.str() ); }
void ReflectStlVectorInterpreter::InterpretField(const Field* field, const std::vector<Reflect::Object*>& instances, Container* parent) { if (field->m_Flags & FieldFlags::Hide) { return; } // create the label ContainerPtr labelContainer = CreateControl<Container>(); parent->AddChild( labelContainer ); LabelPtr label = CreateControl< Label >(); label->a_HelpText.Set( field->GetProperty( TXT( "HelpText" ) ) ); labelContainer->AddChild( label ); tstring temp; field->GetProperty( TXT( "UIName" ), temp ); if ( temp.empty() ) { bool converted = Helium::ConvertString( field->m_Name, temp ); HELIUM_ASSERT( converted ); } label->BindText( temp ); // create the list view ContainerPtr listContainer = CreateControl<Container>(); parent->AddChild( listContainer ); ListPtr list = CreateControl<List>(); list->a_HelpText.Set( field->GetProperty( TXT( "HelpText" ) ) ); listContainer->AddChild( list ); // create the buttons ButtonPtr addButton; ButtonPtr removeButton; ButtonPtr upButton; ButtonPtr downButton; if ( !(field->m_Flags & FieldFlags::ReadOnly) ) { addButton = AddAddButton( list ); removeButton = AddRemoveButton( list ); upButton = AddMoveUpButton( list ); downButton = AddMoveDownButton( list ); } // add the buttons to the container ContainerPtr buttonContainer = CreateControl<Container>(); parent->AddChild( buttonContainer ); if ( addButton ) { buttonContainer->AddChild( addButton ); } if ( removeButton ) { buttonContainer->AddChild( removeButton ); } if ( upButton ) { buttonContainer->AddChild( upButton ); } if ( downButton ) { buttonContainer->AddChild( downButton ); } // create the data objects std::vector<Reflect::Object*>::const_iterator itr = instances.begin(); std::vector<Reflect::Object*>::const_iterator end = instances.end(); for ( ; itr != end; ++itr ) { DataPtr s = field->CreateData(); OnCreateFieldData( s ); s->ConnectField(*itr, field); m_Datas.push_back(s); } // bind the ui to the data objects Helium::SmartPtr< MultiStringFormatter<Data> > data = new MultiStringFormatter<Reflect::Data>( (std::vector<Reflect::Data*>&)m_Datas ); list->Bind( data ); // setup the default value DataPtr defaultData = field->CreateDefaultData(); if (defaultData) { tstringstream defaultStream; *defaultData >> defaultStream; list->a_Default.Set( defaultStream.str() ); } }
void ArchiveXML::DeserializeFields( void* structure, const Structure* type ) { if ( m_Iterator.GetCurrent()->GetFirstChild() ) { // advance to the first child m_Iterator.Advance(); for ( XMLElement* sibling = m_Iterator.GetCurrent(); sibling != NULL; sibling = sibling->GetNextSibling() ) { HELIUM_ASSERT( m_Iterator.GetCurrent() == sibling ); const String* fieldNameStr = sibling->GetAttributeValue( Name( TXT("Name") ) ); uint32_t fieldNameCrc = fieldNameStr ? Crc32( fieldNameStr->GetData() ) : 0x0; const Field* field = type->FindFieldByName(fieldNameCrc); if ( field ) { #ifdef REFLECT_ARCHIVE_VERBOSE m_Indent.Get(stdout); Log::Debug(TXT("Deserializing field %s\n"), field->m_Name); m_Indent.Push(); #endif // pull and structure and downcast to data DataPtr latentData = SafeCast<Data>( Allocate() ); if (!latentData.ReferencesObject()) { // this should never happen, the type id read from the file is bogus throw Reflect::TypeInformationException( TXT( "Unknown data for field %s (%s)" ), field->m_Name, m_Path.c_str() ); #pragma TODO("Support blind data") } // if the types match we are a natural fit to just deserialize directly into the field data if ( field->m_DataClass == field->m_DataClass ) { // set data pointer latentData->ConnectField( structure, field ); // process natively DeserializeInstance( (ObjectPtr&)latentData ); // disconnect latentData->Disconnect(); } else // else the type does not match, deserialize it into temp data then attempt to cast it into the field data { REFLECT_SCOPE_TIMER(("Casting")); // construct current serialization structure ObjectPtr currentObject = Registry::GetInstance()->CreateInstance( field->m_DataClass ); // downcast to data DataPtr currentData = SafeCast<Data>(currentObject); if (!currentData.ReferencesObject()) { // this should never happen, the type id in the rtti data is bogus throw Reflect::TypeInformationException( TXT( "Invalid type id for field %s (%s)" ), field->m_Name, m_Path.c_str() ); } // process into temporary memory currentData->ConnectField(structure, field); // process natively DeserializeInstance( (ObjectPtr&)latentData ); // attempt cast data into new definition Data::CastValue( latentData, currentData, DataFlags::Shallow ); // disconnect currentData->Disconnect(); } } #ifdef REFLECT_ARCHIVE_VERBOSE m_Indent.Pop(); #endif } } else { // advance to the next element m_Iterator.Advance(); } }
void ArchiveBinary::DeserializeFields( void* structure, const Structure* type ) { int32_t fieldCount = -1; m_Stream->Read(&fieldCount); for (int i=0; i<fieldCount; i++) { uint32_t fieldNameCrc = BeginCrc32(); m_Stream->Read( &fieldNameCrc ); const Field* field = type->FindFieldByName(fieldNameCrc); if ( field ) { #ifdef REFLECT_ARCHIVE_VERBOSE m_Indent.Get(stdout); Log::Print(TXT("Deserializing field %s\n"), field->m_Name); m_Indent.Push(); #endif // pull and structure and downcast to data DataPtr latentData = SafeCast<Data>( Allocate() ); if (!latentData.ReferencesObject()) { // this should never happen, the type id read from the file is bogus throw Reflect::TypeInformationException( TXT( "Unknown data for field %s (%s)" ), field->m_Name, m_Path.c_str() ); #pragma TODO("Support blind data") } // if the types match we are a natural fit to just deserialize directly into the field data if ( field->m_DataClass == field->m_DataClass ) { // set data pointer latentData->ConnectField( structure, field ); // process natively DeserializeInstance( (ObjectPtr&)latentData ); // disconnect latentData->Disconnect(); } else // else the type does not match, deserialize it into temp data then attempt to cast it into the field data { REFLECT_SCOPE_TIMER(("Casting")); // construct current serialization structure ObjectPtr currentObject = Registry::GetInstance()->CreateInstance( field->m_DataClass ); // downcast to data DataPtr currentData = SafeCast<Data>(currentObject); if (!currentData.ReferencesObject()) { // this should never happen, the type id in the rtti data is bogus throw Reflect::TypeInformationException( TXT( "Invalid type id for field %s (%s)" ), field->m_Name, m_Path.c_str() ); } // process into temporary memory currentData->ConnectField(structure, field); // process natively DeserializeInstance( (ObjectPtr&)latentData ); // attempt cast data into new definition Data::CastValue( latentData, currentData, DataFlags::Shallow ); // disconnect currentData->Disconnect(); } } #ifdef REFLECT_ARCHIVE_VERBOSE m_Indent.Pop(); #endif } int32_t terminator = -1; m_Stream->Read(&terminator); if (terminator != -1) { throw Reflect::DataFormatException( TXT( "Unterminated field array block (%s)" ), m_Path.c_str() ); } }
void ArchiveBinary::DeserializeFields(Object* object) { int32_t fieldCount = -1; m_Stream->Read(&fieldCount); for (int i=0; i<fieldCount; i++) { uint32_t fieldNameCrc = BeginCrc32(); m_Stream->Read( &fieldNameCrc ); const Class* type = object->GetClass(); HELIUM_ASSERT( type ); ObjectPtr unknown; const Field* field = type->FindFieldByName(fieldNameCrc); if ( field ) { #ifdef REFLECT_ARCHIVE_VERBOSE m_Indent.Get(stdout); Log::Print(TXT("Deserializing field %s\n"), field->m_Name); m_Indent.Push(); #endif // pull and object and downcast to data DataPtr latentData = SafeCast<Data>( Allocate() ); if (!latentData.ReferencesObject()) { // this should never happen, the type id read from the file is bogus throw Reflect::TypeInformationException( TXT( "Unknown data for field %s (%s)" ), field->m_Name, m_Path.c_str() ); #pragma TODO("Support blind data") } // if the types match we are a natural fit to just deserialize directly into the field data if ( field->m_DataClass == field->m_DataClass ) { // set data pointer latentData->ConnectField( object, field ); // process natively object->PreDeserialize( field ); DeserializeInstance( (ObjectPtr&)latentData ); object->PostDeserialize( field ); // disconnect latentData->Disconnect(); } else // else the type does not match, deserialize it into temp data then attempt to cast it into the field data { REFLECT_SCOPE_TIMER(("Casting")); // construct current serialization object ObjectPtr currentObject = Registry::GetInstance()->CreateInstance( field->m_DataClass ); // downcast to data DataPtr currentData = SafeCast<Data>(currentObject); if (!currentData.ReferencesObject()) { // this should never happen, the type id in the rtti data is bogus throw Reflect::TypeInformationException( TXT( "Invalid type id for field %s (%s)" ), field->m_Name, m_Path.c_str() ); } // process into temporary memory currentData->ConnectField(object, field); // process natively object->PreDeserialize( field ); DeserializeInstance( (ObjectPtr&)latentData ); // attempt cast data into new definition if ( !Data::CastValue( latentData, currentData, DataFlags::Shallow ) ) { // handle as unknown unknown = latentData; } else { // post process object->PostDeserialize( field ); } // disconnect currentData->Disconnect(); } } else // else the field does not exist in the current class anymore { try { DeserializeInstance( unknown ); } catch (Reflect::LogisticException& ex) { Log::Debug( TXT( "Unable to deserialize %s::%s, discarding: %s\n" ), type->m_Name, field->m_Name, ex.What()); } } if ( unknown.ReferencesObject() ) { // attempt processing object->ProcessUnknown( unknown, field ? Crc32( field->m_Name ) : 0 ); } #ifdef REFLECT_ARCHIVE_VERBOSE m_Indent.Pop(); #endif } int32_t terminator = -1; m_Stream->Read(&terminator); if (terminator != -1) { throw Reflect::DataFormatException( TXT( "Unterminated field array block (%s)" ), m_Path.c_str() ); } }
void PathInterpreter::InterpretField(const Field* field, const std::vector<Reflect::Object*>& instances, Container* parent) { if (field->m_Flags & FieldFlags::Hide) { return; } // // Create the ui we are generating // std::vector< ContainerPtr > groups; ContainerPtr container = CreateControl<Container>(); groups.push_back( container ); bool pathField = field->m_DataClass == Reflect::GetClass< PathData >(); bool readOnly = ( field->m_Flags & FieldFlags::ReadOnly ) == FieldFlags::ReadOnly; DataChangingSignature::Delegate changingDelegate; FileDialogButtonPtr fileDialogButton; // // Parse // tstring fieldUI; field->GetProperty( TXT( "UIScript" ), fieldUI ); bool result = Script::Parse(fieldUI, this, parent->GetCanvas(), container, field->m_Flags); if (!result) { if ( pathField || field->m_DataClass == Reflect::GetClass<StlStringData>() ) { ContainerPtr valueContainer = CreateControl<Container>(); ValuePtr value = CreateControl< Value >(); value->a_Justification.Set( Justifications::Right ); value->a_IsReadOnly.Set( readOnly ); value->a_HelpText.Set( field->GetProperty( TXT( "HelpText" ) ) ); valueContainer->AddChild( value ); groups.push_back( valueContainer ); if ( !readOnly ) { changingDelegate = DataChangingSignature::Delegate(this, &PathInterpreter::DataChanging); // File dialog button fileDialogButton = CreateControl< FileDialogButton >(); fileDialogButton->a_HelpText.Set( TXT( "Open a file dialog to choose a new file." ) ); field->GetProperty( TXT( "FileFilter" ), m_FileFilter ); if ( !m_FileFilter.empty() ) { fileDialogButton->a_Filter.Set( m_FileFilter ); } container->AddChild( fileDialogButton ); value->SetProperty( TXT( "FileFilter" ), m_FileFilter ); m_Value = value; } if ( instances.size() == 1 ) { // File edit button ButtonPtr editButton = CreateControl< Button >(); editButton->ButtonClickedEvent().Add( ButtonClickedSignature::Delegate ( this, &PathInterpreter::Edit ) ); editButton->a_Label.Set( TXT( "Edit" ) ); editButton->a_HelpText.Set( TXT( "Attempt to edit the file using its associated default application." ) ); container->AddChild( editButton ); } } } else { ValuePtr value = CreateControl< Value >(); value->a_IsReadOnly.Set( readOnly ); value->a_HelpText.Set( field->GetProperty( TXT( "HelpText" ) ) ); container->AddChild( value ); } // // Setup label // LabelPtr label = NULL; { V_Control::const_iterator itr = container->GetChildren().begin(); V_Control::const_iterator end = container->GetChildren().end(); for( ; itr != end; ++itr ) { Label* label = Reflect::SafeCast<Label>( *itr ); if (label) { break; } } } if (!label.ReferencesObject()) { label = CreateControl< Label >(); tstring temp; field->GetProperty( TXT( "UIName" ), temp ); if ( temp.empty() ) { bool converted = Helium::ConvertString( field->m_Name, temp ); HELIUM_ASSERT( converted ); } label->BindText( temp ); label->a_HelpText.Set( field->GetProperty( TXT( "HelpText" ) ) ); container->InsertChild(0, label); } // // Create type m_FinderSpecific data bound to this and additional instances // std::vector<Data*> ser; { std::vector<Reflect::Object*>::const_iterator itr = instances.begin(); std::vector<Reflect::Object*>::const_iterator end = instances.end(); for ( ; itr != end; ++itr ) { DataPtr s = field->CreateData(); if (s->IsClass(Reflect::GetClass<ContainerData>())) { return; } s->ConnectField(*itr, field); ser.push_back(s); m_Datas.push_back(s); } } // // Create data and bind // Helium::SmartPtr< MultiStringFormatter<Data> > data = new MultiStringFormatter<Data>( ser ); if (changingDelegate.Valid()) { data->AddChangingListener( changingDelegate ); } { std::vector<ContainerPtr>::const_iterator itr = groups.begin(); std::vector<ContainerPtr>::const_iterator end = groups.end(); for ( ; itr != end; ++itr ) { (*itr)->Bind( data ); } } // // Set default // DataPtr defaultData = field->CreateDefaultData(); if (defaultData.ReferencesObject()) { tstringstream defaultStream; *defaultData >> defaultStream; container->a_Default.Set( defaultStream.str() ); }
void ReflectVectorInterpreter::InterpretField(const Field* field, const std::vector<Reflect::Object*>& instances, Container* parent) { if ( field->m_Flags & FieldFlags::Hide ) { return; } // create the container ContainerPtr container = CreateControl< Container >(); parent->AddChild( container ); // create the label LabelPtr label = CreateControl< Label >(); container->AddChild( label ); label->a_HelpText.Set( field->GetProperty( TXT( "HelpText" ) ) ); tstring temp; field->GetProperty( TXT( "UIName" ), temp ); if ( temp.empty() ) { bool converted = Helium::ConvertString( field->m_Name, temp ); HELIUM_ASSERT( converted ); } label->BindText( temp ); label->a_HelpText.Set( field->GetProperty( TXT( "HelpText" ) ) ); // compute dimensions int dimensions = 2; if ( field->m_DataClass == Reflect::GetClass<Vector3Data>() ) { dimensions += 1; } if ( field->m_DataClass == Reflect::GetClass<Vector4Data>() ) { dimensions += 2; } // create the dimension ui for ( int offset = 0; offset < dimensions*4; offset += 4 ) { // create the data objects std::vector<Reflect::Data*> data; std::vector<Reflect::Object*>::const_iterator itr = instances.begin(); std::vector<Reflect::Object*>::const_iterator end = instances.end(); for ( ; itr != end; ++itr ) { DataPtr s = new Float32Data (); s->ConnectField(*itr, field, offset); m_Datas.push_back(s); data.push_back(s); } // create the text box ValuePtr value = CreateControl< Value >(); container->AddChild( value ); value->a_IsReadOnly.Set( ( field->m_Flags & FieldFlags::ReadOnly ) == FieldFlags::ReadOnly ); value->a_HelpText.Set( field->GetProperty( TXT( "HelpText" ) ) ); // bind the ui to the data objects value->Bind( new MultiStringFormatter<Data>( data ) ); } }