Dynamic setting sample

This sample demonstrates how to load/save an application settings via the wxXmlSerializer class. The serializable class instance with application settings is dynamically created in this sample.

The sample consists of three main classes:

The following diagram showing the relations between these classes:

dynamic-settings-sample-diagram.png



SerializableObject class

Encapsulates wxString data type member m_sTextData. Class has implemented copy constructor necessary for proper functionality of the wxXmlSerializer class copy constructor and wxXmlSerializer::CopyItems() function.

Declaration and implementation of this class (from source files SettingsSample.h and SettingsSample.cpp):

class SerializableObject : public xsSerializable
{
public:
        // RTTI must be provided
        DECLARE_DYNAMIC_CLASS(SerializableObject);

        // constructor
        SerializableObject();
        // copy constructor needed by the xml serializer class copy constructor
        // or by default implementation of the xsSerializable::Clone() function.
        // You haven't to define it if you don't plan to use the Clone() function
        // or serializer class copy constructor.
        SerializableObject(SerializableObject &obj);
        // destructor
        virtual ~SerializableObject();

        // Clone function and copy constructor must be implemented for proper
        // functionality of the serializer class copy constructor and
        // wxXmlSerializer::CopyItems() function. The Clone function can
        // be defined automatically if you use XS_DECLARE_CLONABLE_CLASS and
        // XS_IMPLEMENT_CLONABLE_CLASS instead of the DECLARE_DYNAMIC_CLASS
        // and IMPLEMENT_DYNAMIC_CLASS (see Settings class bellow)
        virtual xsSerializable* Clone(){return new SerializableObject(*this);}

        // protected data members
        wxString m_sTextData;
};
// SerializableObject class /////////////////////////////////////////////////////////

IMPLEMENT_DYNAMIC_CLASS(SerializableObject, xsSerializable);

SerializableObject::SerializableObject()
{
        // initialize member data
        m_sTextData = wxT("Textual data encapsulated by 'SerializableObject' class object");
        // mark the data members which should be serialized
        XS_SERIALIZE(m_sTextData, wxT("text"));
}

SerializableObject::SerializableObject(SerializableObject &obj)
: xsSerializable(obj)
{
        // initialize member data
        m_sTextData = obj.m_sTextData;
        // mark the data members which should be serialized
        XS_SERIALIZE(m_sTextData, wxT("text"));
}

SerializableObject::~SerializableObject()
{
}


Settings class

This class encapsulates tha data members of all data types which are currently supported by the wxXmlSerializer library and also contains the static and dynamic instances of the SerializableObject class. All these members can be marked to serialize by calling the function Settings::MarkDataMembers() and their default values are set in the constructor.

Declaration and implementation of the Settings class with commentary:

class Settings : public xsSerializable
{
public:
        // RTTI and xsSerializable::Clone() function must be provided
        XS_DECLARE_CLONABLE_CLASS(Settings);

        // constructor
        Settings();
        // copy constructor needed by the xml serializer class copy constructor
        // or by default implementation of the xsSerializable::Clone() function.
        // You haven't to define it if you don't plan to use the Clone() function
        // or serializer class copy constructor.
        Settings(Settings &obj);
        // destructor
        virtual ~Settings();

protected:
        // protected data members

        // wxXmlSerializer currently supports these data types:
        // int
        int m_nIntData;
        // long
        long m_nLongData;
        // double
        float m_nFloatData;
        // double
        double m_nDoubleData;
        // double
        double m_nFloatNaNData;
        // double
        double m_nDoubleInfData;
        // bool
        bool m_fBoolData;
        // wxChar
        wxChar m_nCharData;
        // wxString
        wxString m_sTextData;
        // wxPoint
        wxPoint m_nPointData;
        // wxSize
        wxSize m_nSizeData;
        // wxRealPoint
        wxRealPoint m_nRealPointData;
        // wxColour
        wxColour m_nColourData;
        // wxPen
        wxPen m_PenData;
        // wxBrush
        wxBrush m_BrushData;
        // wxFont
        wxFont m_FontData;
        // wxArrayString
        wxArrayString m_arrStringData;
        // RealPointArray - array of wxRealPoint values
        RealPointArray m_arrRealPointData;
        // RealPointList - list of wxRealPoint values
        RealPointList m_lstRealPointData;
        // StringMap - hash map with string keys and values
        StringMap m_mapStringData;
        // dynamic instances of xsSerializable class or other derived classes
        SerializableObject *m_pDynamicSerializableObject;
        // static instances of xsSerializable class or other derived classes
        SerializableObject m_StaticSerializableObject;

private:
        // private auxiliary functions
        void MarkDataMembers();
};
// Settings class ///////////////////////////////////////////////////////////////////

