2.3. GtkOL serialization handling
GtkOL implements the
libgenerics xml serialization abtraction. It does not support the
libgenerics archive abstraction. Any of the GtkOL components are serializable in an xml way unless they are declared as
capsule or
generic
classes. The purpose of such an implementation is the ability for an
application to dump its whole state into a file to be launched
again with the same detailed state it was when it ended.
2.3.1. GtkOL serialization considerations
First of all, let's have a look on how the xml file is structured about an instance.
fig. GtkOL serialization overview
Xml Dump
To dump a component state, you first have to declare
an xml document giving it an xml file name, the write mode and
the absolute xml element name.
CXMLDocument XMLDocWrite (CString("/home/user/gtkol-dump.xml"), XML_WRITE, CString("gtkol")); |
Once you've got it, you can redirect any GtkOL
component into and the serialization process of the component and its descent hierarchy will be
automatically handled.
CForm *aForm = new CForm ();
XMLDocWrite << aForm; |
Xml Load
To reload a GtkOL
components hierarchy from a given xml file, you first have to declare
an xml document giving it the desired xml file name, the read mode and
the expected absolute xml element name. You have to retreive the root
xml element.
CXMLDocument XMLDocRead (CString("/home/user/gtkol-dump.xml"), XML_READ, CString("gtkol"));
CXMLElementNode *inXMLRoot = XMLDocRead.GetRootElement (); |
Then, you can request a GtkOL components hierarchy
instanciation mapping the given xml scheme from the xml root element
and free the xml pointer.
CSerialized *inSerialized = CSerialized::Instanciate (inXMLRoot);
delete inXMLRoot;
|
The returned
instance might be any of the GtkOL ones, depending on what has been
dumped into the xml file when created. Let's consider the whole
application has been dumped i.e. the GtkOL application instance itself
has been dumped, so the complete GtkOL hierarchy is reloaded from
scratch, you just have to check the returned pointer type and request
the application launch...
Simple application xml dump sample :
<?xml version="1.0" encoding="UTF-8" ?>
<gtkol>
<cserialized name="CApplication" tag="appl">
<ccomponent>
<capplication>
<argv>./gtkol-dump</argv>
</capplication>
<children>
<cserialized name="CForm" tag="form">
<cserialized name="CMainFormListener" tag="_mfm"></cserialized>
<ccomponent>
<ccontrol draggable="false" dropsite="true" x="252" y="30" w="520" h="670">
<cwidget shown="true" enabled="true">
<ccontainer padding="0">
<cform caption="Gtkol Dump" maximize="false" minimize="false"
fullscreen="false" sticky="false" above="false" below="false"
resizeable="true" decorated="true" taskbar-hint="true"
pager-hint="true"></cform>
</ccontainer>
</cwidget>
</ccontrol>
<children>
<cserialized name="CVBoxLayout" tag="vbly">
<ccomponent>
<ccontrol draggable="false" dropsite="true">
<cwidget shown="true" enabled="true">
<ccontainer padding="0">
<cboxlayout spacing="1" homogeneous="false">
<cboxlayout-child box="start" expand="false" fill="false"
padding="0"></cboxlayout-child>
</cboxlayout>
</ccontainer>
</cwidget>
</ccontrol>
<children>
<cserialized name="CMenuBar" tag="mnbr">
<ccomponent>
<ccontrol draggable="false" dropsite="false">
<cwidget shown="true" enabled="true">
<ccontainer padding="0"></ccontainer>
</cwidget>
</ccontrol>
<children>
<cserialized name="CMenuItem" tag="mntm">
<ccomponent>
<ccontrol draggable="false" dropsite="false">
<cwidget shown="true" enabled="true">
<ccontainer padding="0">
<cmenuitem caption="_File"></cmenuitem>
</ccontainer>
</cwidget>
</ccontrol>
<children>
<cserialized name="CMenuItem" tag="mntm">
<cserialized name="CFileExitMenuItemListener" tag="_cmn"></cserialized>
<ccomponent>
<ccontrol draggable="false" dropsite="false">
<cwidget shown="true" enabled="true">
<ccontainer padding="0">
<cmenuitem caption="_Quit" key="113"
combinaison="ctrl"></cmenuitem>
</ccontainer>
</cwidget>
</ccontrol>
</ccomponent>
</cserialized>
</children>
</ccomponent>
</cserialized>
</children>
</ccomponent>
</cserialized>
</children>
</ccomponent>
</cserialized>
</children>
</ccomponent>
</cserialized>
</children>
</ccomponent>
</cserialized>
</gtkol> |
|
2.3.2. GtkOL runtime potential approach
With such an
implementation, it would be very easy to create a complete GtkOL
application while just building it as an xml file and injecting it in a
simple "
gtkol runtime binary"
that would dynamically link particular widgets signal handlers such as a pool of developper typicall listeners, open
the given xml template and instanciate the complete GUI, giving the
developper the possibility to write the minimum amount of code : the event handlers
scope only.
fig. GtkOL runtime logical implementation
The simple reusable GtkOL runtime could be something like :
// get the gtkol application definition and the generics metamodule importer API
#include "capplication.h"
#include "cmetamoduleimporter.h"
//---------------------------------------------------------------------------------------
// gtkol-runtime entry point
//---------------------------------------------------------------------------------------
int main (int argc, char **argv)
{
// check command line arguments
if (argc != 2)
{
::printf ("%s file.xml\n", argv[0]);
return 0;
}
// get the potential runtime modules from the specified directory
CStrings inMetaModuleNames (CMetaModuleImporter::GetLibNames (CString("./modules")));
// declare a metamodule importer list
TBuffer <CMetaModuleImporter *> theMetaModuleImporters;
try
{
// foreach potential module, try to link it with the metamodule importer API
for (size_t i=inMetaModuleNames.GetLength(), j=0; i>0; i--, j++)
theMetaModuleImporters += new CMetaModuleImporter
(*inMetaModuleNames[i-1]);
// get an xml document, check its root element name
CXMLDocument XMLDoc (CString(argv[1]), XML_READ, CString("gtkol"));
CXMLElementNode *inXMLNode = XMLDoc.GetRootElement();
// instanciate the specified gtkol hierarchy
CSerialized *inSerialized = CSerialized::Instanciate (inXMLNode);
// check we got an expected CApplication instance and launch it if so !
if (inSerialized -> ClassIs (__metaclass(CApplication)))
static_cast <CApplication *> (inSerialized) -> Run ();
// free the pointers
delete inXMLNode;
delete inSerialized;
}
// so sad...
catch (CException *e)
{
printf ("An exception occured : %s\n", e->GetMessage().Get());
return -1;
}
// unlink the modules and free any resource
for (size_t i=theMetaModuleImporters.GetLength(); i>0; i--) delete *theMetaModuleImporters[i-1];
// ok
return 0;
} |
And with the previous xml dump
sample, the developper would have to
write only two listeners that would be dynamically linked to the
runtime : the referenced
CMainFormListener and
CFileExitMenuItemListener classes that could be written with something like :
#include "cform.h"
//------------------------------------------------------------------------------------
// CMainFormListener
//------------------------------------------------------------------------------------
class CMainFormListener : public CFormListener
{
// called when the form is closed
virtual void OnClose (CObject *)
{
CXMLDocument XMLDoc (CString("./gtkol-dump.xml"), XML_WRITE,
CString("gtkol"));
XMLDoc << CComponent::GetComponent (1L);
}
SECTION_DYNAMIC_METACLASS;
};
DECLARE_DYNAMIC_METACLASS ('_mfm', CMainFormListener, CFormListener);
RESOLVE_DYNAMIC_METACLASS (CMainFormListener);
DECLARE_METAMODULE_EXPORT (CMainFormListener); |
#include "cmenu.h"
//--------------------------------------------------------------------------------------
// CFileExitMenuItemListener
//--------------------------------------------------------------------------------------
class CFileExitMenuItemListener : public CMenuItemListener
{
// called when the menu is clicked
virtual void OnClick (CObject *inSender)
{
static_cast <CForm *> (static_cast <CMenuItem *> (inSender)
-> GetOwner (__metaclass(CForm))) -> Close ();
}
SECTION_DYNAMIC_METACLASS;
};
DECLARE_DYNAMIC_METACLASS ('_cmn', CFileExitMenuItemListener, CMenuItemListener);
RESOLVE_DYNAMIC_METACLASS (CFileExitMenuItemListener);
DECLARE_METAMODULE_EXPORT (CFileExitMenuItemListener); |
Compilation directives :
c++ -Wno-multichar -O2 -rdynamic -o gtkol-runtime `pkg-config --cflags
libgtkol-1.2` gtkol-runtime.c `pkg-config --libs libgtkol-1.2`
c++ -Wno-multichar -O2 -shared -o
cfileexitmenuitemlistener.so `pkg-config --cflags libgtkol-1.2`
cfileexitmenuitemlistener.c
c++ -Wno-multichar -O2 -shared -o cmainformlistener.so `pkg-config --cflags libgtkol-1.2` cmainformlistener.c |