Define new 'pivot-prop-loadable' property
[nautilus-actions.git] / src / io-desktop / nadp-desktop-file.c
blob50184e19e06c8bbfd2273e886b06c430a7f2b298
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 <string.h>
37 #include <gio/gio.h>
39 #include <api/na-core-utils.h>
41 #include "nadp-desktop-file.h"
42 #include "nadp-keys.h"
44 /* private class data
46 struct _NadpDesktopFileClassPrivate {
47 void *empty; /* so that gcc -pedantic is happy */
50 /* private instance data
52 struct _NadpDesktopFilePrivate {
53 gboolean dispose_has_run;
54 gchar *id;
55 gchar *uri;
56 GKeyFile *key_file;
59 static GObjectClass *st_parent_class = NULL;
61 static GType register_type( void );
62 static void class_init( NadpDesktopFileClass *klass );
63 static void instance_init( GTypeInstance *instance, gpointer klass );
64 static void instance_dispose( GObject *object );
65 static void instance_finalize( GObject *object );
67 static NadpDesktopFile *ndf_new( const gchar *uri );
68 static gchar *path2id( const gchar *path );
69 static gchar *uri2id( const gchar *uri );
70 static gboolean check_key_file( NadpDesktopFile *ndf );
71 static void remove_encoding_part( NadpDesktopFile *ndf );
73 GType
74 nadp_desktop_file_get_type( void )
76 static GType class_type = 0;
78 if( !class_type ){
79 class_type = register_type();
82 return( class_type );
85 static GType
86 register_type( void )
88 static const gchar *thisfn = "nadp_desktop_file_register_type";
89 GType type;
91 static GTypeInfo info = {
92 sizeof( NadpDesktopFileClass ),
93 NULL,
94 NULL,
95 ( GClassInitFunc ) class_init,
96 NULL,
97 NULL,
98 sizeof( NadpDesktopFile ),
100 ( GInstanceInitFunc ) instance_init
103 g_debug( "%s", thisfn );
105 type = g_type_register_static( G_TYPE_OBJECT, "NadpDesktopFile", &info, 0 );
107 return( type );
110 static void
111 class_init( NadpDesktopFileClass *klass )
113 static const gchar *thisfn = "nadp_desktop_file_class_init";
114 GObjectClass *object_class;
116 g_debug( "%s: klass=%p", thisfn, ( void * ) klass );
118 st_parent_class = g_type_class_peek_parent( klass );
120 object_class = G_OBJECT_CLASS( klass );
121 object_class->dispose = instance_dispose;
122 object_class->finalize = instance_finalize;
124 klass->private = g_new0( NadpDesktopFileClassPrivate, 1 );
127 static void
128 instance_init( GTypeInstance *instance, gpointer klass )
130 static const gchar *thisfn = "nadp_desktop_file_instance_init";
131 NadpDesktopFile *self;
133 g_debug( "%s: instance=%p (%s), klass=%p",
134 thisfn, ( void * ) instance, G_OBJECT_TYPE_NAME( instance ), ( void * ) klass );
135 g_return_if_fail( NADP_IS_DESKTOP_FILE( instance ));
136 self = NADP_DESKTOP_FILE( instance );
138 self->private = g_new0( NadpDesktopFilePrivate, 1 );
140 self->private->dispose_has_run = FALSE;
141 self->private->key_file = g_key_file_new();
144 static void
145 instance_dispose( GObject *object )
147 static const gchar *thisfn = "nadp_desktop_file_instance_dispose";
148 NadpDesktopFile *self;
150 g_return_if_fail( NADP_IS_DESKTOP_FILE( object ));
152 self = NADP_DESKTOP_FILE( object );
154 if( !self->private->dispose_has_run ){
156 g_debug( "%s: object=%p (%s)", thisfn, ( void * ) object, G_OBJECT_TYPE_NAME( object ));
158 self->private->dispose_has_run = TRUE;
160 /* chain up to the parent class */
161 if( G_OBJECT_CLASS( st_parent_class )->dispose ){
162 G_OBJECT_CLASS( st_parent_class )->dispose( object );
167 static void
168 instance_finalize( GObject *object )
170 static const gchar *thisfn = "nadp_desktop_file_instance_finalize";
171 NadpDesktopFile *self;
173 g_return_if_fail( NADP_IS_DESKTOP_FILE( object ));
175 g_debug( "%s: object=%p (%s)", thisfn, ( void * ) object, G_OBJECT_TYPE_NAME( object ));
177 self = NADP_DESKTOP_FILE( object );
179 g_free( self->private->id );
180 g_free( self->private->uri );
182 if( self->private->key_file ){
183 g_key_file_free( self->private->key_file );
186 g_free( self->private );
188 /* chain call to parent class */
189 if( G_OBJECT_CLASS( st_parent_class )->finalize ){
190 G_OBJECT_CLASS( st_parent_class )->finalize( object );
195 * nadp_desktop_file_new:
197 * Retuns: a newly allocated #NadpDesktopFile object.
199 NadpDesktopFile *
200 nadp_desktop_file_new( void )
202 NadpDesktopFile *ndf;
204 ndf = g_object_new( NADP_DESKTOP_FILE_TYPE, NULL );
206 return( ndf );
210 * nadp_desktop_file_new_from_path:
211 * @path: the full pathname of a .desktop file.
213 * Retuns: a newly allocated #NadpDesktopFile object.
215 * Key file has been loaded, and first validity checks made.
217 NadpDesktopFile *
218 nadp_desktop_file_new_from_path( const gchar *path )
220 static const gchar *thisfn = "nadp_desktop_file_new_from_path";
221 NadpDesktopFile *ndf;
222 GError *error;
223 gchar *uri;
225 ndf = NULL;
226 g_debug( "%s: path=%s", thisfn, path );
227 g_return_val_if_fail( path && g_utf8_strlen( path, -1 ) && g_path_is_absolute( path ), ndf );
229 error = NULL;
230 uri = g_filename_to_uri( path, NULL, &error );
231 if( !uri || error ){
232 g_warning( "%s: %s: %s", thisfn, path, error->message );
233 g_error_free( error );
234 g_free( uri );
235 return( NULL );
238 ndf = ndf_new( uri );
240 g_free( uri );
242 g_key_file_load_from_file( ndf->private->key_file, path, G_KEY_FILE_KEEP_COMMENTS | G_KEY_FILE_KEEP_TRANSLATIONS, &error );
243 if( error ){
244 g_warning( "%s: %s: %s", thisfn, path, error->message );
245 g_error_free( error );
246 g_object_unref( ndf );
247 return( NULL );
250 if( !check_key_file( ndf )){
251 g_object_unref( ndf );
252 return( NULL );
255 return( ndf );
259 * nadp_desktop_file_new_from_uri:
260 * @uri: the URI the desktop file should be loaded from.
262 * Retuns: a newly allocated #NadpDesktopFile object, or %NULL.
264 * Key file has been loaded, and first validity checks made.
266 * Note: This function is in particular used when importing a file.
267 * So it is rather common that the file not be a .desktop one.
268 * Do not warns when file is malformed.
270 NadpDesktopFile *
271 nadp_desktop_file_new_from_uri( const gchar *uri )
273 static const gchar *thisfn = "nadp_desktop_file_new_from_uri";
274 NadpDesktopFile *ndf;
275 GError *error;
276 gchar *data;
277 gsize length;
279 ndf = NULL;
280 g_debug( "%s: uri=%s", thisfn, uri );
281 g_return_val_if_fail( uri && g_utf8_strlen( uri, -1 ), ndf );
283 ndf = ndf_new( uri );
284 data = na_core_utils_file_load_from_uri( uri, &length );
286 error = NULL;
287 g_key_file_load_from_data( ndf->private->key_file, data, length, G_KEY_FILE_KEEP_COMMENTS | G_KEY_FILE_KEEP_TRANSLATIONS, &error );
288 if( error ){
289 if( error->code != G_KEY_FILE_ERROR_GROUP_NOT_FOUND ){
290 g_warning( "%s: %s", thisfn, error->message );
292 g_error_free( error );
293 g_object_unref( ndf );
294 g_free( data );
295 return( NULL );
298 g_free( data );
300 if( !check_key_file( ndf )){
301 g_object_unref( ndf );
302 return( NULL );
305 return( ndf );
309 * nadp_desktop_file_new_for_write:
310 * @path: the full pathname of a .desktop file.
312 * Retuns: a newly allocated #NadpDesktopFile object.
314 NadpDesktopFile *
315 nadp_desktop_file_new_for_write( const gchar *path )
317 static const gchar *thisfn = "nadp_desktop_file_new_for_write";
318 NadpDesktopFile *ndf;
319 GError *error;
320 gchar *uri;
322 ndf = NULL;
323 g_debug( "%s: path=%s", thisfn, path );
324 g_return_val_if_fail( path && g_utf8_strlen( path, -1 ) && g_path_is_absolute( path ), ndf );
326 error = NULL;
327 uri = g_filename_to_uri( path, NULL, &error );
328 if( !uri || error ){
329 g_warning( "%s: %s: %s", thisfn, path, error->message );
330 g_error_free( error );
331 g_free( uri );
332 return( NULL );
335 ndf = ndf_new( uri );
337 g_free( uri );
339 return( ndf );
343 * nadp_desktop_file_get_key_file:
344 * @ndf: the #NadpDesktopFile instance.
346 * Returns: a pointer to the internal #GKeyFile.
348 GKeyFile *
349 nadp_desktop_file_get_key_file( const NadpDesktopFile *ndf )
351 GKeyFile *key_file;
353 g_return_val_if_fail( NADP_IS_DESKTOP_FILE( ndf ), NULL );
355 key_file = NULL;
357 if( !ndf->private->dispose_has_run ){
359 key_file = ndf->private->key_file;
362 return( key_file );
366 * nadp_desktop_file_get_key_file_uri:
367 * @ndf: the #NadpDesktopFile instance.
369 * Returns: the URI of the key file, as a newly allocated
370 * string which should be g_free() by the caller.
372 gchar *
373 nadp_desktop_file_get_key_file_uri( const NadpDesktopFile *ndf )
375 gchar *uri;
377 g_return_val_if_fail( NADP_IS_DESKTOP_FILE( ndf ), NULL );
379 uri = NULL;
381 if( !ndf->private->dispose_has_run ){
383 uri = g_strdup( ndf->private->uri );
386 return( uri );
389 static NadpDesktopFile *
390 ndf_new( const gchar *uri )
392 NadpDesktopFile *ndf;
394 ndf = g_object_new( NADP_DESKTOP_FILE_TYPE, NULL );
396 ndf->private->id = uri2id( uri );
397 ndf->private->uri = g_strdup( uri );
399 return( ndf );
403 * The id of the file is equal to the basename, minus the suffix.
405 static gchar *
406 path2id( const gchar *path )
408 gchar *bname;
409 gchar *id;
411 bname = g_path_get_basename( path );
412 id = na_core_utils_str_remove_suffix( bname, NADP_DESKTOP_FILE_SUFFIX );
413 g_free( bname );
415 return( id );
418 static gchar *
419 uri2id( const gchar *uri )
421 gchar *path;
422 gchar *id;
424 id = NULL;
425 path = g_filename_from_uri( uri, NULL, NULL );
427 if( path ){
428 id = path2id( path );
429 g_free( path );
432 return( id );
435 static gboolean
436 check_key_file( NadpDesktopFile *ndf )
438 static const gchar *thisfn = "nadp_desktop_file_check_key_file";
439 gboolean ret;
440 gchar *start_group;
441 gboolean has_key;
442 gboolean hidden;
443 GError *error;
445 ret = TRUE;
446 error = NULL;
448 /* start group must be [Desktop Entry] */
449 start_group = g_key_file_get_start_group( ndf->private->key_file );
450 if( strcmp( start_group, NADP_GROUP_DESKTOP )){
451 g_warning( "%s: %s: invalid start group, found %s, waited for %s",
452 thisfn, ndf->private->uri, start_group, NADP_GROUP_DESKTOP );
453 ret = FALSE;
456 /* must not have Hidden=true value */
457 if( ret ){
458 has_key = g_key_file_has_key( ndf->private->key_file, start_group, NADP_KEY_HIDDEN, &error );
459 if( error ){
460 g_warning( "%s: %s: %s", thisfn, ndf->private->uri, error->message );
461 ret = FALSE;
463 } else if( has_key ){
464 hidden = g_key_file_get_boolean( ndf->private->key_file, start_group, NADP_KEY_HIDDEN, &error );
465 if( error ){
466 g_warning( "%s: %s: %s", thisfn, ndf->private->uri, error->message );
467 ret = FALSE;
469 } else if( hidden ){
470 g_debug( "%s: %s: Hidden=true", thisfn, ndf->private->uri );
471 ret = FALSE;
476 g_free( start_group );
478 return( ret );
482 * nadp_desktop_file_get_type:
483 * @ndf: the #NadpDesktopFile instance.
485 * Returns: the value for the Type entry as a newly allocated string which
486 * should be g_free() by the caller.
488 gchar *
489 nadp_desktop_file_get_file_type( const NadpDesktopFile *ndf )
491 static const gchar *thisfn = "nadp_desktop_file_get_file_type";
492 gchar *type;
493 gboolean has_key;
494 GError *error;
496 g_return_val_if_fail( NADP_IS_DESKTOP_FILE( ndf ), NULL );
498 type = NULL;
500 if( !ndf->private->dispose_has_run ){
502 error = NULL;
504 has_key = g_key_file_has_key( ndf->private->key_file, NADP_GROUP_DESKTOP, NADP_KEY_TYPE, &error );
505 if( error ){
506 g_warning( "%s: %s", thisfn, error->message );
507 g_error_free( error );
509 } else if( has_key ){
510 type = g_key_file_get_string( ndf->private->key_file, NADP_GROUP_DESKTOP, NADP_KEY_TYPE, &error );
511 if( error ){
512 g_warning( "%s: %s", thisfn, error->message );
513 g_error_free( error );
514 g_free( type );
515 type = NULL;
520 return( type );
524 * nadp_desktop_file_get_id:
525 * @ndf: the #NadpDesktopFile instance.
527 * Returns: a newly allocated string which holds the id of the Desktop
528 * File.
530 gchar *
531 nadp_desktop_file_get_id( const NadpDesktopFile *ndf )
533 gchar *value;
535 g_return_val_if_fail( NADP_IS_DESKTOP_FILE( ndf ), NULL );
537 value = NULL;
539 if( !ndf->private->dispose_has_run ){
541 value = g_strdup( ndf->private->id );
544 return( value );
548 * nadp_desktop_file_get_profiles:
549 * @ndf: the #NadpDesktopFile instance.
551 * Returns: the list of profiles in the file, as a newly allocated GSList
552 * which must be na_core_utils_slist_free() by the caller.
554 * Silently ignore unknown groups.
556 GSList *
557 nadp_desktop_file_get_profiles( const NadpDesktopFile *ndf )
559 GSList *list;
560 gchar **groups, **ig;
561 gchar *profile_pfx;
562 gchar *profile_id;
563 guint pfx_len;
565 g_return_val_if_fail( NADP_IS_DESKTOP_FILE( ndf ), NULL );
567 list = NULL;
569 if( !ndf->private->dispose_has_run ){
571 groups = g_key_file_get_groups( ndf->private->key_file, NULL );
572 if( groups ){
573 ig = groups;
574 profile_pfx = g_strdup_printf( "%s ", NADP_GROUP_PROFILE );
575 pfx_len = strlen( profile_pfx );
577 while( *ig ){
578 if( !strncmp( *ig, profile_pfx, pfx_len )){
579 profile_id = g_strdup( *ig+pfx_len );
580 list = g_slist_prepend( list, profile_id );
583 ig++;
586 g_strfreev( groups );
587 g_free( profile_pfx );
591 return( list );
595 * nadp_desktop_file_remove_key:
596 * @ndf: this #NadpDesktopFile instance.
597 * @group: the group.
598 * @key: the key.
600 * Removes the specified key.
602 * Note that this doesn't work very well for localized keys, as we only
603 * remove a key which has the exact same label that the provided one.
604 * So we'd have to remove:
605 * - key
606 * - key[en_US.UTF-8]
607 * - key[en_US]
608 * - key[en]
610 void
611 nadp_desktop_file_remove_key( const NadpDesktopFile *ndf, const gchar *group, const gchar *key )
613 char **locales;
614 char **iloc;
615 gchar *locale_key;
617 g_return_if_fail( NADP_IS_DESKTOP_FILE( ndf ));
619 if( !ndf->private->dispose_has_run ){
621 g_key_file_remove_key( ndf->private->key_file, group, key, NULL );
623 locales = ( char ** ) g_get_language_names();
624 iloc = locales;
626 while( *iloc ){
627 locale_key = g_strdup_printf( "%s[%s]", key, *iloc );
628 g_key_file_remove_key( ndf->private->key_file, group, locale_key, NULL );
629 g_free( locale_key );
630 iloc++;
636 * nadp_desktop_file_remove_profile:
637 * @ndf: this #NadpDesktopFile instance.
638 * @profile_id: the id of the profile.
640 * Removes the group which describes the specified profile.
642 void
643 nadp_desktop_file_remove_profile( const NadpDesktopFile *ndf, const gchar *profile_id )
645 gchar *group_name;
647 g_return_if_fail( NADP_IS_DESKTOP_FILE( ndf ));
649 if( !ndf->private->dispose_has_run ){
651 group_name = g_strdup_printf( "%s %s", NADP_GROUP_PROFILE, profile_id );
652 g_key_file_remove_group( ndf->private->key_file, group_name, NULL );
653 g_free( group_name );
658 * nadp_desktop_file_get_boolean:
659 * @ndf: this #NadpDesktopFile instance.
660 * @group: the searched group.
661 * @entry: the searched entry.
662 * @key_found: set to %TRUE if the key has been found, to %FALSE else.
663 * @default_value: value to be set if key has not been found.
665 * Returns: the read value, or the default value if the entry has not
666 * been found in the given group.
668 gboolean
669 nadp_desktop_file_get_boolean( const NadpDesktopFile *ndf, const gchar *group, const gchar *entry, gboolean *key_found, gboolean default_value )
671 static const gchar *thisfn = "nadp_desktop_file_get_boolean";
672 gboolean value;
673 gboolean read_value;
674 gboolean has_entry;
675 GError *error;
677 value = default_value;
678 *key_found = FALSE;
680 g_return_val_if_fail( NADP_IS_DESKTOP_FILE( ndf ), FALSE );
682 if( !ndf->private->dispose_has_run ){
684 error = NULL;
685 has_entry = g_key_file_has_key( ndf->private->key_file, group, entry, &error );
686 if( error ){
687 g_warning( "%s: %s", thisfn, error->message );
688 g_error_free( error );
690 } else if( has_entry ){
691 read_value = g_key_file_get_boolean( ndf->private->key_file, group, entry, &error );
692 if( error ){
693 g_warning( "%s: %s", thisfn, error->message );
694 g_error_free( error );
696 } else {
697 value = read_value;
698 *key_found = TRUE;
703 return( value );
707 * nadp_desktop_file_get_locale_string:
708 * @ndf: this #NadpDesktopFile instance.
709 * @group: the searched group.
710 * @entry: the searched entry.
711 * @key_found: set to %TRUE if the key has been found, to %FALSE else.
712 * @default_value: value to be set if key has not been found.
714 * Returns: the read value, or the default value if the entry has not
715 * been found in the given group.
717 gchar *
718 nadp_desktop_file_get_locale_string( const NadpDesktopFile *ndf, const gchar *group, const gchar *entry, gboolean *key_found, const gchar *default_value )
720 static const gchar *thisfn = "nadp_desktop_file_get_locale_string";
721 gchar *value;
722 gchar *read_value;
723 GError *error;
725 value = g_strdup( default_value );
726 *key_found = FALSE;
728 g_return_val_if_fail( NADP_IS_DESKTOP_FILE( ndf ), NULL );
730 if( !ndf->private->dispose_has_run ){
732 error = NULL;
734 read_value = g_key_file_get_locale_string( ndf->private->key_file, group, entry, NULL, &error );
735 if( !read_value || error ){
736 if( error->code != G_KEY_FILE_ERROR_KEY_NOT_FOUND ){
737 g_warning( "%s: %s", thisfn, error->message );
738 g_error_free( error );
739 g_free( read_value );
742 } else {
743 g_free( value );
744 value = read_value;
745 *key_found = TRUE;
749 return( value );
753 * nadp_desktop_file_get_string:
754 * @ndf: this #NadpDesktopFile instance.
755 * @group: the searched group.
756 * @entry: the searched entry.
757 * @key_found: set to %TRUE if the key has been found, to %FALSE else.
758 * @default_value: value to be set if key has not been found.
760 * Returns: the read value, or the default value if the entry has not
761 * been found in the given group.
763 gchar *
764 nadp_desktop_file_get_string( const NadpDesktopFile *ndf, const gchar *group, const gchar *entry, gboolean *key_found, const gchar *default_value )
766 static const gchar *thisfn = "nadp_desktop_file_get_string";
767 gchar *value;
768 gchar *read_value;
769 gboolean has_entry;
770 GError *error;
772 value = g_strdup( default_value );
773 *key_found = FALSE;
775 g_return_val_if_fail( NADP_IS_DESKTOP_FILE( ndf ), NULL );
777 if( !ndf->private->dispose_has_run ){
779 error = NULL;
780 has_entry = g_key_file_has_key( ndf->private->key_file, group, entry, &error );
781 if( error ){
782 g_warning( "%s: %s", thisfn, error->message );
783 g_error_free( error );
785 } else if( has_entry ){
786 read_value = g_key_file_get_string( ndf->private->key_file, group, entry, &error );
787 if( error ){
788 g_warning( "%s: %s", thisfn, error->message );
789 g_error_free( error );
790 g_free( read_value );
792 } else {
793 g_free( value );
794 value = read_value;
795 *key_found = TRUE;
800 return( value );
804 * nadp_desktop_file_get_string_list:
805 * @ndf: this #NadpDesktopFile instance.
806 * @group: the searched group.
807 * @entry: the searched entry.
808 * @key_found: set to %TRUE if the key has been found, to %FALSE else.
809 * @default_value: value to be set if key has not been found.
811 * Returns: the read value, or the default value if the entry has not
812 * been found in the given group.
814 GSList *
815 nadp_desktop_file_get_string_list( const NadpDesktopFile *ndf, const gchar *group, const gchar *entry, gboolean *key_found, const gchar *default_value )
817 static const gchar *thisfn = "nadp_desktop_file_get_string_list";
818 GSList *value;
819 gchar **read_array;
820 gboolean has_entry;
821 GError *error;
823 value = g_slist_append( NULL, g_strdup( default_value ));
824 *key_found = FALSE;
826 g_return_val_if_fail( NADP_IS_DESKTOP_FILE( ndf ), NULL );
828 if( !ndf->private->dispose_has_run ){
830 error = NULL;
831 has_entry = g_key_file_has_key( ndf->private->key_file, group, entry, &error );
832 if( error ){
833 g_warning( "%s: %s", thisfn, error->message );
834 g_error_free( error );
836 } else if( has_entry ){
837 read_array = g_key_file_get_string_list( ndf->private->key_file, group, entry, NULL, &error );
838 if( error ){
839 g_warning( "%s: %s", thisfn, error->message );
840 g_error_free( error );
842 } else {
843 na_core_utils_slist_free( value );
844 value = na_core_utils_slist_from_array(( const gchar ** ) read_array );
845 *key_found = TRUE;
848 g_strfreev( read_array );
852 return( value );
856 * nadp_desktop_file_get_uint:
857 * @ndf: this #NadpDesktopFile instance.
858 * @group: the searched group.
859 * @entry: the searched entry.
860 * @key_found: set to %TRUE if the key has been found, to %FALSE else.
861 * @default_value: value to be set if key has not been found.
863 * Returns: the read value, or the default value if the entry has not
864 * been found in the given group.
866 guint
867 nadp_desktop_file_get_uint( const NadpDesktopFile *ndf, const gchar *group, const gchar *entry, gboolean *key_found, guint default_value )
869 static const gchar *thisfn = "nadp_desktop_file_get_uint";
870 guint value;
871 gboolean has_entry;
872 GError *error;
874 value = default_value;
875 *key_found = FALSE;
877 g_return_val_if_fail( NADP_IS_DESKTOP_FILE( ndf ), 0 );
879 if( !ndf->private->dispose_has_run ){
881 error = NULL;
882 has_entry = g_key_file_has_key( ndf->private->key_file, group, entry, &error );
883 if( error ){
884 g_warning( "%s: %s", thisfn, error->message );
885 g_error_free( error );
887 } else if( has_entry ){
888 value = ( guint ) g_key_file_get_integer( ndf->private->key_file, group, entry, &error );
889 if( error ){
890 g_warning( "%s: %s", thisfn, error->message );
891 g_error_free( error );
893 } else {
894 *key_found = TRUE;
899 return( value );
903 * nadp_desktop_file_set_boolean:
904 * @ndf: this #NadpDesktopFile object.
905 * @group: the name of the group.
906 * @key: the name of the key.
907 * @value: the value to be written.
909 * Write the given boolean value.
911 void
912 nadp_desktop_file_set_boolean( const NadpDesktopFile *ndf, const gchar *group, const gchar *key, gboolean value )
914 g_return_if_fail( NADP_IS_DESKTOP_FILE( ndf ));
916 if( !ndf->private->dispose_has_run ){
918 g_key_file_set_boolean( ndf->private->key_file, group, key, value );
923 * nadp_desktop_file_set_locale_string:
924 * @ndf: this #NadpDesktopFile object.
925 * @group: the name of the group.
926 * @key: the name of the key.
927 * @value: the value to be written.
929 * Write the given string value.
931 * Until v 3.0.4, locale strings used to be written for all available locales
932 * e.g. 'en_US.UTF-8', 'en_US', 'en.UTF-8', 'en', 'C'.
934 * Starting with v 3.0.4, encoding part of the locale is no more written.
936 * The better solution would be to include in the UI a listbox with all
937 * available locales, letting the user choose himself which locale he wish
938 * modify.
940 * A first fallback would be to set some sort of user preferences: whether
941 * to write all available locales, whether to write all but C locales, ...
943 * As of v 3.0.4, we choose:
944 * - always write the first locale, which should obviously be the user locale;
945 * - also write all locales derived from the first (e.g. en_US, en_GB, en);
946 * - when the prefix of the locale changes, stop to write other locales unless
947 * the first prefix was 'en', as we suppose that the C locale will always be
948 * in english.
950 * The locale prefix is identified by '_' or '@' character.
952 void
953 nadp_desktop_file_set_locale_string( const NadpDesktopFile *ndf, const gchar *group, const gchar *key, const gchar *value )
955 char **locales;
956 guint i;
957 gchar *prefix;
958 gboolean write;
960 g_return_if_fail( NADP_IS_DESKTOP_FILE( ndf ));
962 if( !ndf->private->dispose_has_run ){
964 locales = ( char ** ) g_get_language_names();
966 en_US.UTF-8
967 en_US
968 en.UTF-8
973 prefix = g_strdup( locales[0] );
974 for( i = 0 ; prefix[i] ; ++i ){
975 if( prefix[i] == '_' || prefix[i] == '@' || prefix[i] == '.' ){
976 prefix[i] = '\0';
977 break;
981 /* using locales[0] writes a string with, e.g. Label[en_US.UTF-8]
982 * after that trying to read the same key with another locale, even en_US.utf-8,
983 * fails ans returns an empty string.
984 * so write all available locales for the string, so that there is a chance at
985 * least one of these will be used as default
987 * pwi 2010-12-30 v 3.0.4
988 * no more write encoding part of the locale as desktop files are supposed to
989 * be UTF-8 encoded.
991 for( i = 0 ; i < g_strv_length( locales ) ; ++i ){
992 write = FALSE;
994 if( g_strstr_len( locales[i], -1, "." )){
995 continue;
998 /* write the locale string for all locales derived from the first one */
999 if( !strncmp( locales[i], prefix, strlen( prefix ))){
1000 write = TRUE;
1002 /* also write other locales if first was a 'en'-derivative */
1003 } else if( !strcmp( prefix, "en" )){
1004 write = TRUE;
1007 if( write ){
1008 g_key_file_set_locale_string( ndf->private->key_file, group, key, locales[i], value );
1012 g_free( prefix );
1017 * nadp_desktop_file_set_string:
1018 * @ndf: this #NadpDesktopFile object.
1019 * @group: the name of the group.
1020 * @key: the name of the key.
1021 * @value: the value to be written.
1023 * Write the given string value.
1025 void
1026 nadp_desktop_file_set_string( const NadpDesktopFile *ndf, const gchar *group, const gchar *key, const gchar *value )
1028 g_return_if_fail( NADP_IS_DESKTOP_FILE( ndf ));
1030 if( !ndf->private->dispose_has_run ){
1032 g_key_file_set_string( ndf->private->key_file, group, key, value );
1037 * nadp_desktop_file_set_string_list:
1038 * @ndf: this #NadpDesktopFile object.
1039 * @group: the name of the group.
1040 * @key: the name of the key.
1041 * @value: the value to be written.
1043 * Write the given list value.
1045 void
1046 nadp_desktop_file_set_string_list( const NadpDesktopFile *ndf, const gchar *group, const gchar *key, GSList *value )
1048 gchar **array;
1050 g_return_if_fail( NADP_IS_DESKTOP_FILE( ndf ));
1052 if( !ndf->private->dispose_has_run ){
1054 array = na_core_utils_slist_to_array( value );
1055 g_key_file_set_string_list( ndf->private->key_file, group, key, ( const gchar * const * ) array, g_slist_length( value ));
1056 g_strfreev( array );
1061 * nadp_desktop_file_set_uint:
1062 * @ndf: this #NadpDesktopFile object.
1063 * @group: the name of the group.
1064 * @key: the name of the key.
1065 * @value: the value to be written.
1067 * Write the given uint value.
1069 void
1070 nadp_desktop_file_set_uint( const NadpDesktopFile *ndf, const gchar *group, const gchar *key, guint value )
1072 g_return_if_fail( NADP_IS_DESKTOP_FILE( ndf ));
1074 if( !ndf->private->dispose_has_run ){
1076 g_key_file_set_integer( ndf->private->key_file, group, key, value );
1081 * nadp_desktop_file_write:
1082 * @ndf: the #NadpDesktopFile instance.
1084 * Writes the key file to the disk.
1086 * Returns: %TRUE if write is ok, %FALSE else.
1088 * Starting with v 3.0.4, locale strings whose identifier include an
1089 * encoding part are removed from the desktop file when rewriting it
1090 * (these were wrongly written between v 2.99 and 3.0.3).
1092 gboolean
1093 nadp_desktop_file_write( NadpDesktopFile *ndf )
1095 static const gchar *thisfn = "nadp_desktop_file_write";
1096 gboolean ret;
1097 gchar *data;
1098 GFile *file;
1099 GFileOutputStream *stream;
1100 GError *error;
1101 gsize length;
1103 ret = FALSE;
1104 error = NULL;
1105 g_return_val_if_fail( NADP_IS_DESKTOP_FILE( ndf ), ret );
1107 if( !ndf->private->dispose_has_run ){
1109 if( ndf->private->key_file ){
1110 remove_encoding_part( ndf );
1113 data = g_key_file_to_data( ndf->private->key_file, &length, NULL );
1114 file = g_file_new_for_uri( ndf->private->uri );
1115 g_debug( "%s: uri=%s", thisfn, ndf->private->uri );
1117 stream = g_file_replace( file, NULL, FALSE, G_FILE_CREATE_NONE, NULL, &error );
1118 if( error ){
1119 g_warning( "%s: g_file_replace: %s", thisfn, error->message );
1120 g_error_free( error );
1121 if( stream ){
1122 g_object_unref( stream );
1124 g_object_unref( file );
1125 g_free( data );
1126 return( FALSE );
1129 g_output_stream_write( G_OUTPUT_STREAM( stream ), data, length, NULL, &error );
1130 if( error ){
1131 g_warning( "%s: g_output_stream_write: %s", thisfn, error->message );
1132 g_error_free( error );
1133 g_object_unref( stream );
1134 g_object_unref( file );
1135 g_free( data );
1136 return( FALSE );
1139 g_output_stream_close( G_OUTPUT_STREAM( stream ), NULL, &error );
1140 if( error ){
1141 g_warning( "%s: g_output_stream_close: %s", thisfn, error->message );
1142 g_error_free( error );
1143 g_object_unref( stream );
1144 g_object_unref( file );
1145 g_free( data );
1146 return( FALSE );
1149 g_object_unref( stream );
1150 g_object_unref( file );
1151 g_free( data );
1153 return( TRUE );
1156 return( FALSE );
1159 static void
1160 remove_encoding_part( NadpDesktopFile *ndf )
1162 static const gchar *thisfn = "nadp_desktop_file_remove_encoding_part";
1163 gchar **groups;
1164 gchar **keys;
1165 guint ig, ik;
1166 GRegex *regex;
1167 GMatchInfo *info;
1168 GError *error;
1170 error = NULL;
1171 regex = g_regex_new( "\\[(.*)\\.(.*)\\]$", G_REGEX_CASELESS | G_REGEX_UNGREEDY, G_REGEX_MATCH_NOTEMPTY, &error );
1172 if( error ){
1173 g_warning( "%s: %s", thisfn, error->message );
1174 g_error_free( error );
1176 } else {
1177 groups = g_key_file_get_groups( ndf->private->key_file, NULL );
1179 for( ig = 0 ; ig < g_strv_length( groups ) ; ++ig ){
1180 keys = g_key_file_get_keys( ndf->private->key_file, groups[ig], NULL, NULL );
1182 for( ik = 0 ; ik < g_strv_length( keys ) ; ++ik ){
1184 if( g_regex_match( regex, keys[ik], 0, &info )){
1185 g_key_file_remove_key( ndf->private->key_file, groups[ig], keys[ik], &error );
1186 if( error ){
1187 g_warning( "%s: %s", thisfn, error->message );
1188 g_error_free( error );
1189 error = NULL;
1193 g_match_info_free( info );
1196 g_strfreev( keys );
1199 g_strfreev( groups );
1200 g_regex_unref( regex );