XS_IMPLEMENT_CLONABLE_CLASS(Settings, xsSerializable);

Settings::Settings()
{
        // set default values of application properties:

        // int
        m_nIntData = 1024;
        // long
        m_nLongData = 123456789;
        // double
        m_nDoubleData = 3.14159267;
        // double INF
        m_nDoubleInfData = numeric_limits<double>::infinity();
        // double
        m_nFloatData = 3.14f;
        // float NaN
        m_nFloatNaNData = numeric_limits<float>::quiet_NaN();
        // bool
        m_fBoolData = true;
        // wxChar
        m_nCharData = 'A';
        // wxString
        m_sTextData = wxT("Textual data");
        // wxPoint
        m_nPointData = wxPoint(0, 0);
        // wxSize
        m_nSizeData = wxSize(100, 200);
        // wxRealPoint
        m_nRealPointData = wxRealPoint(1.23, 4.56);
        // wxPen
        m_PenData = *wxBLACK_PEN;
        // wxBrush
        m_BrushData = *wxBLACK_BRUSH;
        // wxFont
        m_FontData = *wxSWISS_FONT;
        // wxColour
        m_nColourData = *wxWHITE;
        // wxArrayString
        m_arrStringData.Add(wxT("First string item"));
        m_arrStringData.Add(wxT("Second string item"));
        // RealPointArray - array of wxRealPoint values
        m_arrRealPointData.Add(wxRealPoint(1.2, 3.4));
        m_arrRealPointData.Add(wxRealPoint(5.6, 7.8));
        // RealPointList - list of wxRealPoint values
        m_lstRealPointData.Append(new wxRealPoint(1.2, 3.4));
        m_lstRealPointData.Append(new wxRealPoint(5.6, 7.8));
        // StringMap - hash map with string keys and values
        m_mapStringData[wxT("Key1")] = wxT("Value1");
        m_mapStringData[wxT("Key2")] = wxT("Value2");
        // dynamic instances of xsSerializable class or other derived classes
        m_pDynamicSerializableObject = new SerializableObject();
        // static instances of xsSerializable class or other derived classes
        m_StaticSerializableObject.m_sTextData = wxT("Modified textual data encapsulated by 'SerializableObject' class object");

        // mark class data members which should be serialized
        MarkDataMembers();
}

// Copy constructor needed by the xml serializer class copy constructor
// or by default implementation of the xsSerializable::Clone() function.
// You haven't to define it if you don't plan to use the Clone() function
// or serializer class copy constructor.
Settings::Settings(Settings &obj) : xsSerializable(obj)
{
        // copy values from source object

        m_nIntData = obj.m_nIntData;
        m_nLongData = obj.m_nLongData;
        m_nDoubleData = obj.m_nDoubleData;
        m_nDoubleInfData = obj.m_nDoubleInfData;
        m_nFloatData = obj.m_nFloatData;
        m_nFloatNaNData = obj.m_nFloatNaNData;
        m_fBoolData = obj.m_fBoolData;
        m_nCharData = obj.m_nCharData;
        m_sTextData = obj.m_sTextData;
        m_nPointData = obj.m_nPointData;
        m_nSizeData = obj.m_nSizeData;
        m_nRealPointData = obj.m_nRealPointData;
        m_PenData = obj.m_PenData;
        m_BrushData = obj.m_BrushData;
        m_FontData = obj.m_FontData;
        m_nColourData = obj.m_nColourData;

        // copy array items
        WX_APPEND_ARRAY(m_arrStringData, obj.m_arrStringData);
        WX_APPEND_ARRAY(m_arrRealPointData, obj.m_arrRealPointData);

        // copy list item
        wxRealPointListNode *node = obj.m_lstRealPointData.GetFirst();
        while(node)
        {
                m_lstRealPointData.Append(new wxRealPoint(*node->GetData()));
                node = node->GetNext();
        }

    // copy map content
        m_mapStringData = obj.m_mapStringData;

        // copy dynamic instances of xsSerializable class or other derived classes
        m_pDynamicSerializableObject = (SerializableObject*)obj.m_pDynamicSerializableObject->Clone();

        // copy static instances of xsSerializable class or other derived classes
        m_StaticSerializableObject.m_sTextData = obj.m_StaticSerializableObject.m_sTextData;

        // mark class data members which should be serialized
        MarkDataMembers();
}

Settings::~Settings()
{
        // data clean up
        if( m_pDynamicSerializableObject )delete m_pDynamicSerializableObject;

        m_lstRealPointData.DeleteContents(true);
        m_lstRealPointData.Clear();
}

void Settings::MarkDataMembers()
{
        // mark class data members which should be serialized
        XS_SERIALIZE(m_nIntData, wxT("integer_data"));
        XS_SERIALIZE(m_nLongData, wxT("long_int_data"));
        XS_SERIALIZE(m_nFloatData, wxT("float_data"));
        XS_SERIALIZE(m_nDoubleData, wxT("double_data"));
        XS_SERIALIZE(m_nFloatNaNData, wxT("float_NaN_data"));
        XS_SERIALIZE(m_nDoubleInfData, wxT("double_INF_data"));
        XS_SERIALIZE(m_fBoolData, wxT("boolean_data"));
        XS_SERIALIZE(m_nCharData, wxT("char_data"));
        XS_SERIALIZE(m_sTextData, wxT("string_data"));
        XS_SERIALIZE(m_nPointData, wxT("point_data"));
        XS_SERIALIZE(m_nSizeData, wxT("size_data"));
        XS_SERIALIZE(m_nRealPointData, wxT("realpoint_data"));
        XS_SERIALIZE(m_nColourData, wxT("color_data"));
        XS_SERIALIZE(m_PenData, wxT("pen_data"));
        XS_SERIALIZE(m_BrushData, wxT("brush_data"));
        XS_SERIALIZE(m_FontData, wxT("font_data"));
        XS_SERIALIZE(m_arrStringData, wxT("stringarray_data"));
        XS_SERIALIZE(m_arrRealPointData, wxT("realpointarray_data"));
        XS_SERIALIZE(m_lstRealPointData, wxT("realpointlist_data"));
        XS_SERIALIZE(m_mapStringData, wxT("stringmap_data"));
        XS_SERIALIZE_DYNAMIC_OBJECT_NO_CREATE(m_pDynamicSerializableObject, wxT("dynamicobject_data"));
        XS_SERIALIZE_STATIC_OBJECT(m_StaticSerializableObject, wxT("staticobject_data"));
}


SettingsSampleApp class

This class implements the functions necessary for the serilization/deserialization of the dynamic Settings class instance which is encapsulated by this class.

Function oninit() deserialize values of Setting class properties from XML file, if this file doesn't exist the Settings class instance is serialized with its default values. Settings class instance is dynamically created and added to the serializer as its root node.

Function onexit() performs saving the content of the serializer to the output XML file.

The commented declaration and implementation of this class is here (from source files SettingsSample.h and SettingsSample.cpp):

class SettingsSampleApp : 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;
};

DECLARE_APP(SettingsSampleApp);
// SettingsSampleApp class //////////////////////////////////////////////////////////

IMPLEMENT_APP(SettingsSampleApp);

bool SettingsSampleApp::OnInit()
{
        // load application settings if the configuration file exists, otherwise create new
        // settings class object with default values

        // initialize serializer
        m_XmlIO.SetSerializerOwner(wxT("DynamicSettingsSampleApp"));
        m_XmlIO.SetSerializerRootName(wxT("settings"));
        m_XmlIO.SetSerializerVersion(wxT("1.0.0"));

    // 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 ('Settings' class object properties
                // are deserialized from the information stored in the 'settings.xml' 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 the main application frame
    MainFrame *frame = new MainFrame(NULL);
    SetTopWindow(frame);
    frame->Show();

    return true;
}

