Commit 08f65b7a authored by Pierre Wieser's avatar Pierre Wieser

NAIDuplicable: rewrite validity check stack

parent a92ee0f1
2011-02-21 Pierre Wieser <pwieser@trychlos.org>
Rewrite validity status check stack
* src/api/na-icontext.h:
* src/core/na-icontext.c (na_icontext_are_equal): New function.
* src/core/na-factory-object.c (na_factory_object_is_valid):
* src/core/na-object.c (iduplicable_is_valid):
* src/core/na-object-id.c (object_is_valid):
* src/core/na-object-id-factory.c:
* src/core/na-object-item.c (object_is_valid):
* src/core/na-object-action.c (object_is_valid):
* src/core/na-object-profile.c (object_is_valid):
* src/core/na-object-menu.c (object_is_valid): Updated accordingly.
Rewrite modification status check stack
* src/api/na-object-item.h:
......
......@@ -95,6 +95,7 @@ typedef struct {
GType na_icontext_get_type( void );
gboolean na_icontext_are_equal ( const NAIContext *a, const NAIContext *b );
gboolean na_icontext_is_candidate ( const NAIContext *context, guint target, GList *selection );
gboolean na_icontext_is_valid ( const NAIContext *context );
......
......@@ -492,7 +492,7 @@ na_factory_object_is_valid( const NAIFactoryObject *object )
list = g_object_get_data( G_OBJECT( object ), NA_IFACTORY_OBJECT_PROP_DATA );
is_valid = TRUE;
/* mndatory data must be set
/* mandatory data must be set
*/
NafoValidIter iter_data;
iter_data.object = ( NAIFactoryObject * ) object;
......@@ -508,9 +508,7 @@ na_factory_object_is_valid( const NAIFactoryObject *object )
is_valid = na_data_boxed_is_valid( NA_DATA_BOXED( iv->data ));
}
if( is_valid ){
is_valid = v_is_valid( object );
}
is_valid &= v_is_valid( object );
return( is_valid );
}
......@@ -862,15 +860,11 @@ v_copy( NAIFactoryObject *target, const NAIFactoryObject *source )
static gboolean
v_are_equal( const NAIFactoryObject *a, const NAIFactoryObject *b )
{
gboolean are_equal;
are_equal = TRUE;
if( NA_IFACTORY_OBJECT_GET_INTERFACE( a )->are_equal ){
are_equal = NA_IFACTORY_OBJECT_GET_INTERFACE( a )->are_equal( a, b );
return( NA_IFACTORY_OBJECT_GET_INTERFACE( a )->are_equal( a, b ));
}
return( are_equal );
return( TRUE );
}
static gboolean
......@@ -880,7 +874,7 @@ v_is_valid( const NAIFactoryObject *object )
return( NA_IFACTORY_OBJECT_GET_INTERFACE( object )->is_valid( object ));
}
return( FALSE );
return( TRUE );
}
static void
......
......@@ -167,6 +167,31 @@ interface_base_finalize( NAIContextInterface *klass )
}
}
/**
* na_icontext_are_equal:
* @a: the (original) #NAIContext context.
* @b: the (duplicated) #NAIContext context to be checked.
*
* Returns: %TRUE if this @a and @b are equal, %FALSE else.
*
* Since: 3.1.0
*/
gboolean
na_icontext_are_equal( const NAIContext *a, const NAIContext *b )
{
static const gchar *thisfn = "na_icontext_are_equal";
gboolean are_equal;
g_return_val_if_fail( NA_IS_ICONTEXT( a ), FALSE );
g_return_val_if_fail( NA_IS_ICONTEXT( b ), FALSE );
g_debug( "%s: a=%p, b=%p", thisfn, ( void * ) a, ( void * ) b );
are_equal = TRUE;
return( are_equal );
}
/**
* na_icontext_is_candidate:
* @context: a #NAIContext to be checked.
......@@ -221,7 +246,7 @@ na_icontext_is_candidate( const NAIContext *context, guint target, GList *select
/**
* na_icontext_is_valid:
* @context: the #NAObjectProfile to be checked.
* @context: the #NAIContext to be checked.
*
* Returns: %TRUE if this @context is valid, %FALSE else.
*
......@@ -236,10 +261,13 @@ na_icontext_is_candidate( const NAIContext *context, guint target, GList *select
gboolean
na_icontext_is_valid( const NAIContext *context )
{
static const gchar *thisfn = "na_icontext_is_valid";
gboolean is_valid;
g_return_val_if_fail( NA_IS_ICONTEXT( context ), FALSE );
g_debug( "%s: context=%p (%s)", thisfn, ( void * ) context, G_OBJECT_TYPE_NAME( context ));
is_valid =
is_valid_basenames( context ) &&
is_valid_mimetypes( context ) &&
......
......@@ -80,7 +80,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_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 );
static guint ifactory_object_write_done( NAIFactoryObject *instance, const NAIFactoryProvider *writer, void *writer_data, GSList **messages );
......@@ -93,7 +92,6 @@ static void read_done_deals_with_toolbar_label( NAIFactoryObject *instan
static guint write_done_write_profiles( NAIFactoryObject *instance, const NAIFactoryProvider *writer, void *writer_data, GSList **messages );
static gboolean object_object_is_valid( const NAObjectAction *action );
static gboolean is_valid_label( const NAObjectAction *action );
static gboolean is_valid_toolbar_label( const NAObjectAction *action );
......@@ -332,9 +330,39 @@ object_are_equal( const NAObject *a, const NAObject *b )
static gboolean
object_is_valid( const NAObject *object )
{
static const gchar *thisfn = "na_object_action_object_is_valid";
gboolean is_valid;
NAObjectAction *action;
g_return_val_if_fail( NA_IS_OBJECT_ACTION( object ), FALSE );
return( object_object_is_valid( NA_OBJECT_ACTION( object )));
is_valid = FALSE;
action = NA_OBJECT_ACTION( object );
if( !action->private->dispose_has_run ){
g_debug( "%s: action=%p (%s)", thisfn, ( void * ) action, G_OBJECT_TYPE_NAME( action ));
is_valid = TRUE;
if( na_object_is_target_toolbar( action )){
is_valid &= is_valid_toolbar_label( action );
}
if( na_object_is_target_selection( action ) || na_object_is_target_location( action )){
is_valid &= is_valid_label( action );
}
if( !is_valid ){
na_object_debug_invalid( action, "no valid profile" );
}
}
/* chain up to the parent class */
if( NA_OBJECT_CLASS( st_parent_class )->is_valid ){
is_valid &= NA_OBJECT_CLASS( st_parent_class )->is_valid( object );
}
return( is_valid );
}
static void
......@@ -346,7 +374,6 @@ ifactory_object_iface_init( NAIFactoryObjectInterface *iface )
iface->get_version = ifactory_object_get_version;
iface->get_groups = ifactory_object_get_groups;
iface->is_valid = ifactory_object_is_valid;
iface->read_done = ifactory_object_read_done;
iface->write_start = ifactory_object_write_start;
iface->write_done = ifactory_object_write_done;
......@@ -364,14 +391,6 @@ ifactory_object_get_groups( const NAIFactoryObject *instance )
return( action_data_groups );
}
static gboolean
ifactory_object_is_valid( const NAIFactoryObject *object )
{
g_return_val_if_fail( NA_IS_OBJECT_ACTION( object ), FALSE );
return( object_object_is_valid( NA_OBJECT_ACTION( object )));
}
/*
* at this time, we don't yet have read the profiles as this will be
* done in ifactory_provider_read_done - we so just be able to deal with
......@@ -561,49 +580,6 @@ write_done_write_profiles( NAIFactoryObject *instance, const NAIFactoryProvider
return( code );
}
static gboolean
object_object_is_valid( const NAObjectAction *action )
{
gboolean is_valid;
GList *profiles, *ip;
gint valid_profiles;
is_valid = FALSE;
if( !action->private->dispose_has_run ){
is_valid = TRUE;
if( is_valid ){
if( na_object_is_target_toolbar( action )){
is_valid = is_valid_toolbar_label( action );
}
}
if( is_valid ){
if( na_object_is_target_selection( action )){
is_valid = is_valid_label( action );
}
}
if( is_valid ){
valid_profiles = 0;
profiles = na_object_get_items( action );
for( ip = profiles ; ip && !valid_profiles ; ip = ip->next ){
if( na_object_is_valid( ip->data )){
valid_profiles += 1;
}
}
is_valid = ( valid_profiles > 0 );
if( !is_valid ){
na_object_debug_invalid( action, "no valid profile" );
}
}
}
return( is_valid );
}
static gboolean
is_valid_label( const NAObjectAction *action )
{
......
......@@ -54,7 +54,7 @@ NADataDef data_def_id [] = {
FALSE,
TRUE,
TRUE,
TRUE,
TRUE, /* mandatory */
FALSE,
NULL,
NULL,
......
......@@ -57,8 +57,6 @@ static void instance_init( GTypeInstance *instance, gpointer klass );
static void instance_dispose( GObject *object );
static void instance_finalize( GObject *object );
static gboolean object_is_valid( const NAObject *object );
static gchar *v_new_id( const NAObjectId *object, const NAObjectId *new_parent );
GType
......@@ -103,7 +101,6 @@ class_init( NAObjectIdClass *klass )
{
static const gchar *thisfn = "na_object_id_class_init";
GObjectClass *object_class;
NAObjectClass *naobject_class;
g_debug( "%s: klass=%p", thisfn, ( void * ) klass );
......@@ -113,10 +110,6 @@ class_init( NAObjectIdClass *klass )
object_class->dispose = instance_dispose;
object_class->finalize = instance_finalize;
naobject_class = NA_OBJECT_CLASS( klass );
naobject_class->copy = NULL;
naobject_class->is_valid = object_is_valid;
klass->private = g_new0( NAObjectIdClassPrivate, 1 );
}
......@@ -187,26 +180,6 @@ instance_finalize( GObject *object )
}
}
/*
* a NAObjectId is valid if it has a non-null id
*/
static gboolean
object_is_valid( const NAObject *object )
{
gboolean is_valid;
gchar *id;
is_valid = TRUE;
if( is_valid ){
id = na_object_get_id( object );
is_valid = ( id != NULL && strlen( id ) > 0 );
g_free( id );
}
return( is_valid );
}
/**
* na_object_id_sort_alpha_asc:
* @a: first #NAObjectId.
......
......@@ -71,6 +71,7 @@ static void instance_finalize( GObject *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 gboolean object_is_valid( const NAObject *object );
static gchar *object_id_new_id( const NAObjectId *item, const NAObjectId *new_parent );
......@@ -135,7 +136,7 @@ class_init( NAObjectItemClass *klass )
naobject_class->dump = object_dump;
naobject_class->copy = object_copy;
naobject_class->are_equal = object_are_equal;
naobject_class->is_valid = NULL;
naobject_class->is_valid = object_is_valid;
naobjectid_class = NA_OBJECT_ID_CLASS( klass );
naobjectid_class->new_id = object_id_new_id;
......@@ -318,6 +319,51 @@ object_are_equal( const NAObject *a, const NAObject *b )
return( are_equal );
}
/*
* must have at least one valid subitem
*/
static gboolean
object_is_valid( const NAObject *object )
{
static const gchar *thisfn = "na_object_item_object_is_valid";
gboolean is_valid;
NAObjectItem *item;
GList *children, *ic;
gint valid_children;
g_return_val_if_fail( NA_IS_OBJECT_ITEM( object ), FALSE );
is_valid = FALSE;
item = NA_OBJECT_ITEM( object );
if( !item->private->dispose_has_run ){
g_debug( "%s: item=%p (%s)", thisfn, ( void * ) item, G_OBJECT_TYPE_NAME( item ));
is_valid = TRUE;
valid_children = 0;
children = na_object_get_items( item );
for( ic = children ; ic && !valid_children ; ic = ic->next ){
if( na_object_is_valid( ic->data )){
valid_children += 1;
}
}
is_valid &= ( valid_children > 0 );
if( !is_valid ){
na_object_debug_invalid( item, "no valid child" );
}
}
/* chain up to the parent class */
if( NA_OBJECT_CLASS( st_parent_class )->is_valid ){
is_valid &= NA_OBJECT_CLASS( st_parent_class )->is_valid( object );
}
return( is_valid );
}
/*
* new_parent is not relevant when allocating a new identifier for an
* action or a menu ; it may safely be left as NULL though there is no
......
......@@ -71,12 +71,10 @@ 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 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_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 );
static guint ifactory_object_write_done( NAIFactoryObject *instance, const NAIFactoryProvider *writer, void *writer_data, GSList **messages );
......@@ -84,9 +82,6 @@ static guint ifactory_object_write_done( NAIFactoryObject *instance, cons
static void icontext_iface_init( NAIContextInterface *iface );
static gboolean icontext_is_candidate( NAIContext *object, guint target, GList *selection );
static gboolean menu_is_valid( const NAObjectMenu *menu );
static gboolean is_valid_label( const NAObjectMenu *menu );
GType
na_object_menu_get_type( void )
{
......@@ -161,7 +156,6 @@ class_init( NAObjectMenuClass *klass )
naobject_class = NA_OBJECT_CLASS( klass );
naobject_class->dump = object_dump;
naobject_class->copy = object_copy;
naobject_class->is_valid = object_is_valid;
klass->private = g_new0( NAObjectMenuClassPrivate, 1 );
......@@ -287,14 +281,6 @@ object_dump( const NAObject *object )
}
}
static gboolean
object_is_valid( const NAObject *object )
{
g_return_val_if_fail( NA_IS_OBJECT_MENU( object ), FALSE );
return( menu_is_valid( NA_OBJECT_MENU( object )));
}
static void
ifactory_object_iface_init( NAIFactoryObjectInterface *iface )
{
......@@ -304,7 +290,6 @@ ifactory_object_iface_init( NAIFactoryObjectInterface *iface )
iface->get_version = ifactory_object_get_version;
iface->get_groups = ifactory_object_get_groups;
iface->is_valid = ifactory_object_is_valid;
iface->read_done = ifactory_object_read_done;
iface->write_start = ifactory_object_write_start;
iface->write_done = ifactory_object_write_done;
......@@ -322,14 +307,6 @@ ifactory_object_get_groups( const NAIFactoryObject *instance )
return( menu_data_groups );
}
static gboolean
ifactory_object_is_valid( const NAIFactoryObject *object )
{
g_return_val_if_fail( NA_IS_OBJECT_MENU( object ), FALSE );
return( menu_is_valid( NA_OBJECT_MENU( object )));
}
static void
ifactory_object_read_done( NAIFactoryObject *instance, const NAIFactoryProvider *reader, void *reader_data, GSList **messages )
{
......@@ -374,58 +351,6 @@ icontext_is_candidate( NAIContext *object, guint target, GList *selection )
return( TRUE );
}
static gboolean
menu_is_valid( const NAObjectMenu *menu )
{
gboolean is_valid;
gint valid_subitems;
GList *subitems, *ip;
is_valid = FALSE;
if( !menu->private->dispose_has_run ){
is_valid = TRUE;
if( is_valid ){
is_valid = is_valid_label( menu );
}
if( is_valid ){
valid_subitems = 0;
subitems = na_object_get_items( menu );
for( ip = subitems ; ip && !valid_subitems ; ip = ip->next ){
if( na_object_is_valid( ip->data )){
valid_subitems += 1;
}
}
is_valid = ( valid_subitems > 0 );
if( !is_valid ){
na_object_debug_invalid( menu, "no valid subitem" );
}
}
}
return( is_valid );
}
static gboolean
is_valid_label( const NAObjectMenu *menu )
{
gboolean is_valid;
gchar *label;
label = na_object_get_label( menu );
is_valid = ( label && g_utf8_strlen( label, -1 ) > 0 );
g_free( label );
if( !is_valid ){
na_object_debug_invalid( menu, "label" );
}
return( is_valid );
}
/**
* na_object_menu_new:
*
......
......@@ -80,7 +80,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_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_done( NAIFactoryObject *instance, const NAIFactoryProvider *writer, void *writer_data, GSList **messages );
......@@ -93,7 +92,6 @@ static gboolean convert_pre_v3_multiple( NAObjectProfile *profile );
static gboolean convert_pre_v3_isfiledir( NAObjectProfile *profile );
static void read_done_ending( NAObjectProfile *profile );
static void split_path_parameters( NAObjectProfile *profile );
static gboolean profile_is_valid( const NAObjectProfile *profile );
static gboolean is_valid_path_parameters( const NAObjectProfile *profile );
static gchar *object_id_new_id( const NAObjectId *item, const NAObjectId *new_parent );
......@@ -306,9 +304,27 @@ object_dump( const NAObject *object )
static gboolean
object_is_valid( const NAObject *object )
{
static const gchar *thisfn = "na_object_profile_object_is_valid";
gboolean is_valid;
NAObjectProfile *profile;
g_return_val_if_fail( NA_IS_OBJECT_PROFILE( object ), FALSE );
return( profile_is_valid( NA_OBJECT_PROFILE( object )));
is_valid = FALSE;
profile = NA_OBJECT_PROFILE( object );
if( !profile->private->dispose_has_run ){
g_debug( "%s: profile=%p (%s)", thisfn, ( void * ) profile, G_OBJECT_TYPE_NAME( profile ));
is_valid = is_valid_path_parameters( profile );
}
/* chain up to the parent class */
if( NA_OBJECT_CLASS( st_parent_class )->is_valid ){
is_valid &= NA_OBJECT_CLASS( st_parent_class )->is_valid( object );
}
return( is_valid );
}
static void
......@@ -320,7 +336,6 @@ ifactory_object_iface_init( NAIFactoryObjectInterface *iface )
iface->get_version = ifactory_object_get_version;
iface->get_groups = ifactory_object_get_groups;
iface->is_valid = ifactory_object_is_valid;
iface->read_done = ifactory_object_read_done;
iface->write_done = ifactory_object_write_done;
}
......@@ -337,18 +352,6 @@ ifactory_object_get_groups( const NAIFactoryObject *instance )
return( profile_data_groups );
}
static gboolean
ifactory_object_is_valid( const NAIFactoryObject *object )
{
static const gchar *thisfn = "na_object_profile_ifactory_object_is_valid";
g_return_val_if_fail( NA_IS_OBJECT_PROFILE( object ), FALSE );
g_debug( "%s: object=%p (%s)", thisfn, ( void * ) object, G_OBJECT_TYPE_NAME( object ));
return( profile_is_valid( NA_OBJECT_PROFILE( object )));
}
static void
ifactory_object_read_done( NAIFactoryObject *instance, const NAIFactoryProvider *reader, void *reader_data, GSList **messages )
{
......@@ -671,23 +674,6 @@ split_path_parameters( NAObjectProfile *profile )
g_free( path );
}
static gboolean
profile_is_valid( const NAObjectProfile *profile )
{
gboolean is_valid;
is_valid = FALSE;
if( !profile->private->dispose_has_run ){
is_valid = \
is_valid_path_parameters( profile ) &&
na_icontext_is_valid( NA_ICONTEXT( profile ));
}
return( is_valid );
}
/*
* historical behavior was to not check path nor parameters at all
* 2.29.x serie, and up to 2.30.0, have tried to check an actual executable path
......
......@@ -80,11 +80,11 @@ 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_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 v_is_valid( const NAObject *a );
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 );
......@@ -280,6 +280,10 @@ iduplicable_are_equal( const NAIDuplicable *a, const NAIDuplicable *b )
are_equal &= na_factory_object_are_equal( NA_IFACTORY_OBJECT( a ), NA_IFACTORY_OBJECT( b ));
}
if( NA_IS_ICONTEXT( a )){
are_equal &= na_icontext_are_equal( NA_ICONTEXT( a ), NA_ICONTEXT( b ));
}
are_equal &= v_are_equal( NA_OBJECT( a ), NA_OBJECT( b ));
}
......@@ -291,7 +295,6 @@ iduplicable_is_valid( const NAIDuplicable *object )
{
static const gchar *thisfn = "na_object_iduplicable_is_valid";
gboolean is_valid;
HierarchyIter *str;
g_return_val_if_fail( NA_IS_OBJECT( object ), FALSE );
......@@ -300,36 +303,20 @@ iduplicable_is_valid( const NAIDuplicable *object )
if( !NA_OBJECT( object )->private->dispose_has_run ){
g_debug( "%s: object=%p (%s)", thisfn, ( void * ) object, G_OBJECT_TYPE_NAME( object ));
if( NA_IS_IFACTORY_OBJECT( object )){
is_valid = na_factory_object_is_valid( NA_IFACTORY_OBJECT( object ));
} else {
g_debug( "%s: object=%p (%s): iterating on class hierarchy",
thisfn, ( void * ) object, G_OBJECT_TYPE_NAME( object ));
is_valid = TRUE;
str = g_new0( HierarchyIter, 1 );
str->result = TRUE;
iter_on_class_hierarchy( NA_OBJECT( object ), ( HierarchyIterFunc ) &iduplicable_is_valid_iter, str );
is_valid = str->result;
g_free( str );
if( NA_IS_IFACTORY_OBJECT( object )){
is_valid &= na_factory_object_is_valid( NA_IFACTORY_OBJECT( object ));
}
}
return( is_valid );
}
static gboolean
iduplicable_is_valid_iter( GObjectClass *class, const NAObject *a, HierarchyIter *str )
{
gboolean stop = FALSE;
if( NA_OBJECT_CLASS( class )->is_valid ){
if( NA_IS_ICONTEXT( object )){
is_valid &= na_icontext_is_valid( NA_ICONTEXT( object ));
}
str->result = NA_OBJECT_CLASS( class )->is_valid( a );
stop = !str->result;
is_valid &= v_is_valid( NA_OBJECT( object ));
}
return( stop );
return( is_valid );
}
/**
......@@ -440,6 +427,16 @@ v_are_equal( const NAObject *a, const NAObject *b )
return( TRUE );
}
static gboolean
v_is_valid( const NAObject *a )
{
if( NA_OBJECT_GET_CLASS( a )->is_valid ){
return( NA_OBJECT_GET_CLASS( a )->is_valid( a ));
}
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