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; }
DataPtr Field::CreateData(void* instance) const { DataPtr data = CreateData(); if ( data.ReferencesObject() ) { if ( instance ) { data->ConnectField( instance, this ); } } return data; }
void Control::Bind(const DataPtr& data) { if ( !m_BoundData.ReferencesObject() || !data.ReferencesObject() ) { if ( m_BoundData.ReferencesObject() ) { m_BoundData->RemoveChangedListener( DataChangedSignature::Delegate ( this, &Control::DataChanged ) ); } m_BoundData = data; if ( m_BoundData.ReferencesObject() ) { m_BoundData->AddChangedListener( DataChangedSignature::Delegate ( this, &Control::DataChanged ) ); } } }
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 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() ); }