Fix string errors reported by Christian Kirbach
[nautilus-actions.git] / src / core / na-object-action.c
blob58b2f13c082dfdb8fd22ea6d544f11c5dfb11225
1 /*
2 * Nautilus ObjectActions
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 <glib/gi18n.h>
36 #include <libintl.h>
37 #include <string.h>
38 #include <stdlib.h>
40 #include <api/na-core-utils.h>
41 #include <api/na-iio-provider.h>
42 #include <api/na-object-api.h>
44 #include "na-factory-provider.h"
45 #include "na-factory-object.h"
47 /* private class data
49 struct _NAObjectActionClassPrivate {
50 void *empty; /* so that gcc -pedantic is happy */
53 /* private instance data
55 struct _NAObjectActionPrivate {
56 gboolean dispose_has_run;
59 /* i18n: default label for a new action */
60 #define NEW_NAUTILUS_ACTION N_( "New Nautilus action" )
62 extern NADataGroup action_data_groups []; /* defined in na-object-action-factory.c */
63 extern NADataDef data_def_action_v1 []; /* defined in na-object-action-factory.c */
65 static NAObjectItemClass *st_parent_class = NULL;
67 static GType register_type( void );
68 static void class_init( NAObjectActionClass *klass );
69 static void instance_init( GTypeInstance *instance, gpointer klass );
70 static void instance_get_property( GObject *object, guint property_id, GValue *value, GParamSpec *spec );
71 static void instance_set_property( GObject *object, guint property_id, const GValue *value, GParamSpec *spec );
72 static void instance_dispose( GObject *object );
73 static void instance_finalize( GObject *object );
75 static void object_copy( NAObject *target, const NAObject *source, gboolean recursive );
76 static gboolean object_is_valid( const NAObject *object );
78 static void ifactory_object_iface_init( NAIFactoryObjectInterface *iface );
79 static guint ifactory_object_get_version( const NAIFactoryObject *instance );
80 static NADataGroup *ifactory_object_get_groups( const NAIFactoryObject *instance );
81 static gboolean ifactory_object_are_equal( const NAIFactoryObject *a, const NAIFactoryObject *b );
82 static gboolean ifactory_object_is_valid( const NAIFactoryObject *object );
83 static void ifactory_object_read_done( NAIFactoryObject *instance, const NAIFactoryProvider *reader, void *reader_data, GSList **messages );
84 static guint ifactory_object_write_start( NAIFactoryObject *instance, const NAIFactoryProvider *writer, void *writer_data, GSList **messages );
85 static guint ifactory_object_write_done( NAIFactoryObject *instance, const NAIFactoryProvider *writer, void *writer_data, GSList **messages );
87 static void icontext_iface_init( NAIContextInterface *iface );
88 static gboolean icontext_is_candidate( NAIContext *object, guint target, GList *selection );
90 static gboolean read_done_convert_v1_to_last( NAIFactoryObject *instance );
91 static void read_done_deals_with_toolbar_label( NAIFactoryObject *instance );
93 static guint write_done_write_profiles( NAIFactoryObject *instance, const NAIFactoryProvider *writer, void *writer_data, GSList **messages );
95 static gboolean object_object_is_valid( const NAObjectAction *action );
96 static gboolean is_valid_label( const NAObjectAction *action );
97 static gboolean is_valid_toolbar_label( const NAObjectAction *action );
99 GType
100 na_object_action_get_type( void )
102 static GType action_type = 0;
104 if( action_type == 0 ){
106 action_type = register_type();
109 return( action_type );
112 static GType
113 register_type( void )
115 static const gchar *thisfn = "na_object_action_register_type";
116 GType type;
118 static GTypeInfo info = {
119 sizeof( NAObjectActionClass ),
120 NULL,
121 NULL,
122 ( GClassInitFunc ) class_init,
123 NULL,
124 NULL,
125 sizeof( NAObjectAction ),
127 ( GInstanceInitFunc ) instance_init
130 static const GInterfaceInfo icontext_iface_info = {
131 ( GInterfaceInitFunc ) icontext_iface_init,
132 NULL,
133 NULL
136 static const GInterfaceInfo ifactory_object_iface_info = {
137 ( GInterfaceInitFunc ) ifactory_object_iface_init,
138 NULL,
139 NULL
142 g_debug( "%s", thisfn );
144 type = g_type_register_static( NA_OBJECT_ITEM_TYPE, "NAObjectAction", &info, 0 );
146 g_type_add_interface_static( type, NA_ICONTEXT_TYPE, &icontext_iface_info );
148 g_type_add_interface_static( type, NA_IFACTORY_OBJECT_TYPE, &ifactory_object_iface_info );
150 return( type );
153 static void
154 class_init( NAObjectActionClass *klass )
156 static const gchar *thisfn = "na_object_action_class_init";
157 GObjectClass *object_class;
158 NAObjectClass *naobject_class;
160 g_debug( "%s: klass=%p", thisfn, ( void * ) klass );
162 st_parent_class = g_type_class_peek_parent( klass );
164 object_class = G_OBJECT_CLASS( klass );
165 object_class->set_property = instance_set_property;
166 object_class->get_property = instance_get_property;
167 object_class->dispose = instance_dispose;
168 object_class->finalize = instance_finalize;
170 naobject_class = NA_OBJECT_CLASS( klass );
171 naobject_class->dump = NULL;
172 naobject_class->copy = object_copy;
173 naobject_class->are_equal = NULL;
174 naobject_class->is_valid = object_is_valid;
176 klass->private = g_new0( NAObjectActionClassPrivate, 1 );
178 na_factory_object_define_properties( object_class, action_data_groups );
181 static void
182 instance_init( GTypeInstance *instance, gpointer klass )
184 static const gchar *thisfn = "na_object_action_instance_init";
185 NAObjectAction *self;
187 g_return_if_fail( NA_IS_OBJECT_ACTION( instance ));
189 self = NA_OBJECT_ACTION( instance );
191 g_debug( "%s: instance=%p (%s), klass=%p",
192 thisfn, ( void * ) instance, G_OBJECT_TYPE_NAME( instance ), ( void * ) klass );
194 self->private = g_new0( NAObjectActionPrivate, 1 );
197 static void
198 instance_get_property( GObject *object, guint property_id, GValue *value, GParamSpec *spec )
200 g_return_if_fail( NA_IS_OBJECT_ACTION( object ));
201 g_return_if_fail( NA_IS_IFACTORY_OBJECT( object ));
203 if( !NA_OBJECT_ACTION( object )->private->dispose_has_run ){
205 na_factory_object_get_as_value( NA_IFACTORY_OBJECT( object ), g_quark_to_string( property_id ), value );
209 static void
210 instance_set_property( GObject *object, guint property_id, const GValue *value, GParamSpec *spec )
212 g_return_if_fail( NA_IS_OBJECT_ACTION( object ));
213 g_return_if_fail( NA_IS_IFACTORY_OBJECT( object ));
215 if( !NA_OBJECT_ACTION( object )->private->dispose_has_run ){
217 na_factory_object_set_from_value( NA_IFACTORY_OBJECT( object ), g_quark_to_string( property_id ), value );
221 static void
222 instance_dispose( GObject *object )
224 static const gchar *thisfn = "na_object_action_instance_dispose";
225 NAObjectAction *self;
227 g_return_if_fail( NA_IS_OBJECT_ACTION( object ));
229 self = NA_OBJECT_ACTION( object );
231 if( !self->private->dispose_has_run ){
233 g_debug( "%s: object=%p (%s)", thisfn, ( void * ) object, G_OBJECT_TYPE_NAME( object ));
235 self->private->dispose_has_run = TRUE;
237 /* chain up to the parent class */
238 if( G_OBJECT_CLASS( st_parent_class )->dispose ){
239 G_OBJECT_CLASS( st_parent_class )->dispose( object );
244 static void
245 instance_finalize( GObject *object )
247 static const gchar *thisfn = "na_object_action_instance_finalize";
248 NAObjectAction *self;
250 g_return_if_fail( NA_IS_OBJECT_ACTION( object ));
252 self = NA_OBJECT_ACTION( object );
254 g_debug( "%s: object=%p (%s)", thisfn, ( void * ) object, G_OBJECT_TYPE_NAME( object ));
256 g_free( self->private );
258 /* chain call to parent class */
259 if( G_OBJECT_CLASS( st_parent_class )->finalize ){
260 G_OBJECT_CLASS( st_parent_class )->finalize( object );
264 static void
265 object_copy( NAObject *target, const NAObject *source, gboolean recursive )
267 g_return_if_fail( NA_IS_OBJECT_ACTION( target ));
268 g_return_if_fail( NA_IS_OBJECT_ACTION( source ));
270 if( !NA_OBJECT_ACTION( target )->private->dispose_has_run &&
271 !NA_OBJECT_ACTION( source )->private->dispose_has_run ){
273 na_factory_object_copy( NA_IFACTORY_OBJECT( target ), NA_IFACTORY_OBJECT( source ));
277 static gboolean
278 object_is_valid( const NAObject *object )
280 g_return_val_if_fail( NA_IS_OBJECT_ACTION( object ), FALSE );
282 return( object_object_is_valid( NA_OBJECT_ACTION( object )));
285 static void
286 ifactory_object_iface_init( NAIFactoryObjectInterface *iface )
288 static const gchar *thisfn = "na_object_action_ifactory_object_iface_init";
290 g_debug( "%s: iface=%p", thisfn, ( void * ) iface );
292 iface->get_version = ifactory_object_get_version;
293 iface->get_groups = ifactory_object_get_groups;
294 iface->copy = NULL;
295 iface->are_equal = ifactory_object_are_equal;
296 iface->is_valid = ifactory_object_is_valid;
297 iface->read_start = NULL;
298 iface->read_done = ifactory_object_read_done;
299 iface->write_start = ifactory_object_write_start;
300 iface->write_done = ifactory_object_write_done;
303 static guint
304 ifactory_object_get_version( const NAIFactoryObject *instance )
306 return( 1 );
309 static NADataGroup *
310 ifactory_object_get_groups( const NAIFactoryObject *instance )
312 return( action_data_groups );
315 static gboolean
316 ifactory_object_are_equal( const NAIFactoryObject *a, const NAIFactoryObject *b )
318 return( na_object_item_are_equal( NA_OBJECT_ITEM( a ), NA_OBJECT_ITEM( b )));
321 static gboolean
322 ifactory_object_is_valid( const NAIFactoryObject *object )
324 g_return_val_if_fail( NA_IS_OBJECT_ACTION( object ), FALSE );
326 return( object_object_is_valid( NA_OBJECT_ACTION( object )));
330 * at this time, we don't yet have read the profiles as this will be
331 * done in ifactory_provider_read_done - we so just be able to deal with
332 * action-specific properties (not check for profiles consistency)
334 static void
335 ifactory_object_read_done( NAIFactoryObject *instance, const NAIFactoryProvider *reader, void *reader_data, GSList **messages )
337 guint iversion;
339 g_debug( "na_object_action_ifactory_object_read_done: instance=%p", ( void * ) instance );
341 na_object_item_deals_with_version( NA_OBJECT_ITEM( instance ));
343 /* may attach a new profile if we detect a pre-v2 action
344 * the v1_to_v2 conversion must be followed by a v2_to_v3 one
346 iversion = na_object_get_iversion( instance );
347 if( iversion < 2 ){
348 read_done_convert_v1_to_last( instance );
351 /* deals with obsoleted data, i.e. data which may have been written in the past
352 * but are no long written by now - not relevant for a menu
354 read_done_deals_with_toolbar_label( instance );
356 /* prepare the context after the reading
358 na_icontext_read_done( NA_ICONTEXT( instance ));
360 na_object_dump( instance );
362 /* last, set other action defaults
364 na_factory_object_set_defaults( instance );
367 static guint
368 ifactory_object_write_start( NAIFactoryObject *instance, const NAIFactoryProvider *writer, void *writer_data, GSList **messages )
370 na_object_item_rebuild_children_slist( NA_OBJECT_ITEM( instance ));
372 return( NA_IIO_PROVIDER_CODE_OK );
375 static guint
376 ifactory_object_write_done( NAIFactoryObject *instance, const NAIFactoryProvider *writer, void *writer_data, GSList **messages )
378 guint code;
380 g_return_val_if_fail( NA_IS_OBJECT_ACTION( instance ), NA_IIO_PROVIDER_CODE_PROGRAM_ERROR );
382 code = write_done_write_profiles( instance, writer, writer_data, messages );
384 return( code );
387 static void
388 icontext_iface_init( NAIContextInterface *iface )
390 static const gchar *thisfn = "na_object_action_icontext_iface_init";
392 g_debug( "%s: iface=%p", thisfn, ( void * ) iface );
394 iface->is_candidate = icontext_is_candidate;
397 static gboolean
398 icontext_is_candidate( NAIContext *object, guint target, GList *selection )
400 return( TRUE );
404 * do we have a pre-v2 action ?
405 * it is be identified by an version = "1.x"
406 * any data found in data_def_action_v1 (defined in na-object-action-factory.c)
407 * is obsoleted and moved to a new profile
409 * actions read from .desktop already have iversion=3 (cf. desktop_read_start)
410 * and v1 actions may only come from xml or gconf
412 * returns TRUE if this actually was a v1 action which has been converted to v2
414 static gboolean
415 read_done_convert_v1_to_last( NAIFactoryObject *instance )
417 static const gchar *thisfn = "na_object_action_read_done_read_done_convert_v1_to_last";
418 GList *to_move;
419 NADataDef *def;
420 NADataBoxed *boxed;
421 GList *ibox;
422 NAObjectProfile *profile;
424 /* search for old data in the body: this is only possible before profiles
425 * because starting with contexts, iversion was written
427 to_move = NULL;
428 def = data_def_action_v1;
430 while( def->name ){
431 boxed = na_ifactory_object_get_data_boxed( instance , def->name );
432 if( boxed ){
433 g_debug( "%s: boxed=%p (%s) marked to be moved from action body to profile",
434 thisfn, ( void * ) boxed, def->name );
435 to_move = g_list_prepend( to_move, boxed );
437 def++;
440 if( !to_move ){
441 return( FALSE );
444 /* now create a new profile
446 profile = na_object_profile_new();
447 na_object_set_id( profile, "profile-pre-v2" );
448 na_object_set_label( profile, _( "Profile automatically created from pre-v2 action" ));
449 na_object_attach_profile( instance, profile );
451 if( to_move ){
452 for( ibox = to_move ; ibox ; ibox = ibox->next ){
453 na_factory_object_move_boxed(
454 NA_IFACTORY_OBJECT( profile ), instance, NA_DATA_BOXED( ibox->data ));
458 na_factory_object_set_defaults( NA_IFACTORY_OBJECT( profile ));
459 na_object_profile_convert_v2_to_last( profile );
460 return( TRUE );
464 * if toolbar-same-label is true, then ensure that this is actually true
466 static void
467 read_done_deals_with_toolbar_label( NAIFactoryObject *instance )
469 gchar *toolbar_label;
470 gchar *action_label;
471 gboolean same_label;
473 toolbar_label = na_object_get_toolbar_label( instance );
474 action_label = na_object_get_label( instance );
476 if( !toolbar_label || !g_utf8_strlen( toolbar_label, -1 )){
477 na_object_set_toolbar_label( instance, action_label );
478 na_object_set_toolbar_same_label( instance, TRUE );
480 } else {
481 same_label = ( na_core_utils_str_collate( action_label, toolbar_label ) == 0 );
482 na_object_set_toolbar_same_label( instance, same_label );
485 g_free( action_label );
486 g_free( toolbar_label );
490 * write the profiles of the action
491 * note that subitems string list has been rebuilt on write_start
493 static guint
494 write_done_write_profiles( NAIFactoryObject *instance, const NAIFactoryProvider *writer, void *writer_data, GSList **messages )
496 static const gchar *thisfn = "na_object_action_write_done_write_profiles";
497 guint code;
498 GSList *children_slist, *ic;
499 NAObjectProfile *profile;
501 code = NA_IIO_PROVIDER_CODE_OK;
502 children_slist = na_object_get_items_slist( instance );
504 for( ic = children_slist ; ic && code == NA_IIO_PROVIDER_CODE_OK ; ic = ic->next ){
505 profile = NA_OBJECT_PROFILE( na_object_get_item( instance, ic->data ));
507 if( profile ){
508 code = na_ifactory_provider_write_item( writer, writer_data, NA_IFACTORY_OBJECT( profile ), messages );
510 } else {
511 g_warning( "%s: profile not found: %s", thisfn, ( const gchar * ) ic->data );
515 return( code );
518 static gboolean
519 object_object_is_valid( const NAObjectAction *action )
521 gboolean is_valid;
522 GList *profiles, *ip;
523 gint valid_profiles;
525 is_valid = FALSE;
527 if( !action->private->dispose_has_run ){
529 is_valid = TRUE;
531 if( is_valid ){
532 if( na_object_is_target_toolbar( action )){
533 is_valid = is_valid_toolbar_label( action );
537 if( is_valid ){
538 if( na_object_is_target_selection( action )){
539 is_valid = is_valid_label( action );
543 if( is_valid ){
544 valid_profiles = 0;
545 profiles = na_object_get_items( action );
546 for( ip = profiles ; ip && !valid_profiles ; ip = ip->next ){
547 if( na_object_is_valid( ip->data )){
548 valid_profiles += 1;
551 is_valid = ( valid_profiles > 0 );
552 if( !is_valid ){
553 na_object_debug_invalid( action, "no valid profile" );
558 return( is_valid );
561 static gboolean
562 is_valid_label( const NAObjectAction *action )
564 gboolean is_valid;
565 gchar *label;
567 label = na_object_get_label( action );
568 is_valid = ( label && g_utf8_strlen( label, -1 ) > 0 );
569 g_free( label );
571 if( !is_valid ){
572 na_object_debug_invalid( action, "label" );
575 return( is_valid );
578 static gboolean
579 is_valid_toolbar_label( const NAObjectAction *action )
581 gboolean is_valid;
582 gchar *label;
584 label = na_object_get_toolbar_label( action );
585 is_valid = ( label && g_utf8_strlen( label, -1 ) > 0 );
586 g_free( label );
588 if( !is_valid ){
589 na_object_debug_invalid( action, "toolbar-label" );
592 return( is_valid );
596 * na_object_action_new:
598 * Allocates a new #NAObjectAction object.
600 * The new #NAObjectAction object is initialized with suitable default values,
601 * but without any profile.
603 * Returns: the newly allocated #NAObjectAction object.
605 * Since: 2.30
607 NAObjectAction *
608 na_object_action_new( void )
610 NAObjectAction *action;
612 action = g_object_new( NA_OBJECT_ACTION_TYPE, NULL );
614 return( action );
618 * na_object_action_new_with_profile:
620 * Allocates a new #NAObjectAction object along with a default profile.
622 * Returns: the newly allocated #NAObjectAction action.
624 * Since: 2.30
626 NAObjectAction *
627 na_object_action_new_with_profile( void )
629 NAObjectAction *action;
630 NAObjectProfile *profile;
632 action = na_object_action_new();
633 profile = na_object_profile_new();
634 na_object_action_attach_profile( action, profile );
636 return( action );
640 * na_object_action_new_with_defaults:
642 * Allocates a new #NAObjectAction object along with a default profile.
643 * These two objects have suitable default values.
645 * Returns: the newly allocated #NAObjectAction action.
647 * Since: 2.30
649 NAObjectAction *
650 na_object_action_new_with_defaults( void )
652 NAObjectAction *action;
653 NAObjectProfile *profile;
655 action = na_object_action_new();
656 na_object_set_new_id( action, NULL );
657 na_object_set_label( action, gettext( NEW_NAUTILUS_ACTION ));
658 na_object_set_toolbar_label( action, gettext( NEW_NAUTILUS_ACTION ));
659 na_factory_object_set_defaults( NA_IFACTORY_OBJECT( action ));
661 profile = na_object_profile_new_with_defaults();
662 na_object_action_attach_profile( action, profile );
664 return( action );
668 * na_object_action_get_new_profile_name:
669 * @action: the #NAObjectAction object which will receive a new profile.
671 * Returns a name suitable as a new profile name.
673 * The search is made by iterating over the standard profile name
674 * prefix : basically, we increment a counter until finding a name
675 * which is not yet allocated. The provided name is so only suitable
676 * for the specified @action.
678 * When inserting a list of profiles in the action, we iter first for
679 * new names, before actually do the insertion. We so keep the last
680 * allocated name to avoid to allocate the same one twice.
682 * Returns: a newly allocated profile name, which should be g_free() by
683 * the caller.
685 * Since: 2.30
687 gchar *
688 na_object_action_get_new_profile_name( const NAObjectAction *action )
690 int i;
691 gboolean ok = FALSE;
692 gchar *candidate = NULL;
693 guint last_allocated;
695 g_return_val_if_fail( NA_IS_OBJECT_ACTION( action ), NULL );
697 if( !action->private->dispose_has_run ){
699 last_allocated = na_object_get_last_allocated( action );
701 for( i = last_allocated + 1 ; !ok ; ++i ){
702 g_free( candidate );
703 candidate = g_strdup_printf( "profile-%d", i );
705 if( !na_object_get_item( action, candidate )){
706 ok = TRUE;
707 na_object_set_last_allocated( action, i );
711 if( !ok ){
712 g_free( candidate );
713 candidate = NULL;
717 /*g_debug( "returning candidate=%s", candidate );*/
718 return( candidate );
722 * na_object_action_attach_profile:
723 * @action: the #NAObjectAction action to which the profile will be attached.
724 * @profile: the #NAObjectProfile profile to be attached to @action.
726 * Adds a profile at the end of the list of profiles.
728 * Since: 2.30
730 void
731 na_object_action_attach_profile( NAObjectAction *action, NAObjectProfile *profile )
733 g_return_if_fail( NA_IS_OBJECT_ACTION( action ));
734 g_return_if_fail( NA_IS_OBJECT_PROFILE( profile ));
736 if( !action->private->dispose_has_run ){
738 na_object_append_item( action, profile );
739 na_object_set_parent( profile, action );
744 * na_object_action_set_last_version:
745 * @action: the #NAObjectAction action to update.
747 * Set the version number of the @action to the last one.
749 * Since: 2.30
751 void
752 na_object_action_set_last_version( NAObjectAction *action )
754 g_return_if_fail( NA_IS_OBJECT_ACTION( action ));
756 if( !action->private->dispose_has_run ){
758 na_object_set_version( action, "2.0" );