Flip BabyStep Tutorial

 

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
  1. include the class...
  2. ... that will automatically make a flip root object
  3. 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)
{
}
  1. before declaring our own classes, we need to make flip declare all its internal types such as flip::Int64 , flip::Float64 , etc.
  2. set a name for this class
  3. set the current version of the document format
  4. tell the class manager to finally declare the class to flip
  5. 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
  1. add a setter for the point. this will make a flip transaction that will change the two members.
  2. this function will be used when observing the document, to know if the members changed
  3. add a getter for the point
  4. the two flip attributes for this class, in a floating point format
  5. 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 :

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)
{
}
  1. add the two members to our root class
  2. 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.
}
  1. prepare the undo system
  2. start a flip transaction. if a transaction is always started, abort the operation
  3. set the values
  4. set a name for this transaction for the undo system
  5. 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