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.
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)
35 #include <api/na-object-api.h>
37 #include "na-factory-object.h"
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
);
74 na_object_object_get_type( void )
76 static GType item_type
= 0;
79 item_type
= register_type();
88 static const gchar
*thisfn
= "na_object_register_type";
91 static GTypeInfo info
= {
92 sizeof( NAObjectClass
),
95 ( GClassInitFunc
) class_init
,
100 ( GInstanceInitFunc
) instance_init
103 static const GInterfaceInfo iduplicable_iface_info
= {
104 ( GInterfaceInitFunc
) iduplicable_iface_init
,
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
);
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 );
143 instance_init( GTypeInstance
*instance
, gpointer klass
)
147 g_return_if_fail( NA_IS_OBJECT( instance
));
149 self
= NA_OBJECT( instance
);
151 self
->private = g_new0( NAObjectPrivate
, 1 );
155 instance_dispose( GObject
*object
)
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
);
177 instance_finalize( GObject
*object
)
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
);
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
));
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
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",
243 ( void * ) dest
, G_OBJECT_TYPE_NAME( dest
),
244 ( void * ) src
, G_OBJECT_TYPE_NAME( src
),
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
);
260 iduplicable_are_equal( const NAIDuplicable
*a
, const NAIDuplicable
*b
)
262 static const gchar
*thisfn
= "na_object_iduplicable_are_equal";
265 g_return_val_if_fail( NA_IS_OBJECT( a
), FALSE
);
266 g_return_val_if_fail( NA_IS_OBJECT( b
), 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
);
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
));
292 iduplicable_is_valid( const NAIDuplicable
*object
)
294 static const gchar
*thisfn
= "na_object_iduplicable_is_valid";
297 g_return_val_if_fail( NA_IS_OBJECT( object
), 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
));
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
));
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
327 * Internally set some properties which may be requested later. This
328 * two-steps check-request let us optimize some work in the UI.
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>
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
362 * when the modification status of a NAObjectProfile changes, then its
363 * NAObjectAction parent is rechecked;
368 * when the validity status of an object is changed, then its parent is
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
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
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
);
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
);
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
);
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
));
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
));
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
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.
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.
531 na_object_object_dump_tree( GList
*tree
)
533 dump_tree( tree
, 0 );
537 dump_tree( GList
*tree
, gint level
)
542 const NAObject
*object
;
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
);
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.
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.
615 na_object_object_ref( NAObject
*object
)
619 g_return_val_if_fail( NA_IS_OBJECT( object
), 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
);
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.
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)
668 build_class_hierarchy( const NAObject
*object
)
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 );
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.
698 na_object_get_hierarchy( const NAObject
*object
)
702 g_return_val_if_fail( NA_IS_OBJECT( object
), NULL
);
706 if( !object
->private->dispose_has_run
){
708 hierarchy
= build_class_hierarchy( object
);
715 * na_object_free_hierarchy:
716 * @hierarchy: the #GList of hierarchy, as returned from
717 * na_object_get_hierarchy().
719 * Releases the #NAObject hierarchy.
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.
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
);