BabyStep 2: Adding the Root Object
This chapter will be our second modification of the code exposed in BabyStep 0: Starting Point . Now that a flip document is bound to our application, we will now add the root model object to it.
Making a Flip Class
ModelRoot.h
A flip document has one and one only object which defines the model root. The following will describe how to code this object.
ListingModifying ModelRoot.h
/*\\\ INCLUDE FILES \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/ |
#include "ohm/flip/RootBase.h" // 1. |
class ModelRoot |
: public ohm::flip::RootBase // 2. |
{ |
/*\\\ PUBLIC \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/ |
public: |
static void declare (); // 3. |
ModelRoot (ohm::flip::DocumentBase & document); |
virtual ~ModelRoot (); |
}; // class ModelRoot |
- include the class...
- ... that will automatically make a flip root object
- flip is a declarative framework, flip classes need to be declared before they can be used
ModelRoot.cpp
Then we are going to change the definition file to reflect the changes we made in the header.
ListingModifying ModelRoot.cpp
/*\\\ INCLUDE FILES \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/ |
#include "ModelRoot.h" |
#include "ohm/flip/ClassDescription.h" |
/*\\\ PUBLIC \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/ |
void ModelRoot::declare () |
{ |
using namespace ohm::flip; |
ClassDescManager::use_instance ().declare_basic_types (); // 1. |
ClassDescription <ModelRoot>::use ().set_name ("ModelRoot"); // 2. |
ClassDescription <ModelRoot>::use ().enable_root ("v1.0"); // 3. |
ClassDescManager::declare (ClassDescription <ModelRoot>::use ()); // 4. |
ClassDescManager::use_instance ().post_check (); // 5. |
} |
ModelRoot::ModelRoot (ohm::flip::DocumentBase & document) |
: ohm::flip::RootBase (document) |
{ |
} |
- before declaring our own classes, we need to make flip declare all its internal types such as flip::Int64 , flip::Float64 , etc.
- set a name for this class
- set the current version of the document format
- tell the class manager to finally declare the class to flip
- after all classes have been declared, let flip make an internal consistency check
Now that a root object has been added to the document, we are going to add some attributes to the root object to make it more useful.
Adding Objects to a Flip Class
ModelRoot.h
ListingModifying ModelRoot.h
/*\\\ INCLUDE FILES \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/ |
#include "ohm/flip/RootBase.h" |
#include "ohm/flip/Float64.h" |
#include "ohm/flip/TxSessionGuard.h" |
class ModelRoot |
: public ohm::flip::RootBase |
{ |
/*\\\ PUBLIC \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/ |
public: |
static void declare (); |
ModelRoot (ohm::flip::DocumentBase & document); |
virtual ~ModelRoot (); |
void set_point (float x, float y); // 1. |
bool point_changed () const; // 2. |
float get_point_x () const; // 3. |
float get_point_y () const; |
/*\\\ PRIVATE \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/ |
private: |
ohm::flip::Float64 // 4. |
_point_x; |
ohm::flip::Float64 |
_point_y; |
ohm::flip::TxSessionGuard |
_tx_session_guard; // 5. |
}; // class ModelRoot |
- add a setter for the point. this will make a flip transaction that will change the two members.
- this function will be used when observing the document, to know if the members changed
- add a getter for the point
- the two flip attributes for this class, in a floating point format
- a guard for the class that ensures that we are not trying to make two concurrent flip transactions and also gives a convenient way to bind with the undo system
flip comes with a bunch of different basic types, namely :
- flip::Bool that represents a boolean object
- flip::Int64 that represents an 64 bits integer object
- flip::Float64 that represents an 64 bits floating point object
- flip::Enum that represents a named type
- flip::Blob that represents an opaque blob of data
- flip::Cue that represents a way to signal non persistent data between clients
- flip::ObjectRef that represents a pointer to another flip object
- flip::Array that represented an ordered container
- flip::Collection that represented an unordered container
ModelRoot.cpp
ListingModifying ModelRoot.cpp / ModelRoot::declare and constructor
/*\\\ INCLUDE FILES \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/ |
#include "ModelRoot.h" |
#include "ohm/flip/ClassDescription.h" |
/*\\\ PUBLIC \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/ |
void ModelRoot::declare () |
{ |
using namespace ohm::flip; |
ClassDescManager::use_instance ().declare_basic_types (); |
ClassDescription <ModelRoot>::use ().set_name ("ModelRoot"); |
ClassDescription <ModelRoot>::use ().push_var_desc (&ModelRoot::_point_x, "_point_x"); // 1. |
ClassDescription <ModelRoot>::use ().push_var_desc (&ModelRoot::_point_y, "_point_y"); |
ClassDescription <ModelRoot>::use ().enable_root ("v1.0"); |
ClassDescManager::declare (ClassDescription <ModelRoot>::use ()); |
ClassDescManager::use_instance ().post_check (); |
} |
ModelRoot::ModelRoot (ohm::flip::DocumentBase & document) |
: flip::RootBase (document) |
, _point_x (document) // 2. |
, _point_y (document) |
, _tx_session_guard (document) |
{ |
} |
- add the two members to our root class
- bind everything to the flip document
ListingModifying ModelRoot.cpp / ModelRoot::set_point
void ModelRoot::set_point (float x, float y) |
{ |
_tx_session_guard.prepare_record (use_scribe ()); // 1. |
if (!_tx_session_guard.start ()) return; // 2. |
_point_x = x; // 3. |
_point_y = y; |
set_scribe_metadata ("Change Point"); // 4. |
_tx_session_guard.commit (); // 5. |
} |
- prepare the undo system
- start a flip transaction. if a transaction is always started, abort the operation
- set the values
- set a name for this transaction for the undo system
- commit the transaction
point_changed and getters implementation are straight forward and listed below.
ListingModifying ModelRoot.cpp / ModelRoot::point_changed and getters
bool ModelRoot::point_changed () const |
{ |
return _point_x.did_value_change () || _point_y.did_value_change (); |
} |
float ModelRoot::get_point_x () const |
{ |
return _point_x; |
} |
float ModelRoot::get_point_y () const |
{ |
return _point_y; |
} |
At this point, we have a fully functionnal model. We can call set_point and this will actually change the document to reflect the change. Now we need to be able to know and display document changes, which is done in the observer, here in the BabystepGui class