Fix string errors reported by Christian Kirbach
[nautilus-actions.git] / src / core / na-object-item.c
blob12f23191af5d39d4cc9072309ce28d4b6313bfe2
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 <stdlib.h>
36 #include <string.h>
37 #include <uuid/uuid.h>
39 #include <api/na-core-utils.h>
40 #include <api/na-object-api.h>
42 #include "na-io-provider.h"
44 /* private class data
46 struct _NAObjectItemClassPrivate {
47 void *empty; /* so that gcc -pedantic is happy */
50 /* private instance data
52 struct _NAObjectItemPrivate {
53 gboolean dispose_has_run;
55 void *provider_data;
57 /* dynamically set when reading the item from the I/O storage
58 * subsystem; may be reset from FALSE to TRUE if a write operation
59 * has returned an error.
60 * defaults to FALSE for snew, not yet written to a provider, item
62 gboolean readonly;
65 static NAObjectIdClass *st_parent_class = NULL;
67 static GType register_type( void );
68 static void class_init( NAObjectItemClass *klass );
69 static void instance_init( GTypeInstance *instance, gpointer klass );
70 static void instance_dispose( GObject *object );
71 static void instance_finalize( GObject *object );
73 static void object_copy( NAObject*target, const NAObject *source, gboolean recursive );
75 static gchar *object_id_new_id( const NAObjectId *item, const NAObjectId *new_parent );
77 static void copy_children( NAObjectItem *target, const NAObjectItem *source );
79 GType
80 na_object_item_get_type( void )
82 static GType item_type = 0;
84 if( item_type == 0 ){
85 item_type = register_type();
88 return( item_type );
91 static GType
92 register_type( void )
94 static const gchar *thisfn = "na_object_item_register_type";
95 GType type;
97 static GTypeInfo info = {
98 sizeof( NAObjectItemClass ),
99 NULL,
100 NULL,
101 ( GClassInitFunc ) class_init,
102 NULL,
103 NULL,
104 sizeof( NAObjectItem ),
106 ( GInstanceInitFunc ) instance_init
109 g_debug( "%s", thisfn );
111 type = g_type_register_static( NA_OBJECT_ID_TYPE, "NAObjectItem", &info, 0 );
113 return( type );
116 static void
117 class_init( NAObjectItemClass *klass )
119 static const gchar *thisfn = "na_object_item_class_init";
120 GObjectClass *object_class;
121 NAObjectClass *naobject_class;
122 NAObjectIdClass *naobjectid_class;
124 g_debug( "%s: klass=%p", thisfn, ( void * ) klass );
126 st_parent_class = g_type_class_peek_parent( klass );
128 object_class = G_OBJECT_CLASS( klass );
129 object_class->dispose = instance_dispose;
130 object_class->finalize = instance_finalize;
132 naobject_class = NA_OBJECT_CLASS( klass );
133 naobject_class->dump = NULL;
134 naobject_class->copy = object_copy;
135 naobject_class->are_equal = NULL;
136 naobject_class->is_valid = NULL;
138 naobjectid_class = NA_OBJECT_ID_CLASS( klass );
139 naobjectid_class->new_id = object_id_new_id;
141 klass->private = g_new0( NAObjectItemClassPrivate, 1 );
144 static void
145 instance_init( GTypeInstance *instance, gpointer klass )
147 NAObjectItem *self;
149 g_return_if_fail( NA_IS_OBJECT_ITEM( instance ));
151 self = NA_OBJECT_ITEM( instance );
153 self->private = g_new0( NAObjectItemPrivate, 1 );
156 static void
157 instance_dispose( GObject *object )
159 static const gchar *thisfn = "na_object_item_instance_dispose";
160 NAObjectItem *self;
161 GList *children;
163 g_return_if_fail( NA_IS_OBJECT_ITEM( object ));
165 self = NA_OBJECT_ITEM( object );
167 if( !self->private->dispose_has_run ){
169 self->private->dispose_has_run = TRUE;
171 children = na_object_get_items( self );
172 g_debug( "%s: children=%p (count=%d)", thisfn, ( void * ) children, g_list_length( children ));
173 na_object_set_items( self, NULL );
174 na_object_unref_items( children );
176 /* chain up to the parent class */
177 if( G_OBJECT_CLASS( st_parent_class )->dispose ){
178 G_OBJECT_CLASS( st_parent_class )->dispose( object );
183 static void
184 instance_finalize( GObject *object )
186 NAObjectItem *self;
188 g_return_if_fail( NA_IS_OBJECT_ITEM( object ));
190 self = NA_OBJECT_ITEM( object );
192 g_free( self->private );
194 /* chain call to parent class */
195 if( G_OBJECT_CLASS( st_parent_class )->finalize ){
196 G_OBJECT_CLASS( st_parent_class )->finalize( object );
200 static void
201 object_copy( NAObject *target, const NAObject *source, gboolean recursive )
203 static const gchar *thisfn = "na_object_item_object_copy";
204 void *provider;
206 g_return_if_fail( NA_IS_OBJECT_ITEM( target ));
207 g_return_if_fail( NA_IS_OBJECT_ITEM( source ));
209 if( !NA_OBJECT_ITEM( target )->private->dispose_has_run &&
210 !NA_OBJECT_ITEM( source )->private->dispose_has_run ){
212 if( recursive ){
213 copy_children( NA_OBJECT_ITEM( target ), NA_OBJECT_ITEM( source ));
216 provider = na_object_get_provider( source );
218 if( provider ){
219 if( !NA_IS_IO_PROVIDER( provider )){
220 g_warning( "%s: source=%p (%s), provider=%p is not a NAIOProvider",
221 thisfn,
222 ( void * ) source, G_OBJECT_TYPE_NAME( source ),
223 ( void * ) provider );
225 } else {
226 na_io_provider_duplicate_data( NA_IO_PROVIDER( provider ), NA_OBJECT_ITEM( target ), NA_OBJECT_ITEM( source ), NULL );
233 * new_parent is not relevant when allocating a new identifier for an
234 * action or a menu ; it may safely be left as NULL though there is no
235 * gain to check this
237 static gchar *
238 object_id_new_id( const NAObjectId *item, const NAObjectId *new_parent )
240 GList *children, *it;
241 uuid_t uuid;
242 gchar uuid_str[64];
243 gchar *new_uuid = NULL;
245 g_return_val_if_fail( NA_IS_OBJECT_ITEM( item ), NULL );
247 if( !NA_OBJECT_ITEM( item )->private->dispose_has_run ){
249 /* recurse into NAObjectItems children
250 * i.e., if a menu, recurse into embedded actions
252 children = na_object_get_items( item );
253 for( it = children ; it ; it = it->next ){
254 na_object_set_new_id( it->data, new_parent );
257 uuid_generate( uuid );
258 uuid_unparse_lower( uuid, uuid_str );
259 new_uuid = g_strdup( uuid_str );
262 return( new_uuid );
266 * na_object_item_are_equal:
267 * @a: the first (original) #NAObjectItem instance.
268 * @b: the second #NAObjectItem instance.
270 * This function participates to the #na_iduplicable_check_status() stack,
271 * and is triggered after all comparable elementary data (in #NAIFactoryObject
272 * sense) have already been successfully compared.
274 * We have to deal here with the subitems: comparing children by their ids
275 * between @a and @b.
277 * Note that, when called from na_object_check_status, the status of children
278 * have already been checked, and so we should be able to rely on them.
280 * Returns: %TRUE if @a is equal to @b.
282 * Since: 2.30
284 gboolean
285 na_object_item_are_equal( const NAObjectItem *a, const NAObjectItem *b )
287 static const gchar *thisfn = "na_object_item_are_equal";
288 gboolean equal;
289 GList *a_children, *b_children, *it;
290 gchar *first_id, *second_id;
291 NAObjectId *first_obj, *second_obj;
292 gint first_pos, second_pos;
293 GList *second_list;
295 g_return_val_if_fail( NA_IS_OBJECT_ITEM( a ), FALSE );
296 g_return_val_if_fail( NA_IS_OBJECT_ITEM( b ), FALSE );
298 equal = FALSE;
300 if( !NA_OBJECT_ITEM( a )->private->dispose_has_run &&
301 !NA_OBJECT_ITEM( b )->private->dispose_has_run ){
303 equal = TRUE;
305 if( equal ){
306 a_children = na_object_get_items( a );
307 b_children = na_object_get_items( b );
308 equal = ( g_list_length( a_children ) == g_list_length( b_children ));
309 if( !equal ){
310 g_debug( "%s: %p (%s) not equal as g_list_length not equal",
311 thisfn, ( void * ) b, G_OBJECT_TYPE_NAME( b ));
312 g_debug( "a=%p children_count=%u", ( void * ) a, g_list_length( a_children ));
313 for( it = a_children ; it ; it = it->next ){
314 g_debug( "a_child=%p", ( void * ) it->data );
316 g_debug( "b=%p children_count=%u", ( void * ) b, g_list_length( b_children ));
317 for( it = b_children ; it ; it = it->next ){
318 g_debug( "b_child=%p", ( void * ) it->data );
323 if( equal ){
324 for( it = a_children ; it && equal ; it = it->next ){
325 first_id = na_object_get_id( it->data );
326 second_obj = na_object_get_item( b, first_id );
327 first_pos = -1;
328 second_pos = -1;
330 if( second_obj ){
331 first_pos = g_list_position( a_children, it );
332 second_list = g_list_find( b_children, second_obj );
333 second_pos = g_list_position( b_children, second_list );
335 if( first_pos != second_pos ){
336 equal = FALSE;
337 g_debug( "%s: %p (%s) not equal as child %s is at pos %u",
338 thisfn, ( void * ) b, G_OBJECT_TYPE_NAME( b ), first_id, second_pos );
341 } else {
342 equal = FALSE;
343 g_debug( "%s: %p (%s) not equal as child %s removed",
344 thisfn, ( void * ) b, G_OBJECT_TYPE_NAME( b ), first_id );
347 g_free( first_id );
351 if( equal ){
352 for( it = b_children ; it && equal ; it = it->next ){
353 second_id = na_object_get_id( it->data );
354 first_obj = na_object_get_item( a, second_id );
356 if( !first_obj ){
357 equal = FALSE;
358 g_debug( "%s: %p (%s) not equal as child %s added",
359 thisfn, ( void * ) b, G_OBJECT_TYPE_NAME( b ), second_id );
361 } else {
362 equal = !na_object_is_modified( it->data );
364 if( !equal ){
365 g_debug( "%s: %p (%s) not equal as child %s modified",
366 thisfn, ( void * ) b, G_OBJECT_TYPE_NAME( b ), second_id );
370 g_free( second_id );
374 /*g_debug( "na_object_item_object_are_equal: a=%p (%s), b=%p (%s), are_equal=%s",
375 ( void * ) a, G_OBJECT_TYPE_NAME( a ),
376 ( void * ) b, G_OBJECT_TYPE_NAME( b ),
377 equal ? "True":"False" );*/
380 return( equal );
384 * na_object_item_get_item:
385 * @item: the #NAObjectItem from which we want retrieve a subitem.
386 * @id: the id of the searched subitem.
388 * Returns: a pointer to the #NAObjectId -derived child with the required id.
390 * The returned #NAObjectId is owned by the @item object ; the
391 * caller should not try to g_free() nor g_object_unref() it.
393 * Since: 2.30
395 NAObjectId *
396 na_object_item_get_item( const NAObjectItem *item, const gchar *id )
398 GList *childs, *it;
399 NAObjectId *found = NULL;
400 NAObjectId *isub;
401 gchar *isubid;
403 g_return_val_if_fail( NA_IS_OBJECT_ITEM( item ), NULL );
405 if( !item->private->dispose_has_run ){
407 childs = na_object_get_items( item );
408 for( it = childs ; it && !found ; it = it->next ){
409 isub = NA_OBJECT_ID( it->data );
410 isubid = na_object_get_id( isub );
411 if( !strcmp( id, isubid )){
412 found = isub;
414 g_free( isubid );
418 return( found );
422 * na_object_item_get_position:
423 * @item: this #NAObjectItem object.
424 * @child: a #NAObjectId -derived child.
426 * Returns: the position of @child in the subitems list of @item,
427 * starting from zero, or -1 if not found.
429 * Since: 2.30
431 gint
432 na_object_item_get_position( const NAObjectItem *item, const NAObjectId *child )
434 gint pos = -1;
435 GList *children;
437 g_return_val_if_fail( NA_IS_OBJECT_ITEM( item ), pos );
438 g_return_val_if_fail( NA_IS_OBJECT_ID( child ), pos );
440 if( !child ){
441 return( pos );
444 if( !item->private->dispose_has_run ){
446 children = na_object_get_items( item );
447 pos = g_list_index( children, ( gconstpointer ) child );
450 return( pos );
454 * na_object_item_append_item:
455 * @item: the #NAObjectItem to which add the subitem.
456 * @child: a #NAObjectId to be added to list of subitems.
458 * Appends a new @child to the list of subitems of @item,
459 * and setup the parent pointer of the child to its new parent.
461 * Doesn't modify the reference count on @object.
463 * Since: 2.30
465 void
466 na_object_item_append_item( NAObjectItem *item, const NAObjectId *child )
468 GList *children;
470 g_return_if_fail( NA_IS_OBJECT_ITEM( item ));
471 g_return_if_fail( NA_IS_OBJECT_ID( child ));
473 if( !item->private->dispose_has_run ){
475 children = na_object_get_items( item );
477 if( !g_list_find( children, ( gpointer ) child )){
479 children = g_list_append( children, ( gpointer ) child );
480 na_object_set_parent( child, item );
481 na_object_set_items( item, children );
487 * na_object_item_insert_at:
488 * @item: the #NAObjectItem in which add the subitem.
489 * @child: a #NAObjectId -derived to be inserted in the list of subitems.
490 * @pos: the position at which the @child should be inserted.
492 * Inserts a new @child in the list of subitems of @item.
494 * Doesn't modify the reference count on @child.
496 * Since: 2.30
498 void
499 na_object_item_insert_at( NAObjectItem *item, const NAObjectId *child, gint pos )
501 GList *children, *it;
502 gint i;
504 g_return_if_fail( NA_IS_OBJECT_ITEM( item ));
505 g_return_if_fail( NA_IS_OBJECT_ID( child ));
507 if( !item->private->dispose_has_run ){
509 children = na_object_get_items( item );
510 if( pos == -1 || pos >= g_list_length( children )){
511 na_object_append_item( item, child );
513 } else {
514 i = 0;
515 for( it = children ; it && i <= pos ; it = it->next ){
516 if( i == pos ){
517 children = g_list_insert_before( children, it, ( gpointer ) child );
519 i += 1;
521 na_object_set_items( item, children );
527 * na_object_item_insert_item:
528 * @item: the #NAObjectItem to which add the subitem.
529 * @child: a #NAObjectId to be inserted in the list of subitems.
530 * @before: the #NAObjectId before which the @child should be inserted.
532 * Inserts a new @child in the list of subitems of @item.
534 * Doesn't modify the reference count on @child.
536 * Since: 2.30
538 void
539 na_object_item_insert_item( NAObjectItem *item, const NAObjectId *child, const NAObjectId *before )
541 GList *children;
542 GList *before_list;
544 g_return_if_fail( NA_IS_OBJECT_ITEM( item ));
545 g_return_if_fail( NA_IS_OBJECT_ID( child ));
546 g_return_if_fail( !before || NA_IS_OBJECT_ID( before ));
548 if( !item->private->dispose_has_run ){
550 children = na_object_get_items( item );
551 if( !g_list_find( children, ( gpointer ) child )){
553 before_list = NULL;
555 if( before ){
556 before_list = g_list_find( children, ( gconstpointer ) before );
559 if( before_list ){
560 children = g_list_insert_before( children, before_list, ( gpointer ) child );
561 } else {
562 children = g_list_prepend( children, ( gpointer ) child );
565 na_object_set_items( item, children );
571 * na_object_item_remove_item:
572 * @item: the #NAObjectItem from which the subitem must be removed.
573 * @child: a #NAObjectId -derived to be removed from the list of subitems.
575 * Removes a @child from the list of subitems of @item.
577 * Doesn't modify the reference count on @child.
579 * Since: 2.30
581 void
582 na_object_item_remove_item( NAObjectItem *item, const NAObjectId *child )
584 GList *children;
586 g_return_if_fail( NA_IS_OBJECT_ITEM( item ));
587 g_return_if_fail( NA_IS_OBJECT_ID( child ));
589 if( !item->private->dispose_has_run ){
591 children = na_object_get_items( item );
593 if( children ){
594 g_debug( "na_object_item_remove_item: removing %p (%s) from %p (%s)",
595 ( void * ) child, G_OBJECT_TYPE_NAME( child ),
596 ( void * ) item, G_OBJECT_TYPE_NAME( item ));
598 children = g_list_remove( children, ( gconstpointer ) child );
599 g_debug( "na_object_item_remove_item: after: children=%p, count=%u", ( void * ) children, g_list_length( children ));
600 na_object_set_items( item, children );
606 * na_object_item_get_items_count:
607 * @item: the #NAObjectItem from which we want a count of subitems.
609 * Returns: the count of subitems of @item.
611 * Since: 2.30
613 guint
614 na_object_item_get_items_count( const NAObjectItem *item )
616 guint count = 0;
617 GList *childs;
619 /*g_debug( "na_object_item_get_items_count: item=%p (%s)", ( void * ) item, G_OBJECT_TYPE_NAME( item ));*/
620 g_return_val_if_fail( NA_IS_OBJECT_ITEM( item ), 0 );
622 if( !item->private->dispose_has_run ){
624 childs = na_object_get_items( item );
625 count = childs ? g_list_length( childs ) : 0;
628 return( count );
632 * na_object_item_count_items:
633 * @items: a list if #NAObject -derived to be counted.
634 * @menus: will be set to the count of menus.
635 * @actions: will be set to the count of actions.
636 * @profiles: will be set to the count of profiles.
637 * @recurse: whether to recursively count all items, or only those in
638 * level zero of the list.
640 * Returns: the count the numbers of items if the provided list.
642 * As this function is recursive, the counters should be initialized by
643 * the caller before calling it.
645 * Since: 2.30
647 void
648 na_object_item_count_items( GList *items, gint *menus, gint *actions, gint *profiles, gboolean recurse )
650 GList *it;
652 /*g_debug( "na_object_item_count_items: items=%p (count=%d), menus=%d, actions=%d, profiles=%d",
653 ( void * ) items, items ? g_list_length( items ) : 0, *menus, *actions, *profiles );*/
655 for( it = items ; it ; it = it->next ){
657 if( recurse ){
658 if( NA_IS_OBJECT_ITEM( it->data )){
659 GList *subitems = na_object_get_items( it->data );
660 na_object_count_items( subitems, menus, actions, profiles, recurse );
664 if( NA_IS_OBJECT_MENU( it->data )){
665 *menus += 1;
667 } else if( NA_IS_OBJECT_ACTION( it->data )){
668 *actions += 1;
670 } else if( NA_IS_OBJECT_PROFILE( it->data )){
671 *profiles += 1;
677 * na_object_item_unref_items:
678 * @items: a list of #NAObject -derived items.
680 * Unref only the first level the #NAObject of the list, freeing the list at last.
682 * This is rather only used by NAPivot.
684 * Since: 2.30
686 void
687 na_object_item_unref_items( GList *items )
689 g_list_foreach( items, ( GFunc ) g_object_unref, NULL );
690 g_list_free( items );
694 * na_object_item_unref_items_rec:
695 * @items: a list of #NAObject -derived items.
697 * Recursively unref the #NAObject's of the list, freeing the list at last.
699 * This is heavily used by NACT.
701 * Since: 2.30
703 void
704 na_object_item_unref_items_rec( GList *items )
706 GList *it;
708 for( it = items ; it ; it = it->next ){
709 na_object_unref( it->data );
712 g_list_free( items );
716 * na_object_item_deals_with_version:
717 * @item: this #NAObjectItem -derived object.
719 * Just after the @item has been read from NAIFactoryProvider, setup
720 * the version. This is needed because some conversions may occur in
721 * this object.
723 * Note that there is only some 2.x versions where the version string
724 * was not systematically written. If @item has been read from a
725 * .desktop file, then iversion is already set to (at least) 3.
727 * Since: 2.30
729 void
730 na_object_item_deals_with_version( NAObjectItem *item )
732 guint version_uint;
733 gchar *version_str;
735 g_return_if_fail( NA_IS_OBJECT_ITEM( item ));
737 if( !item->private->dispose_has_run ){
739 version_uint = na_object_get_iversion( item );
741 if( !version_uint ){
742 version_str = na_object_get_version( item );
744 if( !version_str || !strlen( version_str )){
745 g_free( version_str );
746 version_str = g_strdup( "2.0" );
749 version_uint = atoi( version_str );
750 na_object_set_iversion( item, version_uint );
752 g_free( version_str );
758 * na_object_item_rebuild_children_slist:
759 * @item: this #NAObjectItem -derived object.
761 * Rebuild the string list of children.
763 * Since: 2.30
765 void
766 na_object_item_rebuild_children_slist( NAObjectItem *item )
768 GSList *slist;
769 GList *subitems, *it;
770 gchar *id;
772 na_object_set_items_slist( item, NULL );
774 if( !item->private->dispose_has_run ){
776 subitems = na_object_get_items( item );
777 slist = NULL;
779 for( it = subitems ; it ; it = it->next ){
780 id = na_object_get_id( it->data );
781 slist = g_slist_prepend( slist, id );
783 slist = g_slist_reverse( slist );
785 na_object_set_items_slist( item, slist );
787 na_core_utils_slist_free( slist );
791 static void
792 copy_children( NAObjectItem *target, const NAObjectItem *source )
794 static const gchar *thisfn = "na_object_item_copy_children";
795 GList *tgt_children, *src_children, *ic;
796 NAObject *dup;
798 tgt_children = na_object_get_items( target );
799 if( tgt_children ){
800 g_warning( "%s: target_children=%p (count=%d)",
801 thisfn, ( void * ) tgt_children, g_list_length( tgt_children ));
802 g_return_if_fail( tgt_children == NULL );
805 src_children = na_object_get_items( source );
806 for( ic = src_children ; ic ; ic = ic->next ){
808 dup = ( NAObject * ) na_object_duplicate( ic->data );
809 na_object_set_parent( dup, target );
810 tgt_children = g_list_prepend( tgt_children, dup );
813 tgt_children = g_list_reverse( tgt_children );
814 na_object_set_items( target, tgt_children );