Set Nautilus-Actions as being the actual official product name
[nautilus-actions.git] / src / core / na-iduplicable.c
blob11fc494159921c9ff528d5631266c20548792b20
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 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-iduplicable.h>
37 /* private interface data
39 struct _NAIDuplicableInterfacePrivate {
40 GList *consumers;
43 /* the data sructure set on each NAIDuplicable object
45 typedef struct {
46 NAIDuplicable *origin;
47 gboolean modified;
48 gboolean valid;
49 gulong status_changed_handler_id;
51 DuplicableStr;
53 #define NA_IDUPLICABLE_DATA_DUPLICABLE "na-iduplicable-data-duplicable"
55 /* signals emitted on NAIDuplicable when a status changes
57 enum {
58 STATUS_CHANGED,
59 LAST_SIGNAL
62 static NAIDuplicableInterface *st_interface = NULL;
63 static gboolean st_initialized = FALSE;
64 static gboolean st_finalized = FALSE ;
65 static gint st_signals[ LAST_SIGNAL ] = { 0 };
67 static GType register_type( void );
68 static void interface_base_init( NAIDuplicableInterface *klass );
69 static void interface_base_finalize( NAIDuplicableInterface *klass );
71 static void v_copy( NAIDuplicable *target, const NAIDuplicable *source );
72 static gboolean v_are_equal( const NAIDuplicable *a, const NAIDuplicable *b );
73 static gboolean v_is_valid( const NAIDuplicable *object );
75 static DuplicableStr *get_duplicable_str( const NAIDuplicable *object );
77 static void status_changed_handler( NAIDuplicable *instance, gpointer user_data );
78 static void propagate_signal_to_consumers( const gchar *signal, NAIDuplicable *instance, gpointer user_data );
79 static void release_signal_consumers( GList *consumers );
81 GType
82 na_iduplicable_get_type( void )
84 static GType iface_type = 0;
86 if( !iface_type ){
87 iface_type = register_type();
90 return( iface_type );
93 static GType
94 register_type( void )
96 static const gchar *thisfn = "na_iduplicable_register_type";
97 GType type;
99 static const GTypeInfo info = {
100 sizeof( NAIDuplicableInterface ),
101 ( GBaseInitFunc ) interface_base_init,
102 ( GBaseFinalizeFunc ) interface_base_finalize,
103 NULL,
104 NULL,
105 NULL,
108 NULL
111 g_debug( "%s", thisfn );
113 type = g_type_register_static( G_TYPE_INTERFACE, "NAIDuplicable", &info, 0 );
115 g_type_interface_add_prerequisite( type, G_TYPE_OBJECT );
117 return( type );
120 static void
121 interface_base_init( NAIDuplicableInterface *klass )
123 static const gchar *thisfn = "na_iduplicable_interface_base_init";
125 if( !st_initialized ){
127 g_debug( "%s: klass=%p", thisfn, ( void * ) klass );
129 klass->private = g_new0( NAIDuplicableInterfacePrivate, 1 );
131 klass->private->consumers = NULL;
133 klass->copy = NULL;
134 klass->are_equal = NULL;
135 klass->is_valid = NULL;
138 * NAIDuplicable::status-changed:
140 * This signal is emitted by #NAIDuplicable when the modification
141 * or the validity status of an object has been modified.
143 st_signals[ STATUS_CHANGED ] = g_signal_new(
144 NA_IDUPLICABLE_SIGNAL_STATUS_CHANGED,
145 G_TYPE_OBJECT,
146 G_SIGNAL_RUN_LAST,
147 0, /* no default handler */
148 NULL,
149 NULL,
150 g_cclosure_marshal_VOID__POINTER,
151 G_TYPE_NONE,
153 G_TYPE_POINTER );
155 st_interface = klass;
157 st_initialized = TRUE;
161 static void
162 interface_base_finalize( NAIDuplicableInterface *klass )
164 static const gchar *thisfn = "na_iduplicable_interface_base_finalize";
166 if( !st_finalized ){
168 g_debug( "%s: klass=%p", thisfn, ( void * ) klass );
170 st_finalized = TRUE;
172 release_signal_consumers( klass->private->consumers );
174 g_free( klass->private );
179 * na_iduplicable_dispose:
180 * @object: the #NAIDuplicable object to be initialized.
182 * Releases resources.
184 * Since: 2.30
186 void
187 na_iduplicable_dispose( const NAIDuplicable *object )
189 DuplicableStr *str;
191 g_return_if_fail( NA_IS_IDUPLICABLE( object ));
193 if( st_initialized && !st_finalized ){
195 str = get_duplicable_str( object );
197 if( g_signal_handler_is_connected(( gpointer ) object, str->status_changed_handler_id )){
198 g_signal_handler_disconnect(( gpointer ) object, str->status_changed_handler_id );
201 g_free( str );
206 * na_iduplicable_dump:
207 * @object: the #NAIDuplicable object to be dumped.
209 * Dumps via g_debug the properties of the object.
211 * We ouput here only the data we set ourselves againt the
212 * #NAIDuplicable -implemented object.
214 * This function should be called by the implementation when it dumps
215 * itself its own content.
217 * Since: 2.30
219 void
220 na_iduplicable_dump( const NAIDuplicable *object )
222 static const gchar *thisfn = "na_iduplicable_dump";
223 DuplicableStr *str;
225 g_return_if_fail( NA_IS_IDUPLICABLE( object ));
227 if( st_initialized && !st_finalized ){
229 str = get_duplicable_str( object );
231 g_debug( "%s: origin=%p", thisfn, ( void * ) str->origin );
232 g_debug( "%s: modified=%s", thisfn, str->modified ? "True" : "False" );
233 g_debug( "%s: valid=%s", thisfn, str->valid ? "True" : "False" );
238 * na_iduplicable_duplicate:
239 * @object: the #NAIDuplicable object to be duplicated.
241 * Exactly duplicates a #NAIDuplicable -implemented object, including
242 * modification and validity status which are copied from @object to
243 * the duplicated one.
245 * Though this function is not recursive by itself, it is widely supposed
246 * everywhere in the program that recursivity is provided but #NAObject
247 * implementation.
249 * <important>
250 * <para>
251 * na_object_duplicate() (aka na_iduplicable_duplicate())
252 * is definitively recursive
253 * </para>
254 * </important>
256 * Returns: a new #NAIDuplicable.
258 * Since: 2.30
260 NAIDuplicable *
261 na_iduplicable_duplicate( const NAIDuplicable *object )
263 static const gchar *thisfn = "na_iduplicable_duplicate";
264 NAIDuplicable *dup;
265 DuplicableStr *dup_str, *obj_str;
267 g_return_val_if_fail( NA_IS_IDUPLICABLE( object ), NULL );
269 dup = NULL;
271 if( st_initialized && !st_finalized ){
273 g_debug( "%s: object=%p (%s)",
274 thisfn,
275 ( void * ) object, G_OBJECT_TYPE_NAME( object ));
277 dup = g_object_new( G_OBJECT_TYPE( object ), NULL );
279 v_copy( dup, object );
281 dup_str = get_duplicable_str( dup );
282 obj_str = get_duplicable_str( object );
284 dup_str->origin = ( NAIDuplicable * ) object;
285 dup_str->modified = obj_str->modified;
286 dup_str->valid = obj_str->valid;
289 return( dup );
293 * na_iduplicable_check_status:
294 * @object: the #NAIDuplicable object to be checked.
296 * Checks the edition status of the #NAIDuplicable object, and set up
297 * the corresponding properties.
299 * This function is supposed to be called each time the object may have
300 * been modified in order to set the corresponding properties. Helper
301 * functions na_iduplicable_is_modified() and na_iduplicable_is_valid()
302 * will then only return the current value of the properties.
304 * na_iduplicable_check_status() is not, as itself, recursive.
305 * That is, the modification and validity status are only set on the
306 * specified object.
307 * #NAObject implementation has choosen to handle itself the recursivity:
308 * na_object_check_status() so first check status for childs, before
309 * calling this function.
311 * Since: 2.30
313 void
314 na_iduplicable_check_status( const NAIDuplicable *object )
316 static const gchar *thisfn = "na_iduplicable_check_status";
317 DuplicableStr *str;
318 gboolean was_modified, was_valid;
319 gboolean changed;
321 g_return_if_fail( NA_IS_IDUPLICABLE( object ));
323 if( st_initialized && !st_finalized ){
325 g_debug( "%s: object=%p (%s)", thisfn, ( void * ) object, G_OBJECT_TYPE_NAME( object ));
327 str = get_duplicable_str( object );
329 was_modified = str->modified;
330 was_valid = str->valid;
331 changed = FALSE;
333 if( str->origin ){
334 g_debug( "%s: origin=%p (%s)", thisfn, ( void * ) str->origin, G_OBJECT_TYPE_NAME( str->origin ));
335 g_return_if_fail( NA_IS_IDUPLICABLE( str->origin ));
336 str->modified = !v_are_equal( str->origin, object );
338 } else {
339 str->modified = TRUE;
342 str->valid = v_is_valid( object );
344 if( was_modified && !str->modified ){
345 g_debug( "%s: %p (%s) status changed to non-modified",
346 thisfn, ( void * ) object, G_OBJECT_TYPE_NAME( object ));
347 changed = TRUE;
348 } else if ( !was_modified && str->modified ){
349 g_debug( "%s: %p (%s) status changed to modified",
350 thisfn, ( void * ) object, G_OBJECT_TYPE_NAME( object ));
351 changed = TRUE;
354 if( was_valid && !str->valid ){
355 g_debug( "%s: %p (%s) status changed to non-valid",
356 thisfn, ( void * ) object, G_OBJECT_TYPE_NAME( object ));
357 changed = TRUE;
358 } else if( !was_valid && str->valid ){
359 g_debug( "%s: %p (%s) status changed to valid",
360 thisfn, ( void * ) object, G_OBJECT_TYPE_NAME( object ));
361 changed = TRUE;
364 if( changed ){
365 g_signal_emit_by_name( G_OBJECT( object ), NA_IDUPLICABLE_SIGNAL_STATUS_CHANGED, object );
368 #if 0
369 g_debug( "%s: object=%p (%s), modified=%s, valid=%s", thisfn,
370 ( void * ) object, G_OBJECT_TYPE_NAME( object ),
371 modified ? "True":"False", valid ? "True":"False" );
372 #endif
377 * na_iduplicable_get_origin:
378 * @object: the #NAIDuplicable object whose origin is to be returned.
380 * Returns the origin of a duplicated #NAIDuplicable.
382 * Returns: the original #NAIDuplicable, or NULL.
384 * Since: 2.30
386 NAIDuplicable *
387 na_iduplicable_get_origin( const NAIDuplicable *object )
389 NAIDuplicable *origin;
390 DuplicableStr *str;
392 g_return_val_if_fail( NA_IS_IDUPLICABLE( object ), NULL );
394 origin = NULL;
396 if( st_initialized && !st_finalized ){
398 str = get_duplicable_str( object );
399 origin = str->origin;
402 return( origin );
406 * na_iduplicable_is_valid:
407 * @object: the #NAIDuplicable object whose status is to be returned.
409 * Returns the current value of the relevant property
410 * without rechecking the edition status itself.
412 * Returns: %TRUE is the provided object is valid.
414 * Since: 2.30
416 gboolean
417 na_iduplicable_is_valid( const NAIDuplicable *object )
419 gboolean is_valid;
420 DuplicableStr *str;
422 g_return_val_if_fail( NA_IS_IDUPLICABLE( object ), FALSE );
424 is_valid = FALSE;
426 if( st_initialized && !st_finalized ){
428 str = get_duplicable_str( object );
429 is_valid = str->valid;
432 return( is_valid );
436 * na_iduplicable_is_modified:
437 * @object: the #NAIDuplicable object whose status is to be returned.
439 * Returns the current value of the 'is_modified'
440 * property without rechecking the edition status itself.
442 * Returns: %TRUE is the provided object has been modified regarding of
443 * the original one.
445 * Since: 2.30
447 gboolean
448 na_iduplicable_is_modified( const NAIDuplicable *object )
450 gboolean is_modified;
451 DuplicableStr *str;
453 g_return_val_if_fail( NA_IS_IDUPLICABLE( object ), FALSE );
455 is_modified = FALSE;
457 if( st_initialized && !st_finalized ){
459 str = get_duplicable_str( object );
460 is_modified = str->modified;
463 return( is_modified );
467 * na_iduplicable_set_origin:
468 * @object: the #NAIDuplicable object whose origin is to be set.
469 * @origin: the new original #NAIDuplicable.
471 * Sets the new origin of a duplicated #NAIDuplicable.
473 * Since: 2.30
475 void
476 na_iduplicable_set_origin( NAIDuplicable *object, const NAIDuplicable *origin )
478 DuplicableStr *str;
480 g_return_if_fail( NA_IS_IDUPLICABLE( object ));
481 g_return_if_fail( NA_IS_IDUPLICABLE( origin ) || !origin );
483 if( st_initialized && !st_finalized ){
485 str = get_duplicable_str( object );
486 str->origin = ( NAIDuplicable * ) origin;
491 * na_iduplicable_set_modified:
492 * @object: the #NAIDuplicable object whose modification status is to be set.
493 * @modified: the new modification status #NAIDuplicable.
495 * Sets the new modified of a duplicated #NAIDuplicable.
497 * Since: 2.30
499 void
500 na_iduplicable_set_modified( NAIDuplicable *object, gboolean modified )
502 DuplicableStr *str;
504 g_return_if_fail( NA_IS_IDUPLICABLE( object ));
506 if( st_initialized && !st_finalized ){
508 str = get_duplicable_str( object );
510 if( str->modified != modified ){
511 str->modified = modified;
512 g_signal_emit_by_name( G_OBJECT( object ), NA_IDUPLICABLE_SIGNAL_STATUS_CHANGED, object );
517 static void
518 v_copy( NAIDuplicable *target, const NAIDuplicable *source )
520 if( NA_IDUPLICABLE_GET_INTERFACE( target )->copy ){
521 NA_IDUPLICABLE_GET_INTERFACE( target )->copy( target, source );
525 static gboolean
526 v_are_equal( const NAIDuplicable *a, const NAIDuplicable *b )
528 if( NA_IDUPLICABLE_GET_INTERFACE( a )->are_equal ){
529 return( NA_IDUPLICABLE_GET_INTERFACE( a )->are_equal( a, b ));
532 return( FALSE );
535 static gboolean
536 v_is_valid( const NAIDuplicable *object )
538 if( NA_IDUPLICABLE_GET_INTERFACE( object )->is_valid ){
539 return( NA_IDUPLICABLE_GET_INTERFACE( object )->is_valid( object ));
542 return( FALSE );
546 * na_iduplicable_register_consumer:
547 * @consumer: the target instance.
549 * This function registers a consumer, i.e. an instance to which edition
550 * status signals will be propagated.
552 * Since: 2.30
554 void
555 na_iduplicable_register_consumer( GObject *consumer )
557 g_return_if_fail( st_interface );
559 if( st_initialized && !st_finalized ){
561 g_debug( "na_iduplicable_register_consumer: consumer=%p", ( void * ) consumer );
563 st_interface->private->consumers = g_list_prepend( st_interface->private->consumers, consumer );
567 static void
568 status_changed_handler( NAIDuplicable *instance, gpointer user_data )
570 /*g_debug( "na_iduplicable_propagate_modified_changed: instance=%p (%s), user_data=%p (%s)",
571 ( void * ) instance, G_OBJECT_TYPE_NAME( instance ),
572 ( void * ) user_data, G_OBJECT_TYPE_NAME( user_data ));*/
574 propagate_signal_to_consumers( NA_IDUPLICABLE_SIGNAL_STATUS_CHANGED, instance, user_data );
578 * note that propagating the signal to consumers re-triggers
580 static void
581 propagate_signal_to_consumers( const gchar *signal, NAIDuplicable *instance, gpointer user_data )
583 static const gchar *thisfn = "na_iduplicable_propagate_signals_to_consumers";
584 GList *ic;
586 g_return_if_fail( st_interface );
588 if( st_initialized && !st_finalized ){
590 g_debug( "%s: signal=%s, instance=%p, user_data=%p", thisfn, signal, ( void * ) instance, ( void * ) user_data );
592 for( ic = st_interface->private->consumers ; ic ; ic = ic->next ){
593 g_signal_emit_by_name( ic->data, signal, user_data );
598 static void
599 release_signal_consumers( GList *consumers )
601 g_list_free( consumers );
604 static DuplicableStr *
605 get_duplicable_str( const NAIDuplicable *object )
607 DuplicableStr *str;
609 str = ( DuplicableStr * ) g_object_get_data( G_OBJECT( object ), NA_IDUPLICABLE_DATA_DUPLICABLE );
611 if( !str ){
612 str = g_new0( DuplicableStr, 1 );
614 str->origin = NULL;
615 str->modified = FALSE;
616 str->valid = TRUE;
618 str->status_changed_handler_id = g_signal_connect(
619 G_OBJECT( object ),
620 NA_IDUPLICABLE_SIGNAL_STATUS_CHANGED,
621 G_CALLBACK( status_changed_handler ),
622 ( gpointer ) object );
624 g_object_set_data( G_OBJECT( object ), NA_IDUPLICABLE_DATA_DUPLICABLE, str );
627 return( str );