NAIDuplicable: are_equal, is valid default to TRUE
[nautilus-actions.git] / src / core / na-iduplicable.c
blobed79e408ca2394cd41337c88b487c13e4ba0159d
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 #include "na-marshal.h"
39 /* private interface data
41 struct _NAIDuplicableInterfacePrivate {
42 GList *consumers;
45 /* the data sructure set on each NAIDuplicable object
47 typedef struct {
48 NAIDuplicable *origin;
49 gboolean modified;
50 gboolean valid;
52 DuplicableStr;
54 #define NA_IDUPLICABLE_DATA_DUPLICABLE "na-iduplicable-data-duplicable"
56 /* signals emitted on NAIDuplicable when a status changes
58 enum {
59 MODIFIED_CHANGED,
60 VALID_CHANGED,
61 LAST_SIGNAL
64 static NAIDuplicableInterface *st_interface = NULL;
65 static gboolean st_initialized = FALSE;
66 static gboolean st_finalized = FALSE ;
67 static gint st_signals[ LAST_SIGNAL ] = { 0 };
69 static GType register_type( void );
70 static void interface_base_init( NAIDuplicableInterface *klass );
71 static void interface_base_finalize( NAIDuplicableInterface *klass );
73 static void v_copy( NAIDuplicable *target, const NAIDuplicable *source );
74 static gboolean v_are_equal( const NAIDuplicable *a, const NAIDuplicable *b );
75 static gboolean v_is_valid( const NAIDuplicable *object );
77 static DuplicableStr *get_duplicable_str( const NAIDuplicable *object );
79 static void on_modified_changed_class_handler( NAIDuplicable *instance, GObject *object, gboolean is_modified );
80 static void on_valid_changed_class_handler( NAIDuplicable *instance, GObject *object, gboolean is_valid );
81 static void propagate_signal_to_consumers( NAIDuplicable *instance, const gchar *signal, GObject *object, gboolean new_status );
82 static void release_signal_consumers( GList *consumers );
84 GType
85 na_iduplicable_get_type( void )
87 static GType iface_type = 0;
89 if( !iface_type ){
90 iface_type = register_type();
93 return( iface_type );
96 static GType
97 register_type( void )
99 static const gchar *thisfn = "na_iduplicable_register_type";
100 GType type;
102 static const GTypeInfo info = {
103 sizeof( NAIDuplicableInterface ),
104 ( GBaseInitFunc ) interface_base_init,
105 ( GBaseFinalizeFunc ) interface_base_finalize,
106 NULL,
107 NULL,
108 NULL,
111 NULL
114 g_debug( "%s", thisfn );
116 type = g_type_register_static( G_TYPE_INTERFACE, "NAIDuplicable", &info, 0 );
118 g_type_interface_add_prerequisite( type, G_TYPE_OBJECT );
120 return( type );
123 static void
124 interface_base_init( NAIDuplicableInterface *klass )
126 static const gchar *thisfn = "na_iduplicable_interface_base_init";
128 if( !st_initialized ){
130 g_debug( "%s: klass=%p", thisfn, ( void * ) klass );
132 klass->private = g_new0( NAIDuplicableInterfacePrivate, 1 );
134 klass->private->consumers = NULL;
136 klass->copy = NULL;
137 klass->are_equal = NULL;
138 klass->is_valid = NULL;
141 * NAIDuplicable::modified-changed:
143 * This signal is emitted by #NAIDuplicable when the modification
144 * status of an object has been modified.
146 * The default class handler propagates the signal to registered
147 * consumers.
149 * Signal args: New modification status
151 * Handler prototype:
152 * void ( *handler )( NAIDuplicable *duplicable, NAObject *object, gboolean is_modified, gpointer user_data );
154 * When the signal is first emitted, thus on NAIDuplicable, @duplicable
155 * and @object are pointers to the same address. This duplication is
156 * relevant when propagating the signal to customer, as the signal is
157 * emitted on the customer itself, while we still need the @object
158 * pointer.
160 st_signals[ MODIFIED_CHANGED ] = g_signal_new_class_handler(
161 IDUPLICABLE_SIGNAL_MODIFIED_CHANGED,
162 G_TYPE_OBJECT,
163 G_SIGNAL_RUN_CLEANUP,
164 G_CALLBACK( on_modified_changed_class_handler ),
165 NULL,
166 NULL,
167 na_cclosure_marshal_VOID__POINTER_BOOLEAN,
168 G_TYPE_NONE,
170 G_TYPE_POINTER, G_TYPE_BOOLEAN );
173 * NAIDuplicable::valid-changed:
175 * This signal is emitted by #NAIDuplicable when the validity
176 * status of an object has been modified.
178 * The default class handler propagates the signal to registered
179 * consumers.
181 * Signal args: New validity status
183 * Handler prototype:
184 * void ( *handler )( NAIDuplicable *duplicable, NAObject *object, gboolean is_valid, gpointer user_data );
186 * When the signal is first emitted, thus on NAIDuplicable, @duplicable
187 * and @object are pointers to the same address. This duplication is
188 * relevant when propagating the signal to customer, as the signal is
189 * emitted on the customer itself, while we still need the @object
190 * pointer.
192 st_signals[ VALID_CHANGED ] = g_signal_new_class_handler(
193 IDUPLICABLE_SIGNAL_VALID_CHANGED,
194 G_TYPE_OBJECT,
195 G_SIGNAL_RUN_CLEANUP,
196 G_CALLBACK( on_valid_changed_class_handler ),
197 NULL,
198 NULL,
199 na_cclosure_marshal_VOID__POINTER_BOOLEAN,
200 G_TYPE_NONE,
202 G_TYPE_POINTER, G_TYPE_BOOLEAN );
204 st_interface = klass;
206 st_initialized = TRUE;
210 static void
211 interface_base_finalize( NAIDuplicableInterface *klass )
213 static const gchar *thisfn = "na_iduplicable_interface_base_finalize";
215 if( !st_finalized ){
217 g_debug( "%s: klass=%p", thisfn, ( void * ) klass );
219 st_finalized = TRUE;
221 release_signal_consumers( klass->private->consumers );
223 g_free( klass->private );
228 * na_iduplicable_dispose:
229 * @object: the #NAIDuplicable object to be initialized.
231 * Releases resources.
233 * Since: 2.30
235 void
236 na_iduplicable_dispose( const NAIDuplicable *object )
238 DuplicableStr *str;
240 g_return_if_fail( NA_IS_IDUPLICABLE( object ));
242 if( st_initialized && !st_finalized ){
244 str = get_duplicable_str( object );
245 g_free( str );
246 g_object_set_data( G_OBJECT( object ), NA_IDUPLICABLE_DATA_DUPLICABLE, NULL );
251 * na_iduplicable_dump:
252 * @object: the #NAIDuplicable object to be dumped.
254 * Dumps via g_debug the properties of the object.
256 * We ouput here only the data we set ourselves againt the
257 * #NAIDuplicable -implemented object.
259 * This function should be called by the implementation when it dumps
260 * itself its own content.
262 * Since: 2.30
264 void
265 na_iduplicable_dump( const NAIDuplicable *object )
267 static const gchar *thisfn = "na_iduplicable_dump";
268 DuplicableStr *str;
270 g_return_if_fail( NA_IS_IDUPLICABLE( object ));
272 if( st_initialized && !st_finalized ){
274 str = get_duplicable_str( object );
276 g_debug( "| %s: origin=%p", thisfn, ( void * ) str->origin );
277 g_debug( "| %s: modified=%s", thisfn, str->modified ? "True" : "False" );
278 g_debug( "| %s: valid=%s", thisfn, str->valid ? "True" : "False" );
283 * na_iduplicable_duplicate:
284 * @object: the #NAIDuplicable object to be duplicated.
286 * Exactly duplicates a #NAIDuplicable -implemented object, including
287 * modification and validity status which are copied from @object to
288 * the duplicated one.
290 * Though this function is not recursive by itself, it is widely supposed
291 * everywhere in the program that recursivity is provided but #NAObject
292 * implementation.
294 * <important>
295 * <para>
296 * na_object_duplicate() (aka na_iduplicable_duplicate())
297 * is definitively recursive
298 * </para>
299 * </important>
301 * Returns: a new #NAIDuplicable.
303 * Since: 2.30
305 NAIDuplicable *
306 na_iduplicable_duplicate( const NAIDuplicable *object )
308 static const gchar *thisfn = "na_iduplicable_duplicate";
309 NAIDuplicable *dup;
310 DuplicableStr *dup_str, *obj_str;
312 g_return_val_if_fail( NA_IS_IDUPLICABLE( object ), NULL );
314 dup = NULL;
316 if( st_initialized && !st_finalized ){
318 g_debug( "%s: object=%p (%s)",
319 thisfn,
320 ( void * ) object, G_OBJECT_TYPE_NAME( object ));
322 dup = g_object_new( G_OBJECT_TYPE( object ), NULL );
324 v_copy( dup, object );
326 dup_str = get_duplicable_str( dup );
327 obj_str = get_duplicable_str( object );
329 dup_str->origin = ( NAIDuplicable * ) object;
330 dup_str->modified = obj_str->modified;
331 dup_str->valid = obj_str->valid;
334 return( dup );
338 * na_iduplicable_check_status:
339 * @object: the #NAIDuplicable object to be checked.
341 * Checks the edition status of the #NAIDuplicable object, and set up
342 * the corresponding properties.
344 * This function is supposed to be called each time the object may have
345 * been modified in order to set the corresponding properties. Helper
346 * functions na_iduplicable_is_modified() and na_iduplicable_is_valid()
347 * will then only return the current value of the properties.
349 * na_iduplicable_check_status() is not, as itself, recursive.
350 * That is, the modification and validity status are only set on the
351 * specified object.
352 * #NAObject implementation has chosen to handle itself the recursivity:
353 * na_object_check_status() so first check status for children, before
354 * calling this function.
356 * Since: 2.30
358 void
359 na_iduplicable_check_status( const NAIDuplicable *object )
361 static const gchar *thisfn = "na_iduplicable_check_status";
362 DuplicableStr *str;
363 gboolean was_modified, was_valid;
365 g_return_if_fail( NA_IS_IDUPLICABLE( object ));
367 if( st_initialized && !st_finalized ){
369 g_debug( "%s: object=%p (%s)", thisfn, ( void * ) object, G_OBJECT_TYPE_NAME( object ));
371 str = get_duplicable_str( object );
373 was_modified = str->modified;
374 was_valid = str->valid;
376 if( str->origin ){
377 g_debug( "%s: vs. origin=%p (%s)", thisfn, ( void * ) str->origin, G_OBJECT_TYPE_NAME( str->origin ));
378 g_return_if_fail( NA_IS_IDUPLICABLE( str->origin ));
379 str->modified = !v_are_equal( str->origin, object );
381 } else {
382 str->modified = TRUE;
385 if( was_modified != str->modified ){
386 g_debug( "%s: %p (%s) status changed to modified=%s",
387 thisfn, ( void * ) object, G_OBJECT_TYPE_NAME( object ), str->modified ? "True":"False" );
388 g_signal_emit_by_name( G_OBJECT( object ), IDUPLICABLE_SIGNAL_MODIFIED_CHANGED, object, str->modified );
391 str->valid = v_is_valid( object );
393 if( was_valid != str->valid ){
394 g_debug( "%s: %p (%s) status changed to valid=%s",
395 thisfn, ( void * ) object, G_OBJECT_TYPE_NAME( object ), str->valid ? "True":"False" );
396 g_signal_emit_by_name( G_OBJECT( object ), IDUPLICABLE_SIGNAL_VALID_CHANGED, object, str->valid );
402 * na_iduplicable_get_origin:
403 * @object: the #NAIDuplicable object whose origin is to be returned.
405 * Returns the origin of a duplicated #NAIDuplicable.
407 * Returns: the original #NAIDuplicable, or NULL.
409 * Since: 2.30
411 NAIDuplicable *
412 na_iduplicable_get_origin( const NAIDuplicable *object )
414 NAIDuplicable *origin;
415 DuplicableStr *str;
417 g_return_val_if_fail( NA_IS_IDUPLICABLE( object ), NULL );
419 origin = NULL;
421 if( st_initialized && !st_finalized ){
423 str = get_duplicable_str( object );
424 origin = str->origin;
427 return( origin );
431 * na_iduplicable_is_valid:
432 * @object: the #NAIDuplicable object whose status is to be returned.
434 * Returns the current value of the relevant property
435 * without rechecking the edition status itself.
437 * Returns: %TRUE is the provided object is valid.
439 * Since: 2.30
441 gboolean
442 na_iduplicable_is_valid( const NAIDuplicable *object )
444 gboolean is_valid;
445 DuplicableStr *str;
447 g_return_val_if_fail( NA_IS_IDUPLICABLE( object ), FALSE );
449 is_valid = FALSE;
451 if( st_initialized && !st_finalized ){
453 str = get_duplicable_str( object );
454 is_valid = str->valid;
457 return( is_valid );
461 * na_iduplicable_is_modified:
462 * @object: the #NAIDuplicable object whose status is to be returned.
464 * Returns the current value of the 'is_modified'
465 * property without rechecking the edition status itself.
467 * Returns: %TRUE is the provided object has been modified regarding of
468 * the original one.
470 * Since: 2.30
472 gboolean
473 na_iduplicable_is_modified( const NAIDuplicable *object )
475 gboolean is_modified;
476 DuplicableStr *str;
478 g_return_val_if_fail( NA_IS_IDUPLICABLE( object ), FALSE );
480 is_modified = FALSE;
482 if( st_initialized && !st_finalized ){
484 str = get_duplicable_str( object );
485 is_modified = str->modified;
488 return( is_modified );
492 * na_iduplicable_set_origin:
493 * @object: the #NAIDuplicable object whose origin is to be set.
494 * @origin: the new original #NAIDuplicable.
496 * Sets the new origin of a duplicated #NAIDuplicable.
498 * Since: 2.30
500 void
501 na_iduplicable_set_origin( NAIDuplicable *object, const NAIDuplicable *origin )
503 DuplicableStr *str;
505 g_return_if_fail( NA_IS_IDUPLICABLE( object ));
506 g_return_if_fail( NA_IS_IDUPLICABLE( origin ) || !origin );
508 if( st_initialized && !st_finalized ){
510 str = get_duplicable_str( object );
511 str->origin = ( NAIDuplicable * ) origin;
515 #ifndef NA_DISABLE_DEPRECATED
517 * na_iduplicable_set_modified:
518 * @object: the #NAIDuplicable object whose modification status is to be set.
519 * @modified: the new modification status #NAIDuplicable.
521 * Sets the new modified of a duplicated #NAIDuplicable.
523 * Since: 2.30
524 * Deprecated: 3.1.0
526 void
527 na_iduplicable_set_modified( NAIDuplicable *object, gboolean modified )
529 DuplicableStr *str;
531 g_return_if_fail( NA_IS_IDUPLICABLE( object ));
533 if( st_initialized && !st_finalized ){
535 str = get_duplicable_str( object );
536 str->modified = modified;
539 #endif /* NA_DISABLE_DEPRECATED */
541 static void
542 v_copy( NAIDuplicable *target, const NAIDuplicable *source )
544 if( NA_IDUPLICABLE_GET_INTERFACE( target )->copy ){
545 NA_IDUPLICABLE_GET_INTERFACE( target )->copy( target, source );
549 static gboolean
550 v_are_equal( const NAIDuplicable *a, const NAIDuplicable *b )
552 if( NA_IDUPLICABLE_GET_INTERFACE( a )->are_equal ){
553 return( NA_IDUPLICABLE_GET_INTERFACE( a )->are_equal( a, b ));
556 return( TRUE );
559 static gboolean
560 v_is_valid( const NAIDuplicable *object )
562 if( NA_IDUPLICABLE_GET_INTERFACE( object )->is_valid ){
563 return( NA_IDUPLICABLE_GET_INTERFACE( object )->is_valid( object ));
566 return( TRUE );
570 * na_iduplicable_register_consumer:
571 * @consumer: the target instance.
573 * This function registers a consumer, i.e. an instance to which edition
574 * status signals will be propagated.
576 * Since: 2.30
578 void
579 na_iduplicable_register_consumer( GObject *consumer )
581 g_return_if_fail( st_interface );
583 if( st_initialized && !st_finalized ){
585 g_debug( "na_iduplicable_register_consumer: consumer=%p", ( void * ) consumer );
587 st_interface->private->consumers = g_list_prepend( st_interface->private->consumers, consumer );
591 static void
592 on_modified_changed_class_handler( NAIDuplicable *instance, GObject *object, gboolean is_modified )
594 if( NA_IS_IDUPLICABLE( instance )){
595 propagate_signal_to_consumers( instance, IDUPLICABLE_SIGNAL_MODIFIED_CHANGED, object, is_modified );
599 static void
600 on_valid_changed_class_handler( NAIDuplicable *instance, GObject *object, gboolean is_valid )
602 if( NA_IS_IDUPLICABLE( instance )){
603 propagate_signal_to_consumers( instance, IDUPLICABLE_SIGNAL_VALID_CHANGED, object, is_valid );
607 static void
608 propagate_signal_to_consumers( NAIDuplicable *instance, const gchar *signal, GObject *object, gboolean new_status )
610 static const gchar *thisfn = "na_iduplicable_propagate_signals_to_consumers";
611 GList *ic;
613 g_return_if_fail( st_interface );
615 if( st_initialized && !st_finalized ){
616 g_debug( "%s: instance=%p, signal=%s", thisfn, ( void * ) instance, signal );
618 for( ic = st_interface->private->consumers ; ic ; ic = ic->next ){
619 g_signal_emit_by_name( ic->data, signal, object, new_status );
624 static void
625 release_signal_consumers( GList *consumers )
627 g_list_free( consumers );
630 static DuplicableStr *
631 get_duplicable_str( const NAIDuplicable *object )
633 DuplicableStr *str;
635 str = ( DuplicableStr * ) g_object_get_data( G_OBJECT( object ), NA_IDUPLICABLE_DATA_DUPLICABLE );
637 if( !str ){
638 str = g_new0( DuplicableStr, 1 );
640 str->origin = NULL;
641 str->modified = FALSE;
642 str->valid = TRUE;
644 g_object_set_data( G_OBJECT( object ), NA_IDUPLICABLE_DATA_DUPLICABLE, str );
647 return( str );