int SettingsSampleApp::OnExit()
{
        if( m_pSettings )
        {
        // Write application settings. We must tell the serializer the root's properties
        // should be serialized as well (using 'xsWITH_ROOT' in second argument of SerializeToXml() function).
        // Note that the root node isn't serialized like any other nodes: only its properties can
        // be serialized into special xml node called 'NAME_properties' where NAME is the root
        // node name set by function SetSerializerRootName().
                m_XmlIO.SerializeToXml(wxT("settings.xml"), xsWITH_ROOT);
        }

        return 0;
}


In this sample there is another class called MainFrame which takes care about view of the main application window. This class also implements the function DumpSerializableObject(xsSerializable *obj, wxTextCtrl *memo) which print out properties of the serializable class instance passed as the parameter xsSerializable *obj. Implementation of this function with commentary is here:

void MainFrame::DumpSerializableObject(xsSerializable *obj, wxTextCtrl *memo)
{
        // dump info about serializable object
        memo->AppendText(wxString::Format(wxT("Serializable object of type '%s' with ID:%d at address 0x%x :\n"), obj->GetClassInfo()->GetClassName(), obj->GetId(), obj));

        // get serialized properties maintained by the Setting class
        xsProperty *prop;
        PropertyList::compatibility_iterator node = obj->GetProperties().GetFirst();
        while( node )
        {
                prop = node->GetData();
                memo->AppendText( wxString::Format( wxT("Property name: %s, Type: %s, Value: %s\n"),
                                                                                        prop->m_sFieldName.c_str(),
                                                                                        prop->m_sDataType.c_str(),
                                                                                        prop->ToString().c_str() ) );
                node = node->GetNext();
        }

        memo->AppendText(wxT("\n"));
}


A content of the XML file created by this sample application:

<?xml version="1.0" encoding="utf-8"?>
<settings owner="DynamicSettingsSampleApp" version="1.0.0">
    <settings_properties>
        <object type="Settings">
            <property name="id" type="long">-1</property>
            <property name="integer_data" type="int">1024</property>
            <property name="long_int_data" type="long">123456789</property>
            <property name="float_data" type="float">3.140000</property>
            <property name="double_data" type="double">3.141593</property>
            <property name="float_NaN_data" type="double">NAN</property>
            <property name="double_INF_data" type="double">INF</property>
            <property name="boolean_data" type="bool">1</property>
            <property name="char_data" type="char">A</property>
            <property name="string_data" type="string">Textual data</property>
            <property name="point_data" type="point">0,0</property>
            <property name="size_data" type="size">100,200</property>
            <property name="realpoint_data" type="realpoint">1.230000,4.560000</property>
            <property name="color_data" type="colour">255,255,255,255</property>
            <property name="pen_data" type="pen">0,0,0,255 1 100</property>
            <property name="brush_data" type="brush">0,0,0,255 100</property>
            <property name="font_data" type="font">arial</property>
            <property name="stringarray_data" type="arraystring">
                <item>First string item</item>
                <item>Second string item</item>
            </property>
            <property name="realpointarray_data" type="arrayrealpoint">
                <item>1.200000,3.400000</item>
                <item>5.600000,7.800000</item>
            </property>
            <property name="realpointlist_data" type="listrealpoint">
                <item>1.200000,3.400000</item>
                <item>5.600000,7.800000</item>
            </property>
            <property name="stringmap_data" type="mapstring">
                <item key="Key1">Value1</item>
                <item key="Key2">Value2</item>
            </property>
            <property name="dynamicobject_data" type="serializabledynamicnocreate">
                <object type="SerializableObject">
                    <property name="id" type="long">-1</property>
                    <property name="text" type="string">Textual data encapsulated by 'SerializableObject' class object</property>
                </object>
            </property>
            <property name="staticobject_data" type="serializablestatic">
                <object type="SerializableObject">
                    <property name="id" type="long">-1</property>
                    <property name="text" type="string">Modified textual data encapsulated by 'SerializableObject' class object</property>
                </object>
            </property>
        </object>
    </settings_properties>
</settings>


Screenshot of the running application:

dynamic-settings-sample.png
Generated by  doxygen 1.6.3