This sample demonstrates how to extend the wxXmlSerializer about own data types, In this sample wxColourDataType.
First of all the user have to create the new IO handler and define the macros which will be used for marking serialized data members (code taken from CustomDataSample.h):
// declaration of a class 'xsColourDataPropIO' encapsulating custom property I/O handler // for 'wxColouData' data type XS_DECLARE_IO_HANDLER(wxColourData, xsColourDataPropIO); // definition macros which create new serialized wxColourData property (without/with defined default value). data type's assertion is not compulsory, but usefull... #define XS_SERIALIZE_COLOURDATA(x, name) wxASSERT_MSG(x.IsKindOf(CLASSINFO(wxColourData)), wxT("Object is not wxColourData"));XS_SERIALIZE_PROPERTY(x, wxT("colourdata"), name); #define XS_SERIALIZE_COLOURDATA_EX(x, name, def) wxASSERT_MSG(x.IsKindOf(CLASSINFO(wxColourData)), wxT("Object is not wxColourData"));XS_SERIALIZE_PROPERTY_EX(x, wxT("colourdata"), name, xsColourDataPropIO::ToString(def));
The macro XS_DECLARE_IO_HANDLER
declares the new class xsColourDataPropIO
which will handle the data members of wxColourData
data type. Macros XS_SERIALIZE_COLOURDATA
and XS_SERIALIZE_COLOURDATA_EX
will be using for marking wxColourData
data types in similar way like the macro XS_SERIALIZE
used for standardly supported data types.
In the the macro XS_DEFINE_IO_HANDLER
the programmer have to implement the functions xsColourDataPropIO::ToString
and xsColourDataPropIO::FromString
which will be responsible for conversion of processed data value to its string representation and vice versa.
// xsColourDataPropIO class ///////////////////////////////////////////////////////// // define class encapsulating custom data format handler XS_DEFINE_IO_HANDLER(wxColourData, xsColourDataPropIO); // two following static member functions of the data handler class MUST be defined manualy: // wxString xsPropIO::ToString(T value) -> creates a string representation of the given value wxString xsColourDataPropIO::ToString(const wxColourData& value) { wxString out; wxColourData data = value; // << hack due to bug in WX: function wxColourData::GetCustomColour() isn't constant like wxColourData::GetColour() out << xsColourPropIO::ToString( data.GetColour() ); for(int i = 0; i < 16; i++) { out << wxT("|"); out << xsColourPropIO::ToString( data.GetCustomColour(i) ); } return out; } // T xsPropIO::FromString(const wxString& value) -> converts data from given string representation to its relevant value wxColourData xsColourDataPropIO::FromString(const wxString& value) { wxColourData data; if(!value.IsEmpty()) { int i = 0; wxStringTokenizer tokens(value, wxT("|"), wxTOKEN_STRTOK); data.SetColour(xsColourPropIO::FromString(tokens.GetNextToken())); while(tokens.HasMoreTokens()) { data.SetCustomColour(i, xsColourPropIO::FromString(tokens.GetNextToken())); i++; } } return data; }
Setting class contains member of data type wxColourData:
class Settings : public xsSerializable { public: // RTTI and xsSerializable::Clone() function must be provided XS_DECLARE_CLONABLE_CLASS(Settings); // constructor Settings(); // copy onstructor needed by default implementation of xsSerializable::Clone() function Settings(Settings &obj); // destructor virtual ~Settings(); // public data members wxColourData m_colourData; };
// Settings class /////////////////////////////////////////////////////////////////// XS_IMPLEMENT_CLONABLE_CLASS(Settings, xsSerializable); Settings::Settings() { // set default values of application properties: m_colourData.SetColour(*wxBLUE); for(int i = 0; i < 16; i++)m_colourData.SetCustomColour(i, wxColour(i*16, i*16, i*16)); // serialize colour data everytime XS_SERIALIZE_COLOURDATA(m_colourData, wxT("colordlg_content")); // this version of mark macro causes the data will be serialized only if its value // differs from the default one (the last macro parameter) //XS_SERIALIZE_COLOURDATA_EX(m_colourData, wxT("colordlg_content"), m_colourData); } Settings::Settings(Settings &obj) { // set default values of application properties: m_colourData = obj.m_colourData; // serialize colour data everytime XS_SERIALIZE_COLOURDATA(m_colourData, wxT("colordlg_content")); // this version of mark macro causes the data will be serialized only if its value // differs from the default one (the last macro parameter) //XS_SERIALIZE_COLOURDATA_EX(m_colourData, wxT("colordlg_content"), m_colourData); } Settings::~Settings() { // data clean up }
The wxColourData
data type member m_colourData
is marked to serialize by previously defined macro XS_SERIALIZE_COLOURDATA
. Note that new macros XS_DECLARE_CLONABLE_CLASS
and XS_DECLARE_CLONABLE_CLASS
were used in the code. These macros differ from DECLARE_DYNAMIC_CLASS
and IMPLEMENT_DYNAMIC_CLASS
macros in such way that they implement also Clone()
function for the class, which can be used for retrieving the exact copy of the class instance. This function is further used by wxXmlSerializer::CopyItems()
member function and its copy constructor so a whole serializer's content can be copied in a single program line.
The last step in the initialization process of new IO handler is its registration. In this sample it is done in CustomDataSampleApp
class by using the macro XS_REGISTER_IO_HANDLER
.
The declaration and implemetation of CustomDataSampleApp
class (taken from files CustomDataSample.h and CustomDataSample.cpp):
class CustomDataSampleApp : public wxApp { public: virtual bool OnInit(); virtual int OnExit(); // public data members // settings class Settings *m_pSettings; protected: // protected data members // main serializer object wxXmlSerializer m_XmlIO; };
// CustomDataSampleApp class //////////////////////////////////////////////////////// IMPLEMENT_APP(CustomDataSampleApp); bool CustomDataSampleApp::OnInit() { // load application settings if the configuration file exists, otherwise create new // settings class object with default values // initialize serializer m_XmlIO.SetSerializerOwner(wxT("CustomDataSampleApp")); m_XmlIO.SetSerializerRootName(wxT("settings")); m_XmlIO.SetSerializerVersion(wxT("1.0.0")); // register new property I/O handler 'xsColourDataPropIO' for data type with name 'colourdata' XS_REGISTER_IO_HANDLER(wxT("colourdata"), xsColourDataPropIO); // create serialized settings class object manualy with default values m_pSettings = new Settings(); // insert settings class object into serializer as its root node m_XmlIO.SetRootItem(m_pSettings); if( wxFileExists(wxT("settings.xml")) ) { // load settings from configuration file m_XmlIO.DeserializeFromXml(wxT("settings.xml")); } // data stored in serializable classes can be also accessed in a standard way via class data members like this: // m_pSettings->m_nIntData = 100; // or via properties encapsulating the class members, for example in this way: // m_pSettings->GetProperty(wxT("integer_data"))->FromString(wxT("100")); // m_pSettings->GetProperty(wxT("integer_data"))->AsInt() = 1024; // wxPrintf( wxT("Value %d\n"), m_pSettings->GetProperty(wxT("integer_data"))->AsInt() ); // create and show main application frame MainFrame *frame = new MainFrame(NULL); SetTopWindow(frame); frame->Show(); return true; } int CustomDataSampleApp::OnExit() { // write application settings if( m_pSettings ) { // serialize settings to XML file m_XmlIO.SerializeToXml(wxT("settings.xml"), xsWITH_ROOT); } return 0; }
Colaborations between classes in this sample:
A content of the output XML file created bz this sample application:
<?xml version="1.0" encoding="utf-8"?> <settings owner="CustomDataSampleApp" version="1.0.0"> <settings_properties> <object type="Settings"> <property name="id" type="long">-1</property> <property name="colordlg_content" type="colourdata">64,0,128,255|0,0,0,255|16,16,16,255|32,32,32,255|48,48,48,255|64,64,64,255|80,80,80,255|96,96,96,255|112,112,112,255|128,128,128,255|144,144,144,255|160,160,160,255|176,176,176,255|192,192,192,255|208,208,208,255|224,224,224,255|240,240,240,255</property> </object> </settings_properties> </settings>
Screenshot of the running application: