Commit a92ee0f1 authored by Pierre Wieser's avatar Pierre Wieser

NAIDuplicable: rewrite modification check stack

The rationale is double: first is to improve the consistency, second is to remove the iteration
on class hierarchy, adn take advantage of 'call parent class' paradigm.
parent 3ca2b4f7
2011-02-21 Pierre Wieser <pwieser@trychlos.org>
Rewrite modification status check stack
* src/api/na-object-item.h:
* src/core/na-object-item.c (na_object_item_are_equal): Removed function.
* src/api/na-object.h:
* src/core/na-factory-object.c:
* src/core/na-iduplicable.c: Improve comment.
* src/core/na-object.c:
* src/core/na-object-id.c:
* src/core/na-object-menu.c:
* src/core/na-object-action.c:
* src/core/na-object-profile.c: Modification is checked from
NAObject-virtual method instead of NAIFactoryObject interface.
* src/api/na-iduplicable.h:
* src/api/na-iduplicable.c (v_are_equal, v_is_valid): Default to TRUE.
......
......@@ -92,8 +92,6 @@ typedef enum {
GType na_object_item_get_type( void );
gboolean na_object_item_are_equal( const NAObjectItem *a, const NAObjectItem *b );
NAObjectId *na_object_item_get_item ( const NAObjectItem *item, const gchar *id );
gint na_object_item_get_position( const NAObjectItem *item, const NAObjectId *child );
void na_object_item_append_item ( NAObjectItem *item, const NAObjectId *child );
......
......@@ -120,6 +120,9 @@ typedef struct {
*
* Compares the two objects.
*
* When testing for the modification status of an object, @a stands for
* the original object, while @b stands for the duplicated one.
*
* Each derived class should take care of implementing this function
* when relevant. NAObject class will take care of calling this
* function for each class of the hierarchy, starting from topmost
......
......@@ -429,6 +429,8 @@ na_factory_object_are_equal( const NAIFactoryObject *a, const NAIFactoryObject *
a_list = g_object_get_data( G_OBJECT( a ), NA_IFACTORY_OBJECT_PROP_DATA );
b_list = g_object_get_data( G_OBJECT( b ), NA_IFACTORY_OBJECT_PROP_DATA );
g_debug( "%s: a=%p, b=%p", thisfn, ( void * ) a, ( void * ) b );
are_equal = TRUE;
for( ia = a_list ; ia && are_equal ; ia = ia->next ){
......@@ -464,9 +466,7 @@ na_factory_object_are_equal( const NAIFactoryObject *a, const NAIFactoryObject *
}
}
if( are_equal ){
are_equal = v_are_equal( a, b );
}
are_equal &= v_are_equal( a, b );
return( are_equal );
}
......
......@@ -365,7 +365,6 @@ na_iduplicable_check_status( const NAIDuplicable *object )
g_return_if_fail( NA_IS_IDUPLICABLE( object ));
if( st_initialized && !st_finalized ){
g_debug( "%s: object=%p (%s)", thisfn, ( void * ) object, G_OBJECT_TYPE_NAME( object ));
str = get_duplicable_str( object );
......
......@@ -72,14 +72,14 @@ static void instance_set_property( GObject *object, guint property_id, c
static void instance_dispose( GObject *object );
static void instance_finalize( GObject *object );
static void object_copy( NAObject *target, const NAObject *source, gboolean recursive );
static void object_dump( const NAObject *object );
static void object_copy( NAObject *target, const NAObject *source, gboolean recursive );
static gboolean object_are_equal( const NAObject *a, const NAObject *b );
static gboolean object_is_valid( const NAObject *object );
static void ifactory_object_iface_init( NAIFactoryObjectInterface *iface );
static guint ifactory_object_get_version( const NAIFactoryObject *instance );
static NADataGroup *ifactory_object_get_groups( const NAIFactoryObject *instance );
static gboolean ifactory_object_are_equal( const NAIFactoryObject *a, const NAIFactoryObject *b );
static gboolean ifactory_object_is_valid( const NAIFactoryObject *object );
static void ifactory_object_read_done( NAIFactoryObject *instance, const NAIFactoryProvider *reader, void *reader_data, GSList **messages );
static guint ifactory_object_write_start( NAIFactoryObject *instance, const NAIFactoryProvider *writer, void *writer_data, GSList **messages );
......@@ -169,9 +169,9 @@ class_init( NAObjectActionClass *klass )
object_class->finalize = instance_finalize;
naobject_class = NA_OBJECT_CLASS( klass );
naobject_class->copy = object_copy;
naobject_class->dump = object_dump;
naobject_class->are_equal = NULL;
naobject_class->copy = object_copy;
naobject_class->are_equal = object_are_equal;
naobject_class->is_valid = object_is_valid;
klass->private = g_new0( NAObjectActionClassPrivate, 1 );
......@@ -261,19 +261,6 @@ instance_finalize( GObject *object )
}
}
static void
object_copy( NAObject *target, const NAObject *source, gboolean recursive )
{
g_return_if_fail( NA_IS_OBJECT_ACTION( target ));
g_return_if_fail( NA_IS_OBJECT_ACTION( source ));
if( !NA_OBJECT_ACTION( target )->private->dispose_has_run &&
!NA_OBJECT_ACTION( source )->private->dispose_has_run ){
na_factory_object_copy( NA_IFACTORY_OBJECT( target ), NA_IFACTORY_OBJECT( source ));
}
}
static void
object_dump( const NAObject *object )
{
......@@ -297,6 +284,51 @@ object_dump( const NAObject *object )
}
}
static void
object_copy( NAObject *target, const NAObject *source, gboolean recursive )
{
g_return_if_fail( NA_IS_OBJECT_ACTION( target ));
g_return_if_fail( NA_IS_OBJECT_ACTION( source ));
if( !NA_OBJECT_ACTION( target )->private->dispose_has_run &&
!NA_OBJECT_ACTION( source )->private->dispose_has_run ){
na_factory_object_copy( NA_IFACTORY_OBJECT( target ), NA_IFACTORY_OBJECT( source ));
}
}
/*
* @a is the original object
* @b is the current one
*
* Even if they have both the same children list, the current action is
* considered modified as soon as one of its profile is itself modified.
*/
static gboolean
object_are_equal( const NAObject *a, const NAObject *b )
{
static const gchar *thisfn = "na_object_action_object_are_equal";
GList *it;
gboolean are_equal;
g_debug( "%s: a=%p, b=%p", thisfn, ( void * ) a, ( void * ) b );
for( it = na_object_get_items( b ) ; it ; it = it->next ){
if( na_object_is_modified( it->data )){
return( FALSE );
}
}
are_equal = TRUE;
/* chain call to parent class */
if( NA_OBJECT_CLASS( st_parent_class )->are_equal ){
are_equal &= NA_OBJECT_CLASS( st_parent_class )->are_equal( a, b );
}
return( are_equal );
}
static gboolean
object_is_valid( const NAObject *object )
{
......@@ -314,10 +346,7 @@ ifactory_object_iface_init( NAIFactoryObjectInterface *iface )
iface->get_version = ifactory_object_get_version;
iface->get_groups = ifactory_object_get_groups;
iface->copy = NULL;
iface->are_equal = ifactory_object_are_equal;
iface->is_valid = ifactory_object_is_valid;
iface->read_start = NULL;
iface->read_done = ifactory_object_read_done;
iface->write_start = ifactory_object_write_start;
iface->write_done = ifactory_object_write_done;
......@@ -335,29 +364,6 @@ ifactory_object_get_groups( const NAIFactoryObject *instance )
return( action_data_groups );
}
/*
* @a is the original object
* @b is the current one
*
* Even if they have both the same children list, the current action is
* considered modified as soon as one of its profile is itself modified.
*/
static gboolean
ifactory_object_are_equal( const NAIFactoryObject *a, const NAIFactoryObject *b )
{
GList *it;
if( na_object_item_are_equal( NA_OBJECT_ITEM( a ), NA_OBJECT_ITEM( b ))){
for( it = na_object_get_items( b ) ; it ; it = it->next ){
if( na_object_is_modified( it->data )){
return( FALSE );
}
}
}
return( TRUE );
}
static gboolean
ifactory_object_is_valid( const NAIFactoryObject *object )
{
......
......@@ -115,7 +115,6 @@ class_init( NAObjectIdClass *klass )
naobject_class = NA_OBJECT_CLASS( klass );
naobject_class->copy = NULL;
naobject_class->are_equal = NULL;
naobject_class->is_valid = object_is_valid;
klass->private = g_new0( NAObjectIdClassPrivate, 1 );
......
......@@ -62,20 +62,21 @@ struct _NAObjectItemPrivate {
static NAObjectIdClass *st_parent_class = NULL;
static GType register_type( void );
static void class_init( NAObjectItemClass *klass );
static void instance_init( GTypeInstance *instance, gpointer klass );
static void instance_dispose( GObject *object );
static void instance_finalize( GObject *object );
static GType register_type( void );
static void class_init( NAObjectItemClass *klass );
static void instance_init( GTypeInstance *instance, gpointer klass );
static void instance_dispose( GObject *object );
static void instance_finalize( GObject *object );
static void object_copy( NAObject*target, const NAObject *source, gboolean recursive );
static void object_dump( const NAObject *object );
static void object_dump( const NAObject *object );
static void object_copy( NAObject*target, const NAObject *source, gboolean recursive );
static gboolean object_are_equal( const NAObject *a, const NAObject *b );
static gchar *object_id_new_id( const NAObjectId *item, const NAObjectId *new_parent );
static gchar *object_id_new_id( const NAObjectId *item, const NAObjectId *new_parent );
static void count_items_rec( GList *items, gint *menus, gint *actions, gint *profiles, gboolean recurse );
static GSList *get_children_slist( const NAObjectItem *item );
static void copy_children( NAObjectItem *target, const NAObjectItem *source );
static void count_items_rec( GList *items, gint *menus, gint *actions, gint *profiles, gboolean recurse );
static GSList *get_children_slist( const NAObjectItem *item );
static void copy_children( NAObjectItem *target, const NAObjectItem *source );
GType
na_object_item_get_type( void )
......@@ -133,7 +134,7 @@ class_init( NAObjectItemClass *klass )
naobject_class = NA_OBJECT_CLASS( klass );
naobject_class->dump = object_dump;
naobject_class->copy = object_copy;
naobject_class->are_equal = NULL;
naobject_class->are_equal = object_are_equal;
naobject_class->is_valid = NULL;
naobjectid_class = NA_OBJECT_ID_CLASS( klass );
......@@ -200,6 +201,28 @@ instance_finalize( GObject *object )
}
}
static void
object_dump( const NAObject *object )
{
static const gchar *thisfn = "na_object_item_object_dump";
NAObjectItem *item;
g_return_if_fail( NA_IS_OBJECT_ITEM( object ));
item = NA_OBJECT_ITEM( object );
if( !item->private->dispose_has_run ){
g_debug( "| %s: writable=%s", thisfn, item->private->writable ? "True":"False" );
g_debug( "| %s: reason=%u", thisfn, item->private->reason );
/* chain up to the parent class */
if( NA_OBJECT_CLASS( st_parent_class )->dump ){
NA_OBJECT_CLASS( st_parent_class )->dump( object );
}
}
}
static void
object_copy( NAObject *target, const NAObject *source, gboolean recursive )
{
......@@ -238,26 +261,61 @@ object_copy( NAObject *target, const NAObject *source, gboolean recursive )
}
}
static void
object_dump( const NAObject *object )
/*
* object_are_equal:
* @a: the first (original) #NAObjectItem instance.
* @b: the second #NAObjectItem instance.
*
* This function participates to the #na_iduplicable_check_status() stack,
* and is triggered after all comparable elementary data (in #NAIFactoryObject
* sense) have already been successfully compared.
*
* We have to deal here with the subitems: comparing children by their ids
* between @a and @b.
*
* Returns: %TRUE if @a is equal to @b.
*/
static gboolean
object_are_equal( const NAObject *a, const NAObject *b )
{
static const gchar *thisfn = "na_object_item_object_dump";
NAObjectItem *item;
static const gchar *thisfn = "na_object_item_object_are_equal";
gboolean are_equal;
NAObjectItem *origin, *duplicate;
GSList *a_slist, *b_slist;
gchar *a_list, *b_list;
g_return_if_fail( NA_IS_OBJECT_ITEM( object ));
g_return_val_if_fail( NA_IS_OBJECT_ITEM( a ), FALSE );
g_return_val_if_fail( NA_IS_OBJECT_ITEM( b ), FALSE );
item = NA_OBJECT_ITEM( object );
are_equal = FALSE;
origin = NA_OBJECT_ITEM( a );
duplicate = NA_OBJECT_ITEM( b );
if( !item->private->dispose_has_run ){
if( !origin->private->dispose_has_run &&
!duplicate->private->dispose_has_run ){
g_debug( "| %s: writable=%s", thisfn, item->private->writable ? "True":"False" );
g_debug( "| %s: reason=%u", thisfn, item->private->reason );
g_debug( "%s: a=%p, b=%p", thisfn, ( void * ) a, ( void * ) b );
/* chain up to the parent class */
if( NA_OBJECT_CLASS( st_parent_class )->dump ){
NA_OBJECT_CLASS( st_parent_class )->dump( object );
}
a_slist = get_children_slist( origin );
a_list = na_core_utils_slist_join_at_end( a_slist, ";" );
na_core_utils_slist_free( a_slist );
b_slist = get_children_slist( duplicate );
b_list = na_core_utils_slist_join_at_end( b_slist, ";" );
na_core_utils_slist_free( b_slist );
are_equal = ( strcmp( a_list, b_list ) == 0 );
g_free( a_list );
g_free( b_list );
}
/* chain call to parent class */
if( NA_OBJECT_CLASS( st_parent_class )->are_equal ){
are_equal &= NA_OBJECT_CLASS( st_parent_class )->are_equal( a, b );
}
return( are_equal );
}
/*
......@@ -293,58 +351,6 @@ object_id_new_id( const NAObjectId *item, const NAObjectId *new_parent )
return( new_uuid );
}
/**
* na_object_item_are_equal:
* @a: the first (original) #NAObjectItem instance.
* @b: the second #NAObjectItem instance.
*
* This function participates to the #na_iduplicable_check_status() stack,
* and is triggered after all comparable elementary data (in #NAIFactoryObject
* sense) have already been successfully compared.
*
* We have to deal here with the subitems: comparing children by their ids
* between @a and @b.
*
* Note that, when called from na_object_check_status, the status of children
* have already been checked, and so we should be able to rely on them.
*
* Returns: %TRUE if @a is equal to @b.
*
* Since: 2.30
*/
gboolean
na_object_item_are_equal( const NAObjectItem *a, const NAObjectItem *b )
{
/*static const gchar *thisfn = "na_object_item_are_equal";*/
gboolean equal;
GSList *a_slist, *b_slist;
gchar *a_list, *b_list;
g_return_val_if_fail( NA_IS_OBJECT_ITEM( a ), FALSE );
g_return_val_if_fail( NA_IS_OBJECT_ITEM( b ), FALSE );
equal = FALSE;
if( !NA_OBJECT_ITEM( a )->private->dispose_has_run &&
!NA_OBJECT_ITEM( b )->private->dispose_has_run ){
a_slist = get_children_slist( a );
a_list = na_core_utils_slist_join_at_end( a_slist, ";" );
na_core_utils_slist_free( a_slist );
b_slist = get_children_slist( b );
b_list = na_core_utils_slist_join_at_end( b_slist, ";" );
na_core_utils_slist_free( b_slist );
equal = ( strcmp( a_list, b_list ) == 0 );
g_free( a_list );
g_free( b_list );
}
return( equal );
}
/**
* na_object_item_get_item:
* @item: the #NAObjectItem from which we want retrieve a subitem.
......
......@@ -76,7 +76,6 @@ static gboolean object_is_valid( const NAObject *object );
static void ifactory_object_iface_init( NAIFactoryObjectInterface *iface );
static guint ifactory_object_get_version( const NAIFactoryObject *instance );
static NADataGroup *ifactory_object_get_groups( const NAIFactoryObject *instance );
static gboolean ifactory_object_are_equal( const NAIFactoryObject *a, const NAIFactoryObject *b );
static gboolean ifactory_object_is_valid( const NAIFactoryObject *object );
static void ifactory_object_read_done( NAIFactoryObject *instance, const NAIFactoryProvider *reader, void *reader_data, GSList **messages );
static guint ifactory_object_write_start( NAIFactoryObject *instance, const NAIFactoryProvider *writer, void *writer_data, GSList **messages );
......@@ -160,9 +159,8 @@ class_init( NAObjectMenuClass *klass )
object_class->finalize = instance_finalize;
naobject_class = NA_OBJECT_CLASS( klass );
naobject_class->copy = object_copy;
naobject_class->dump = object_dump;
naobject_class->are_equal = NULL;
naobject_class->copy = object_copy;
naobject_class->is_valid = object_is_valid;
klass->private = g_new0( NAObjectMenuClassPrivate, 1 );
......@@ -306,10 +304,7 @@ ifactory_object_iface_init( NAIFactoryObjectInterface *iface )
iface->get_version = ifactory_object_get_version;
iface->get_groups = ifactory_object_get_groups;
iface->copy = NULL;
iface->are_equal = ifactory_object_are_equal;
iface->is_valid = ifactory_object_is_valid;
iface->read_start = NULL;
iface->read_done = ifactory_object_read_done;
iface->write_start = ifactory_object_write_start;
iface->write_done = ifactory_object_write_done;
......@@ -327,12 +322,6 @@ ifactory_object_get_groups( const NAIFactoryObject *instance )
return( menu_data_groups );
}
static gboolean
ifactory_object_are_equal( const NAIFactoryObject *a, const NAIFactoryObject *b )
{
return( na_object_item_are_equal( NA_OBJECT_ITEM( a ), NA_OBJECT_ITEM( b )));
}
static gboolean
ifactory_object_is_valid( const NAIFactoryObject *object )
{
......
......@@ -170,9 +170,8 @@ class_init( NAObjectProfileClass *klass )
object_class->finalize = instance_finalize;
naobject_class = NA_OBJECT_CLASS( klass );
naobject_class->copy = object_copy;
naobject_class->dump = object_dump;
naobject_class->are_equal = NULL;
naobject_class->copy = object_copy;
naobject_class->is_valid = object_is_valid;
naobjectid_class = NA_OBJECT_ID_CLASS( klass );
......@@ -321,12 +320,8 @@ ifactory_object_iface_init( NAIFactoryObjectInterface *iface )
iface->get_version = ifactory_object_get_version;
iface->get_groups = ifactory_object_get_groups;
iface->copy = NULL;
iface->are_equal = NULL;
iface->is_valid = ifactory_object_is_valid;
iface->read_start = NULL;
iface->read_done = ifactory_object_read_done;
iface->write_start = NULL;
iface->write_done = ifactory_object_write_done;
}
......
......@@ -79,12 +79,12 @@ static void object_dump( const NAObject *object );
static void iduplicable_iface_init( NAIDuplicableInterface *iface );
static void iduplicable_copy( NAIDuplicable *target, const NAIDuplicable *source );
static gboolean iduplicable_are_equal( const NAIDuplicable *a, const NAIDuplicable *b );
static gboolean iduplicable_are_equal_iter( GObjectClass *class, const NAObject *a, HierarchyIter *str );
static gboolean iduplicable_is_valid( const NAIDuplicable *object );
static gboolean iduplicable_is_valid_iter( GObjectClass *class, const NAObject *a, HierarchyIter *str );
static void check_status_down_rec( const NAObject *object );
static void check_status_up_rec( const NAObject *object, gboolean was_modified, gboolean was_valid );
static gboolean v_are_equal( const NAObject *a, const NAObject *b );
static gboolean object_copy_iter( GObjectClass *class, const NAObject *source, CopyIter *data );
static void dump_tree( GList *tree, gint level );
static void iter_on_class_hierarchy( const NAObject *object, HierarchyIterFunc pfn, void *user_data );
......@@ -263,7 +263,6 @@ iduplicable_are_equal( const NAIDuplicable *a, const NAIDuplicable *b )
{
static const gchar *thisfn = "na_object_iduplicable_are_equal";
gboolean are_equal;
HierarchyIter *str;
g_return_val_if_fail( NA_IS_OBJECT( a ), FALSE );
g_return_val_if_fail( NA_IS_OBJECT( b ), FALSE );
......@@ -275,36 +274,16 @@ iduplicable_are_equal( const NAIDuplicable *a, const NAIDuplicable *b )
g_debug( "%s: a=%p (%s), b=%p", thisfn, ( void * ) a, G_OBJECT_TYPE_NAME( a ), ( void * ) b );
if( NA_IS_IFACTORY_OBJECT( a )){
are_equal = na_factory_object_are_equal( NA_IFACTORY_OBJECT( a ), NA_IFACTORY_OBJECT( b ));
} else {
str = g_new0( HierarchyIter, 1 );
str->object = NA_OBJECT( b );
str->result = FALSE;
iter_on_class_hierarchy( NA_OBJECT( a ), ( HierarchyIterFunc ) &iduplicable_are_equal_iter, str );
are_equal = str->result;
are_equal = TRUE;
g_free( str );
if( NA_IS_IFACTORY_OBJECT( a )){
are_equal &= na_factory_object_are_equal( NA_IFACTORY_OBJECT( a ), NA_IFACTORY_OBJECT( b ));
}
}
return( are_equal );
}
static gboolean
iduplicable_are_equal_iter( GObjectClass *class, const NAObject *a, HierarchyIter *str )
{
gboolean stop = FALSE;
if( NA_OBJECT_CLASS( class )->are_equal ){
str->result = NA_OBJECT_CLASS( class )->are_equal( a, str->object );
stop = !str->result;
are_equal &= v_are_equal( NA_OBJECT( a ), NA_OBJECT( b ));
}
return( stop );
return( are_equal );
}
static gboolean
......@@ -366,7 +345,19 @@ iduplicable_is_valid_iter( GObjectClass *class, const NAObject *a, HierarchyIter
* na_object_object_check_status_rec( object )
* +- na_iduplicable_check_status( object )
* +- get_origin( object )
* +- modified_status = v_are_equal( origin, object ) -> interface <structfield>NAObjectClass::are_equal</structfield>
* +- modified_status = v_are_equal( origin, object )
* +-> interface <structfield>NAObjectClass::are_equal</structfield>
* which happens to be iduplicable_are_equal( a, b )
* +- v_are_equal( a, b )
* +- NAObjectAction::are_equal()
* +- na_factory_object_are_equal()
* +- check NAObjectActionPrivate data
* +- call parent class
* +- NAObjectItem::are_equal()
* +- check NAObjectItemPrivate data
* +- call parent class
* +- NAObjectId::are_equal()
*
* +- valid_status = v_is_valid( object ) -> interface <structfield>NAObjectClass::is_valid</structfield>
*
* Note that the recursivity is managed here, so that we can be sure
......@@ -439,6 +430,16 @@ check_status_up_rec( const NAObject *object, gboolean was_modified, gboolean was
}
}
static gboolean
v_are_equal( const NAObject *a, const NAObject *b )
{
if( NA_OBJECT_GET_CLASS( a )->are_equal ){
return( NA_OBJECT_GET_CLASS( a )->are_equal( a, b ));
}
return( TRUE );
}
/**
* na_object_object_copy:
* @target: the target #NAObject -derived object.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment