Fixed typo in string
[nautilus-actions.git] / src / core / na-object.c
blobbb70bbfd5240cbf7b7433da0dedc5aadc0b644d7
1 /*
2 * Nautilus-Actions
3 * A Nautilus extension which offers configurable context menu actions.
5 * Copyright (C) 2005 The GNOME Foundation
6 * Copyright (C) 2006, 2007, 2008 Frederic Ruaudel and others (see AUTHORS)
7 * Copyright (C) 2009, 2010, 2011, 2012 Pierre Wieser and others (see AUTHORS)
9 * This Program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License as
11 * published by the Free Software Foundation; either version 2 of
12 * the License, or (at your option) any later version.
14 * This Program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public
20 * License along with this Library; see the file COPYING. If not,
21 * write to the Free Software Foundation, Inc., 59 Temple Place,
22 * Suite 330, Boston, MA 02111-1307, USA.
24 * Authors:
25 * Frederic Ruaudel <grumz@grumz.net>
26 * Rodrigo Moya <rodrigo@gnome-db.org>
27 * Pierre Wieser <pwieser@trychlos.org>
28 * ... and many others (see AUTHORS)
31 #ifdef HAVE_CONFIG_H
32 #include <config.h>
33 #endif
35 #include <api/na-object-api.h>
37 #include "na-factory-object.h"
39 /* private class data
41 struct _NAObjectClassPrivate {
42 void *empty; /* so that gcc -pedantic is happy */
45 /* private instance data
47 struct _NAObjectPrivate {
48 gboolean dispose_has_run;
51 static GObjectClass *st_parent_class = NULL;
53 static GType register_type( void );
54 static void class_init( NAObjectClass *klass );
55 static void instance_init( GTypeInstance *instance, gpointer klass );
56 static void instance_dispose( GObject *object );
57 static void instance_finalize( GObject *object );
59 static void object_dump( const NAObject *object );
61 static void iduplicable_iface_init( NAIDuplicableInterface *iface, void *user_data );
62 static void iduplicable_copy( NAIDuplicable *target, const NAIDuplicable *source, guint mode );
63 static gboolean iduplicable_are_equal( const NAIDuplicable *a, const NAIDuplicable *b );
64 static gboolean iduplicable_is_valid( const NAIDuplicable *object );
66 static void check_status_down_rec( const NAObject *object );
67 static void check_status_up_rec( const NAObject *object, gboolean was_modified, gboolean was_valid );
68 static void v_copy( NAObject *target, const NAObject *source, guint mode );
69 static gboolean v_are_equal( const NAObject *a, const NAObject *b );
70 static gboolean v_is_valid( const NAObject *a );
71 static void dump_tree( GList *tree, gint level );
73 GType
74 na_object_object_get_type( void )
76 static GType item_type = 0;
78 if( item_type == 0 ){
79 item_type = register_type();
82 return( item_type );
85 static GType
86 register_type( void )
88 static const gchar *thisfn = "na_object_register_type";
89 GType type;
91 static GTypeInfo info = {
92 sizeof( NAObjectClass ),
93 NULL,
94 NULL,
95 ( GClassInitFunc ) class_init,
96 NULL,
97 NULL,
98 sizeof( NAObject ),
100 ( GInstanceInitFunc ) instance_init
103 static const GInterfaceInfo iduplicable_iface_info = {
104 ( GInterfaceInitFunc ) iduplicable_iface_init,
105 NULL,
106 NULL
109 g_debug( "%s", thisfn );
111 type = g_type_register_static( G_TYPE_OBJECT, "NAObject", &info, 0 );
113 g_type_add_interface_static( type, NA_TYPE_IDUPLICABLE, &iduplicable_iface_info );
115 return( type );
118 static void
119 class_init( NAObjectClass *klass )
121 static const gchar *thisfn = "na_object_class_init";
122 GObjectClass *object_class;
123 NAObjectClass *naobject_class;
125 g_debug( "%s: klass=%p", thisfn, ( void * ) klass );
127 st_parent_class = g_type_class_peek_parent( klass );
129 object_class = G_OBJECT_CLASS( klass );
130 object_class->dispose = instance_dispose;
131 object_class->finalize = instance_finalize;
133 naobject_class = NA_OBJECT_CLASS( klass );
134 naobject_class->dump = object_dump;
135 naobject_class->copy = NULL;
136 naobject_class->are_equal = NULL;
137 naobject_class->is_valid = NULL;
139 klass->private = g_new0( NAObjectClassPrivate, 1 );
142 static void
143 instance_init( GTypeInstance *instance, gpointer klass )
145 NAObject *self;
147 g_return_if_fail( NA_IS_OBJECT( instance ));
149 self = NA_OBJECT( instance );
151 self->private = g_new0( NAObjectPrivate, 1 );
154 static void
155 instance_dispose( GObject *object )
157 NAObject *self;
159 g_return_if_fail( NA_IS_OBJECT( object ));
161 self = NA_OBJECT( object );
163 if( !self->private->dispose_has_run ){
165 self->private->dispose_has_run = TRUE;
167 na_iduplicable_dispose( NA_IDUPLICABLE( object ));
169 /* chain up to the parent class */
170 if( G_OBJECT_CLASS( st_parent_class )->dispose ){
171 G_OBJECT_CLASS( st_parent_class )->dispose( object );
176 static void
177 instance_finalize( GObject *object )
179 NAObject *self;
181 g_return_if_fail( NA_IS_OBJECT( object ));
183 self = NA_OBJECT( object );
185 g_free( self->private );
187 if( NA_IS_IFACTORY_OBJECT( object )){
188 na_factory_object_finalize( NA_IFACTORY_OBJECT( object ));
191 /* chain call to parent class */
192 if( G_OBJECT_CLASS( st_parent_class )->finalize ){
193 G_OBJECT_CLASS( st_parent_class )->finalize( object );
197 static void
198 object_dump( const NAObject *object )
200 if( !object->private->dispose_has_run ){
202 na_iduplicable_dump( NA_IDUPLICABLE( object ));
204 if( NA_IS_IFACTORY_OBJECT( object )){
205 na_factory_object_dump( NA_IFACTORY_OBJECT( object ));
210 static void
211 iduplicable_iface_init( NAIDuplicableInterface *iface, void *user_data )
213 static const gchar *thisfn = "na_object_iduplicable_iface_init";
215 g_debug( "%s: iface=%p, user_data=%p", thisfn, ( void * ) iface, ( void * ) user_data );
217 iface->copy = iduplicable_copy;
218 iface->are_equal = iduplicable_are_equal;
219 iface->is_valid = iduplicable_is_valid;
223 * implementation of na_iduplicable::copy interface virtual function
224 * it recursively copies @source to @target
226 static void
227 iduplicable_copy( NAIDuplicable *target, const NAIDuplicable *source, guint mode )
229 static const gchar *thisfn = "na_object_iduplicable_copy";
230 NAObject *dest, *src;
232 g_return_if_fail( NA_IS_OBJECT( target ));
233 g_return_if_fail( NA_IS_OBJECT( source ));
235 dest = NA_OBJECT( target );
236 src = NA_OBJECT( source );
238 if( !dest->private->dispose_has_run &&
239 !src->private->dispose_has_run ){
241 g_debug( "%s: target=%p (%s), source=%p (%s), mode=%d",
242 thisfn,
243 ( void * ) dest, G_OBJECT_TYPE_NAME( dest ),
244 ( void * ) src, G_OBJECT_TYPE_NAME( src ),
245 mode );
247 if( NA_IS_IFACTORY_OBJECT( target )){
248 na_factory_object_copy( NA_IFACTORY_OBJECT( target ), NA_IFACTORY_OBJECT( source ));
251 if( NA_IS_ICONTEXT( target )){
252 na_icontext_copy( NA_ICONTEXT( target ), NA_ICONTEXT( source ));
255 v_copy( dest, src, mode );
259 static gboolean
260 iduplicable_are_equal( const NAIDuplicable *a, const NAIDuplicable *b )
262 static const gchar *thisfn = "na_object_iduplicable_are_equal";
263 gboolean are_equal;
265 g_return_val_if_fail( NA_IS_OBJECT( a ), FALSE );
266 g_return_val_if_fail( NA_IS_OBJECT( b ), FALSE );
268 are_equal = FALSE;
270 if( !NA_OBJECT( a )->private->dispose_has_run &&
271 !NA_OBJECT( b )->private->dispose_has_run ){
273 g_debug( "%s: a=%p (%s), b=%p", thisfn, ( void * ) a, G_OBJECT_TYPE_NAME( a ), ( void * ) b );
275 are_equal = TRUE;
277 if( NA_IS_IFACTORY_OBJECT( a )){
278 are_equal &= na_factory_object_are_equal( NA_IFACTORY_OBJECT( a ), NA_IFACTORY_OBJECT( b ));
281 if( NA_IS_ICONTEXT( a )){
282 are_equal &= na_icontext_are_equal( NA_ICONTEXT( a ), NA_ICONTEXT( b ));
285 are_equal &= v_are_equal( NA_OBJECT( a ), NA_OBJECT( b ));
288 return( are_equal );
291 static gboolean
292 iduplicable_is_valid( const NAIDuplicable *object )
294 static const gchar *thisfn = "na_object_iduplicable_is_valid";
295 gboolean is_valid;
297 g_return_val_if_fail( NA_IS_OBJECT( object ), FALSE );
299 is_valid = FALSE;
301 if( !NA_OBJECT( object )->private->dispose_has_run ){
302 g_debug( "%s: object=%p (%s)", thisfn, ( void * ) object, G_OBJECT_TYPE_NAME( object ));
304 is_valid = TRUE;
306 if( NA_IS_IFACTORY_OBJECT( object )){
307 is_valid &= na_factory_object_is_valid( NA_IFACTORY_OBJECT( object ));
310 if( NA_IS_ICONTEXT( object )){
311 is_valid &= na_icontext_is_valid( NA_ICONTEXT( object ));
314 is_valid &= v_is_valid( NA_OBJECT( object ));
317 return( is_valid );
321 * na_object_object_check_status_rec:
322 * @object: the #NAObject -derived object to be checked.
324 * Recursively checks for the edition status of @object and its children
325 * (if any).
327 * Internally set some properties which may be requested later. This
328 * two-steps check-request let us optimize some work in the UI.
330 * <literallayout>
331 * na_object_object_check_status_rec( object )
332 * +- na_iduplicable_check_status( object )
333 * +- get_origin( object )
334 * +- modified_status = v_are_equal( origin, object )
335 * | +-> interface <structfield>NAObjectClass::are_equal</structfield>
336 * | which happens to be iduplicable_are_equal( a, b )
337 * | +- v_are_equal( a, b )
338 * | +- NAObjectAction::are_equal()
339 * | +- na_factory_object_are_equal()
340 * | +- check NAObjectActionPrivate data
341 * | +- call parent class
342 * | +- NAObjectItem::are_equal()
343 * | +- check NAObjectItemPrivate data
344 * | +- call parent class
345 * | +- NAObjectId::are_equal()
347 * +- valid_status = v_is_valid( object ) -> interface <structfield>NAObjectClass::is_valid</structfield>
348 * </literallayout>
350 * Note that the recursivity is managed here, so that we can be sure
351 * that edition status of children is actually checked before those of
352 * the parent.
354 * <formalpara>
355 * <title>
356 * As of 3.1.0:
357 * </title>
358 * <para>
359 * <itemizedlist>
360 * <listitem>
361 * <para>
362 * when the modification status of a NAObjectProfile changes, then its
363 * NAObjectAction parent is rechecked;
364 * </para>
365 * </listitem>
366 * <listitem>
367 * <para>
368 * when the validity status of an object is changed, then its parent is
369 * also rechecked.
370 * </para>
371 * </listitem>
372 * </itemizedlist>
373 * </para>
374 * </formalpara>
376 * Since: 2.30
378 void
379 na_object_object_check_status_rec( const NAObject *object )
381 static const gchar *thisfn = "na_object_object_check_status_rec";
382 gboolean was_modified, was_valid;
384 g_return_if_fail( NA_IS_OBJECT( object ));
386 if( !object->private->dispose_has_run ){
387 g_debug( "%s: object=%p (%s)", thisfn, ( void * ) object, G_OBJECT_TYPE_NAME( object ));
389 was_modified = na_object_is_modified( object );
390 was_valid = na_object_is_valid( object );
391 check_status_down_rec( object );
392 check_status_up_rec( object, was_modified, was_valid );
397 * recursively checks the status downstream
399 static void
400 check_status_down_rec( const NAObject *object )
402 if( NA_IS_OBJECT_ITEM( object )){
403 g_list_foreach( na_object_get_items( object ), ( GFunc ) check_status_down_rec, NULL );
406 na_iduplicable_check_status( NA_IDUPLICABLE( object ));
410 * if the status appears changed, then rechecks the parent
411 * recurse upstream while there is a parent, and its status changes
413 static void
414 check_status_up_rec( const NAObject *object, gboolean was_modified, gboolean was_valid )
416 gboolean is_modified, is_valid;
417 NAObjectItem *parent;
419 is_modified = na_object_is_modified( object );
420 is_valid = na_object_is_valid( object );
422 if(( NA_IS_OBJECT_PROFILE( object ) && was_modified != is_modified ) ||
423 was_valid != is_valid ){
425 parent = na_object_get_parent( object );
427 if( parent ){
428 was_modified = na_object_is_modified( parent );
429 was_valid = na_object_is_valid( parent );
430 na_iduplicable_check_status( NA_IDUPLICABLE( parent ));
431 check_status_up_rec( NA_OBJECT( parent ), was_modified, was_valid );
436 static void
437 v_copy( NAObject *target, const NAObject *source, guint mode )
439 if( NA_OBJECT_GET_CLASS( target )->copy ){
440 NA_OBJECT_GET_CLASS( target )->copy( target, source, mode );
444 static gboolean
445 v_are_equal( const NAObject *a, const NAObject *b )
447 if( NA_OBJECT_GET_CLASS( a )->are_equal ){
448 return( NA_OBJECT_GET_CLASS( a )->are_equal( a, b ));
451 return( TRUE );
454 static gboolean
455 v_is_valid( const NAObject *a )
457 if( NA_OBJECT_GET_CLASS( a )->is_valid ){
458 return( NA_OBJECT_GET_CLASS( a )->is_valid( a ));
461 return( TRUE );
465 * na_object_object_dump:
466 * @object: the #NAObject -derived object to be dumped.
468 * Dumps via g_debug() the actual content of the object.
470 * The recursivity is dealt with here because, if we would let
471 * #NAObjectItem do this, the dump of #NAObjectItem -derived object
472 * would be splitted, children being inserted inside.
474 * na_object_dump() doesn't modify the reference count of the dumped
475 * object.
477 * Since: 2.30
479 void
480 na_object_object_dump( const NAObject *object )
482 GList *children, *ic;
484 g_return_if_fail( NA_IS_OBJECT( object ));
486 if( !object->private->dispose_has_run ){
488 na_object_dump_norec( object );
490 if( NA_IS_OBJECT_ITEM( object )){
491 children = na_object_get_items( object );
493 for( ic = children ; ic ; ic = ic->next ){
494 na_object_dump( ic->data );
501 * na_object_object_dump_norec:
502 * @object: the #NAObject -derived object to be dumped.
504 * Dumps via g_debug the actual content of the object.
506 * This function is not recursive.
508 * Since: 2.30
510 void
511 na_object_object_dump_norec( const NAObject *object )
513 g_return_if_fail( NA_IS_OBJECT( object ));
515 if( !object->private->dispose_has_run ){
516 if( NA_OBJECT_GET_CLASS( object )->dump ){
517 NA_OBJECT_GET_CLASS( object )->dump( object );
523 * na_object_object_dump_tree:
524 * @tree: a hierarchical list of #NAObject -derived objects.
526 * Outputs a brief, hierarchical dump of the provided list.
528 * Since: 2.30
530 void
531 na_object_object_dump_tree( GList *tree )
533 dump_tree( tree, 0 );
536 static void
537 dump_tree( GList *tree, gint level )
539 GString *prefix;
540 gint i;
541 GList *it;
542 const NAObject *object;
543 gchar *label;
545 prefix = g_string_new( "" );
546 for( i = 0 ; i < level ; ++i ){
547 g_string_append_printf( prefix, " " );
550 for( it = tree ; it ; it = it->next ){
551 object = ( const NAObject * ) it->data;
552 label = na_object_get_label( object );
553 g_debug( "na_object_dump_tree: %s%p (%s, ref_count=%u) '%s'", prefix->str,
554 ( void * ) object, G_OBJECT_TYPE_NAME( object ), G_OBJECT( object )->ref_count, label );
555 g_free( label );
557 if( NA_IS_OBJECT_ITEM( object )){
558 dump_tree( na_object_get_items( object ), level+1 );
562 g_string_free( prefix, TRUE );
566 * na_object_object_reset_origin:
567 * @object: a #NAObject -derived object.
568 * @origin: must be a duplication of @object.
570 * Recursively reset origin of @object and its children to @origin (and
571 * its children), so that @origin appears as the actual origin of @object.
573 * The origin of @origin itself is set to NULL.
575 * This only works if @origin has just been duplicated from @object,
576 * and thus we do not have to check if children lists are equal.
578 * Since: 2.30
580 void
581 na_object_object_reset_origin( NAObject *object, const NAObject *origin )
583 GList *origin_children, *iorig;
584 GList *object_children, *iobj;
586 g_return_if_fail( NA_IS_OBJECT( origin ));
587 g_return_if_fail( NA_IS_OBJECT( object ));
589 if( !object->private->dispose_has_run && !origin->private->dispose_has_run ){
591 origin_children = na_object_get_items( origin );
592 object_children = na_object_get_items( object );
594 for( iorig = origin_children, iobj = object_children ; iorig && iobj ; iorig = iorig->next, iobj = iobj->next ){
595 na_object_reset_origin( iobj->data, iorig->data );
598 na_iduplicable_set_origin( NA_IDUPLICABLE( object ), NA_IDUPLICABLE( origin ));
599 na_iduplicable_set_origin( NA_IDUPLICABLE( origin ), NULL );
604 * na_object_object_ref:
605 * @object: a #NAObject -derived object.
607 * Recursively ref the @object and all its children, incrementing their
608 * reference_count by 1.
610 * Returns: a reference on the @object.
612 * Since: 2.30
614 NAObject *
615 na_object_object_ref( NAObject *object )
617 NAObject *ref;
619 g_return_val_if_fail( NA_IS_OBJECT( object ), NULL );
621 ref = NULL;
623 if( !object->private->dispose_has_run ){
625 if( NA_IS_OBJECT_ITEM( object )){
626 g_list_foreach( na_object_get_items( object ), ( GFunc ) na_object_object_ref, NULL );
629 ref = g_object_ref( object );
632 return( ref );
636 * na_object_object_unref:
637 * @object: a #NAObject -derived object.
639 * Recursively unref the @object and all its children, decrementing their
640 * reference_count by 1.
642 * Note that we may want to free a copy+ref of a list of items whichy have
643 * had already disposed (which is probably a bug somewhere). So first test
644 * is the object is still alive.
646 * Since: 2.30
648 void
649 na_object_object_unref( NAObject *object )
651 g_return_if_fail( NA_IS_OBJECT( object ));
653 if( !object->private->dispose_has_run ){
654 if( NA_IS_OBJECT_ITEM( object )){
655 g_list_foreach( na_object_get_items( object ), ( GFunc ) na_object_object_unref, NULL );
657 g_object_unref( object );
661 #ifdef NA_ENABLE_DEPRECATED
663 * build the class hierarchy
664 * returns a list of GObjectClass, which starts with NAObject,
665 * and to with the most derived class (e.g. NAObjectAction or so)
667 static GList *
668 build_class_hierarchy( const NAObject *object )
670 GObjectClass *class;
671 GList *hierarchy;
673 hierarchy = NULL;
674 class = G_OBJECT_GET_CLASS( object );
676 while( G_OBJECT_CLASS_TYPE( class ) != NA_TYPE_OBJECT ){
678 hierarchy = g_list_prepend( hierarchy, class );
679 class = g_type_class_peek_parent( class );
682 hierarchy = g_list_prepend( hierarchy, class );
684 return( hierarchy );
688 * na_object_get_hierarchy:
689 * @object: the #NAObject -derived object.
691 * Returns: the class hierarchy,
692 * from the topmost base class, to the most-derived one.
694 * Since: 2.30
695 * Deprecated: 3.1
697 GList *
698 na_object_get_hierarchy( const NAObject *object )
700 GList *hierarchy;
702 g_return_val_if_fail( NA_IS_OBJECT( object ), NULL );
704 hierarchy = NULL;
706 if( !object->private->dispose_has_run ){
708 hierarchy = build_class_hierarchy( object );
711 return( hierarchy );
715 * na_object_free_hierarchy:
716 * @hierarchy: the #GList of hierarchy, as returned from
717 * na_object_get_hierarchy().
719 * Releases the #NAObject hierarchy.
721 * Since: 2.30
722 * Deprecated: 3.1
724 void
725 na_object_free_hierarchy( GList *hierarchy )
727 g_list_free( hierarchy );
729 #endif /* NA_ENABLE_DEPRECATED */
732 * na_object_object_debug_invalid:
733 * @object: the #NAObject -derived object which is invalid.
734 * @reason: the reason.
736 * Dump the object with the invalidity reason.
738 * Since: 2.30
740 void
741 na_object_object_debug_invalid( const NAObject *object, const gchar *reason )
743 g_debug( "na_object_object_debug_invalid: object %p (%s) is marked invalid for reason \"%s\"",
744 ( void * ) object, G_OBJECT_TYPE_NAME( object ), reason );