Guiliani  Version 2.5 revision 6773 (build 33)
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
DataPool

The Guiliani DataPool Component for generic binding of UI Elements to arbitrary data sources. More...

Classes

class  CDataPoolConnector
 Connects a GUIObject to the DataPool. DataPoolConnectors are used to observe values within the DataPool. GUIObjects, which are observing entries in the datapool must have a DataPoolConnector. A DataPoolConnector will be notified of changes to the DataPool via the OnNotification(DataPoolEntry&) Interface, and will notify its observers via the NotifyObservers (const CGUIValue&, const CGUIObject* const, const eC_UInt, const eC_UInt) interface if the value of its GUIObject changes. More...
 
class  CDataPoolEntry
 A single entry in the DataPool. The DataPoolEntry class represents a single entry (unique id + a value/array of values) within the DataPool. DataPoolEntries are observed by DataPoolConnectors and will be notified of changes to the DataPoolConnector via the OnNotification(value, object, x, y) interface. In the opposite direction, a DataPooolEntry notifies its observers by calling their OnNotification(DataPoolEntry) interfaces. More...
 
class  CGUIDataPool
 

Detailed Description

The Guiliani DataPool Component for generic binding of UI Elements to arbitrary data sources.

The DataPool stores application specific data and allows objects within the user interface to get notified when data changes, for which they have registered themselves as observers.

The DataPool is meant to work as an interface between the GUI and the underlying application and is thus designed to be threadsafe. The CGUIDataPool::Set() and CGUIDataPool::Get() methods may therefore be accessed from both the UI-Thread, and application threads.

Attention
Note that the ONLY threadsafe APIs are:
  • Set(const DataPoolResource_t eDataID, CGUIValue kValue, const eC_UInt uiX, const eC_UInt uiY)
  • Get(const DataPoolResource_t eDataID, CGUIValue& kValue, const eC_UInt uiX, const eC_UInt uiY) Do NOT call any other APIs from outside the Guiliani thread!

The following example shows how an object gets registered to an entry within the DataPool. In this example a DataPool entry named ID_OF_DATAPOOL_RESOURCE (which has been defined in UserDataPoolResource.h) gets connected to the object pkSlider. Note that this will always result in a two-way dependency, which means that the object within the GUI will get notified when the DataPool changes, but changing the GUI object's value (e.g. by dragging the slider) will also update the value within the DataPool.

// Create an object
CGUISlider* pkSlider = new CGUISlider(this, eC_FromInt(0), eC_FromInt(0),
eC_FromInt(300), eC_FromInt(20),
0, 0, 100, 10,
CGUIRange::BASE_AT_MINIMUM,
CGUIBaseSlider::SLD_HORIZONTAL,
OBJ_MY_SLIDER);
// Register to entry within the DataPool
CGUIDataPool::Register(ID_OF_DATAPOOL_RESOURCE, pkSlider);

Using pointers is not possible when streaming. In this case, use the CGUIDataPool::AutoRegister() method instead. It registers an Object Handle with an entry of the DataPool. If an object with this ID is constructed (or streamed) it will automatically be registered within the DataPool.

CGUIDataPool::AutoRegister(ID_OF_DATAPOOL_RESOURCE, OBJ_MY_SLIDER);

Manually changing a value within the DataPool (e.g. from application code) can be done via the CGUIDataPool::Set() interface.

CGUIDataPool::Set(ID_OF_DATAPOOL_RESOURCE, "New Value");

Implementing a custom DataPoolConnector

The following example code demonstrates how to implement a custom DataPoolConnector, which observes a value within the DataPool. Its OnNotification() method will be called whenever the associated value within the DataPool gets updated.

// A basic customized DataPoolConnector example
class MyDataPoolConnector : public CDataPoolConnector
{
public:
MyDataPoolConnector(): CDataPoolConnector() {};
// Called by the DataPool if an entry has changed
virtual void OnNotification(CDataPoolEntry& kObservedValue)
{
GUILOGMESSAGE("Received an update from the DataPool. New value: " + kObservedValue.Get().ToString() + "\n");
}
};
// Usage example:
MyDataPoolConnector* pMyDataPoolConnector = new MyDataPoolConnector();
CGUIDataPool::Register(ID_OF_DATAPOOL_RESOURCE, pMyDataPoolConnector);

Implementing a simple callback function

It is possible to register callback functions to entries within the DataPool, which will automatically be called when their corresponding value gets changed. To work as a callback your function must accept a CDataPoolEntry& as a paramter and have void as return value. The DataPoolEntry parameter will contain the observed DataPoolEntry from which you can extract its current value.

// A simple callback function, which gets called when an entry within the DataPool changes
void MyDataPoolCallback(CDataPoolEntry& kDataPoolEntry)
{
GUILOGMESSAGE(" MyDataPoolCallback called. New value: " + kDataPoolEntry.Get().ToString() + "\n");
}
// Usage example:
CGUIDataPool::Register(DATA_ENTRY_1, &MyDataPoolCallback);

Implementing controls with custom DataPool-bindings

The following is an example implementation of a customized Image-control, which will display one of three defineable images with regard of the value received from the DataPool.

It inherits from the standard CGUIImage base class, but extends it by a custom SetValue() method, which implements the communication with the DataPool.

The SetValue() implementation will interpret the value received from the DataPool as an integer. If the value lies in the range of 0-49 it will display the "GreenImage" supplied during construction. For values in the range of 50-74 it will display the "YellowImage", and for all others it will display the "RedImage".

#include "GUIImage.h"
class CustomImage : public CGUIImage
{
public:
CustomImage (
CGUICompositeObject* const pkParent,
const eC_Value& vX,
const eC_Value& vY,
const ImageResource_t& eGreenImageID,
const ImageResource_t& eYellowImageID,
const ImageResource_t& eRedImageID,
const ObjectHandle_t& eID = NO_HANDLE)
: CGUIImage( pkParent, vX, vY, eGreenImageID, eID),
m_eGreenImage(eGreenImageID), m_eYellowImage(eYellowImageID), m_eRedImage(eRedImageID)
{}
virtual eC_Bool SetValue(CDataPoolEntry& rkValue)
{
// If the numerical value received by the DataPool is smaller than 50, show the "green image"
if (rkValue.Get().ToInt() < 50)
{
SetImage(m_eGreenImage);
}
// If the numerical value received by the DataPool is between 50 and 75, show the "yellow image"
else if (rkValue.Get().ToInt() < 75)
{
SetImage(m_eYellowImage);
}
// in all other cases show the "red image"
else
{
SetImage(m_eRedImage);
}
return true;
}
protected:
ImageResource_t m_eGreenImage;
ImageResource_t m_eYellowImage;
ImageResource_t m_eRedImage;
};

Implementing custom DataPoolEntries

In some ocassions it will be necessary to replace the standard DataPoolEntries within the DataPool with customized code, which does for instance access an external database to retrieve the requested data. For this purpose it is possible to..

  1. inherit from DataPoolEntry,
  2. add the specific code to the Get() method which is called whenever an observer of the DataPool wishes to retrieve the current value of this entry within the DataPool
  3. and assign the customized DataPoolEntry to the DataPool via CGUIDataPool::SetDataPoolEntry

The following example code gives a skeleton implementation of a customized DataPoolEntry.

// Customized DataPoolEntry type.
// This could e.g. access a database in Get(...) to retrieve the requested data
class MyDataPoolEntry : public CDataPoolEntry
{
public:
MyDataPoolEntry()
{
// Choose initial dimension for data storage of 4x1 values
}
void Set(const CGUIValue& kValue, const eC_UInt uiX, const eC_UInt uiY)
{
// Check if value has really changed
const CGUIValue& kOldValue = Get(uiX, uiY);
// Do only trigger notifications and update values if the value has actually changed.
// Note: Even an identical value may trigger a notification when the datatypes are different!
if (kOldValue.GetType() != kValue.GetType() ||
kOldValue != kValue)
{
// TODO: Custom Code for setting the new value goes here...
// or just call CDataPoolEntry::Set(kValue, uiX, uiY);
// Notify the DataPool about the changed value
}
}
const CGUIValue& Get(const eC_UInt uiX = 0, const eC_UInt uiY = 0)
{
// Custom Data retrieval code goes here....
// or just return CDataPoolEntry::Get(uiX, uiY);
}
};
// Assign a custom DataPoolEntry to the entry named ID_OF_DATAPOOL_RESOURCE within the DataPool
CGUIDataPool::SetDataPoolEntry(ID_OF_DATAPOOL_RESOURCE, new MyDataPoolEntry());

Using arrays within the DataPool

A single DataPool entry can store more than a single CGUIValue. If you wish to store multiple values you can access these via the x,y parameters of the CGUIDataPool::Set() and CGUIDataPool::Get() interfaces. Most standard GUI elements will only make use of the first value (=which is the one at indices 0,0). But some - such as ListBoxes - will automatically know how to deal with arrays.

The following example shows how to set / get arrays of data in the DataPool:

// Set maximum number of values for ID_OF_DATAPOOL_RESOURCE
CDataPoolEntry* pkEntry;
CGUIDataPool::Get(ID_OF_DATAPOOL_RESOURCE, &pkEntry);
if (pkEntry) pkEntry->SetQuantity(3,1);
// This sets the string "Last Mouse Position" into the first value (=index 0,0) of ID_OF_DATAPOOL_RESOURCE
// and the mouse X/Y positions at indices (1,0) and (2,0)
CGUIDataPool::Set(ID_OF_DATAPOOL_RESOURCE, "Last Mouse Position", 0,0);
CGUIDataPool::Set(ID_OF_DATAPOOL_RESOURCE, uiMouseX, 1,0);
CGUIDataPool::Set(ID_OF_DATAPOOL_RESOURCE, uiMouseY, 2,0);
// This shows these values in a Listbox
CGUIListBox* pListBox = new CGUIListBox(this, eC_FromInt(10), eC_FromInt(0), eC_FromInt(200), eC_FromInt(60));
CGUIDataPool::Register(ID_OF_DATAPOOL_RESOURCE, pListBox);