na_updater_is_item_writable is renamed as na_updater_check_item_writability_status
[nautilus-actions.git] / src / core / na-updater.c
blobf5d7f2bd85b9d77c37e168ad63c5eaeeb0b18a8c
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-core-utils.h>
36 #include <api/na-gconf-utils.h>
37 #include <api/na-object-api.h>
39 #include "na-io-provider.h"
40 #include "na-settings.h"
41 #include "na-updater.h"
43 /* private class data
45 struct _NAUpdaterClassPrivate {
46 void *empty; /* so that gcc -pedantic is happy */
49 /* private instance data
51 struct _NAUpdaterPrivate {
52 gboolean dispose_has_run;
53 gboolean are_preferences_locked;
54 gboolean is_level_zero_writable;
57 static NAPivotClass *st_parent_class = NULL;
59 static GType register_type( void );
60 static void class_init( NAUpdaterClass *klass );
61 static void instance_init( GTypeInstance *instance, gpointer klass );
62 static void instance_dispose( GObject *object );
63 static void instance_finalize( GObject *object );
65 static gboolean are_preferences_locked( const NAUpdater *updater );
66 static gboolean is_level_zero_writable( const NAUpdater *updater );
67 static void set_writability_status( NAObjectItem *item, const NAUpdater *updater );
69 GType
70 na_updater_get_type( void )
72 static GType object_type = 0;
74 if( !object_type ){
75 object_type = register_type();
78 return( object_type );
81 static GType
82 register_type( void )
84 static const gchar *thisfn = "na_updater_register_type";
85 GType type;
87 static GTypeInfo info = {
88 sizeof( NAUpdaterClass ),
89 ( GBaseInitFunc ) NULL,
90 ( GBaseFinalizeFunc ) NULL,
91 ( GClassInitFunc ) class_init,
92 NULL,
93 NULL,
94 sizeof( NAUpdater ),
96 ( GInstanceInitFunc ) instance_init
99 g_debug( "%s", thisfn );
101 type = g_type_register_static( NA_PIVOT_TYPE, "NAUpdater", &info, 0 );
103 return( type );
106 static void
107 class_init( NAUpdaterClass *klass )
109 static const gchar *thisfn = "na_updater_class_init";
110 GObjectClass *object_class;
112 g_debug( "%s: klass=%p", thisfn, ( void * ) klass );
114 st_parent_class = g_type_class_peek_parent( klass );
116 object_class = G_OBJECT_CLASS( klass );
117 object_class->dispose = instance_dispose;
118 object_class->finalize = instance_finalize;
120 klass->private = g_new0( NAUpdaterClassPrivate, 1 );
123 static void
124 instance_init( GTypeInstance *instance, gpointer klass )
126 static const gchar *thisfn = "na_updater_instance_init";
127 NAUpdater *self;
129 g_return_if_fail( NA_IS_UPDATER( instance ));
131 g_debug( "%s: instance=%p (%s), klass=%p",
132 thisfn, ( void * ) instance, G_OBJECT_TYPE_NAME( instance ), ( void * ) klass );
134 self = NA_UPDATER( instance );
136 self->private = g_new0( NAUpdaterPrivate, 1 );
138 self->private->dispose_has_run = FALSE;
141 static void
142 instance_dispose( GObject *object )
144 static const gchar *thisfn = "na_updater_instance_dispose";
145 NAUpdater *self;
147 g_return_if_fail( NA_IS_UPDATER( object ));
149 self = NA_UPDATER( object );
151 if( !self->private->dispose_has_run ){
153 g_debug( "%s: object=%p (%s)", thisfn, ( void * ) object, G_OBJECT_TYPE_NAME( object ));
155 self->private->dispose_has_run = TRUE;
157 /* chain up to the parent class */
158 if( G_OBJECT_CLASS( st_parent_class )->dispose ){
159 G_OBJECT_CLASS( st_parent_class )->dispose( object );
164 static void
165 instance_finalize( GObject *object )
167 static const gchar *thisfn = "na_updater_instance_finalize";
168 NAUpdater *self;
170 g_return_if_fail( NA_IS_UPDATER( object ));
172 g_debug( "%s: object=%p (%s)", thisfn, ( void * ) object, G_OBJECT_TYPE_NAME( object ));
174 self = NA_UPDATER( object );
176 g_free( self->private );
178 /* chain call to parent class */
179 if( G_OBJECT_CLASS( st_parent_class )->finalize ){
180 G_OBJECT_CLASS( st_parent_class )->finalize( object );
185 * na_updater_new:
187 * Returns: a newly allocated #NAUpdater object.
189 NAUpdater *
190 na_updater_new( void )
192 static const gchar *thisfn = "na_updater_new";
193 NAUpdater *updater;
195 g_debug( "%s", thisfn );
197 updater = g_object_new( NA_UPDATER_TYPE, NULL );
199 updater->private->are_preferences_locked = are_preferences_locked( updater );
200 updater->private->is_level_zero_writable = is_level_zero_writable( updater );
202 return( updater );
205 static gboolean
206 are_preferences_locked( const NAUpdater *updater )
208 gboolean are_locked;
209 gboolean mandatory;
210 NASettings *settings;
212 settings = na_pivot_get_settings( NA_PIVOT( updater ));
213 are_locked = na_settings_get_boolean( settings, NA_IPREFS_ADMIN_PREFERENCES_LOCKED, NULL, &mandatory );
215 return( are_locked && mandatory );
218 static gboolean
219 is_level_zero_writable( const NAUpdater *updater )
221 GSList *level_zero;
222 gboolean mandatory;
224 level_zero = na_settings_get_string_list(
225 na_pivot_get_settings( NA_PIVOT( updater )), NA_IPREFS_ITEMS_LEVEL_ZERO_ORDER, NULL, &mandatory );
227 na_core_utils_slist_free( level_zero );
229 return( !mandatory );
233 * na_updater_are_preferences_locked:
234 * @updater: the #NAUpdater application object.
236 * Returns: %TRUE if preferences have been globally locked down by an
237 * admin, %FALSE else.
239 gboolean
240 na_updater_are_preferences_locked( const NAUpdater *updater )
242 gboolean are_locked;
244 g_return_val_if_fail( NA_IS_UPDATER( updater ), TRUE );
246 are_locked = TRUE;
248 if( !updater->private->dispose_has_run ){
250 are_locked = updater->private->are_preferences_locked;
253 return( are_locked );
257 * na_updater_is_level_zero_writable:
258 * @updater: the #NAUpdater application object.
260 * As of 3.1.0, level-zero is written as a user preference.
262 * This function considers that the level_zero is writable if it is not
263 * a mandatory preference.
264 * Whether preferences themselves are or not globally locked is not
265 * considered here (as imho, level zero is not really and semantically
266 * part of user preferences).
268 * This function only considers the case of the level zero itself.
269 * It does not take into account whether the i/o provider (if any)
270 * is writable, or if the item iself is not read only.
272 * Returns: %TRUE if we are able to update the level-zero list of items,
273 * %FALSE else.
275 gboolean
276 na_updater_is_level_zero_writable( const NAUpdater *updater )
278 gboolean is_writable;
280 g_return_val_if_fail( NA_IS_UPDATER( updater ), FALSE );
282 is_writable = FALSE;
284 if( !updater->private->dispose_has_run ){
286 is_writable = updater->private->is_level_zero_writable;
289 return( is_writable );
293 * na_updater_check_item_writability_status:
294 * @updater: this #NAUpdater object.
295 * @item: the #NAObjectItem to be written.
296 * @reason: the reason for why @item may not be writable.
298 * Returns: %TRUE: if @item is actually writable, given the current
299 * status of its provider, %FALSE else.
301 * For an item be actually writable:
302 * - the item must not be itself in a read-only store, which has been
303 * checked when first reading it
304 * - the provider must be willing (resp. able) to write
305 * - the provider must not has been locked by the admin, nor by the user
307 * If the item does not have a parent, the the level zero must be writable.
309 gboolean
310 na_updater_check_item_writability_status( const NAUpdater *updater, const NAObjectItem *item, guint *reason )
312 gboolean writable;
313 NAIOProvider *provider;
314 NAObjectItem *parent;
316 g_return_val_if_fail( NA_IS_UPDATER( updater ), FALSE );
317 g_return_val_if_fail( NA_IS_OBJECT_ITEM( item ), FALSE );
319 writable = FALSE;
320 if( reason ){
321 *reason = NA_IIO_PROVIDER_STATUS_UNDETERMINED;
324 if( !updater->private->dispose_has_run ){
326 writable = TRUE;
327 if( reason ){
328 *reason = NA_IIO_PROVIDER_STATUS_WRITABLE;
331 /* Writability status of the item has been determined at load time
332 * (cf. e.g. io-desktop/nadp-reader.c:read_done_item_is_writable()).
333 * Though I'm plenty conscious that this status is subject to many
334 * changes during the life of the item (e.g. by modifying permissions
335 * on the underlying store), it is just more efficient to not reevaluate
336 * this status each time we need it, and enough for our needs..
338 if( writable ){
339 if( na_object_is_readonly( item )){
340 writable = FALSE;
341 if( reason ){
342 *reason = NA_IIO_PROVIDER_STATUS_ITEM_READONLY;
347 if( writable ){
348 provider = na_object_get_provider( item );
349 if( provider ){
350 writable = na_io_provider_is_finally_writable( provider, reason );
352 /* the get_writable_provider() api already takes care of above checks
354 } else {
355 provider = na_io_provider_find_writable_io_provider( NA_PIVOT( updater ));
356 if( !provider ){
357 writable = FALSE;
358 if( reason ){
359 *reason = NA_IIO_PROVIDER_STATUS_NO_PROVIDER_FOUND;
365 /* if needed, the level zero must be writable
367 if( writable ){
368 parent = ( NAObjectItem * ) na_object_get_parent( item );
369 if( !parent ){
370 if( updater->private->is_level_zero_writable ){
371 writable = FALSE;
372 if( reason ){
373 *reason = NA_IIO_PROVIDER_STATUS_LEVEL_ZERO;
380 return( writable );
384 * na_updater_append_item:
385 * @updater: this #NAUpdater object.
386 * @item: a #NAObjectItem-derived object to be appended to the tree.
388 * Append a new item at the end of the global tree.
390 void
391 na_updater_append_item( NAUpdater *updater, NAObjectItem *item )
393 GList *tree;
395 g_return_if_fail( NA_IS_UPDATER( updater ));
396 g_return_if_fail( NA_IS_OBJECT_ITEM( item ));
398 if( !updater->private->dispose_has_run ){
400 g_object_get( G_OBJECT( updater ), PIVOT_PROP_TREE, &tree, NULL );
401 tree = g_list_append( tree, item );
402 g_object_set( G_OBJECT( updater ), PIVOT_PROP_TREE, tree, NULL );
407 * na_updater_insert_item:
408 * @updater: this #NAUpdater object.
409 * @item: a #NAObjectItem-derived object to be inserted in the tree.
410 * @parent_id: the id of the parent, or %NULL.
411 * @pos: the position in the children of the parent, starting at zero, or -1.
413 * Insert a new item in the global tree.
415 void
416 na_updater_insert_item( NAUpdater *updater, NAObjectItem *item, const gchar *parent_id, gint pos )
418 GList *tree;
419 NAObjectItem *parent;
421 g_return_if_fail( NA_IS_UPDATER( updater ));
422 g_return_if_fail( NA_IS_OBJECT_ITEM( item ));
424 if( !updater->private->dispose_has_run ){
426 parent = NULL;
427 g_object_get( G_OBJECT( updater ), PIVOT_PROP_TREE, &tree, NULL );
429 if( parent_id ){
430 parent = na_pivot_get_item( NA_PIVOT( updater ), parent_id );
433 if( parent ){
434 na_object_insert_at( parent, item, pos );
436 } else {
437 tree = g_list_append( tree, item );
438 g_object_set( G_OBJECT( updater ), PIVOT_PROP_TREE, tree, NULL );
444 * na_updater_remove_item:
445 * @updater: this #NAPivot instance.
446 * @item: the #NAObjectItem to be removed from the list.
448 * Removes a #NAObjectItem from the hierarchical tree. Does not delete it.
450 void
451 na_updater_remove_item( NAUpdater *updater, NAObject *item )
453 GList *tree;
454 NAObjectItem *parent;
456 g_return_if_fail( NA_IS_PIVOT( updater ));
458 if( !updater->private->dispose_has_run ){
460 g_debug( "na_updater_remove_item: updater=%p, item=%p (%s)",
461 ( void * ) updater,
462 ( void * ) item, G_IS_OBJECT( item ) ? G_OBJECT_TYPE_NAME( item ) : "(null)" );
464 parent = na_object_get_parent( item );
465 if( parent ){
466 tree = na_object_get_items( parent );
467 tree = g_list_remove( tree, ( gconstpointer ) item );
468 na_object_set_items( parent, tree );
470 } else {
471 g_object_get( G_OBJECT( updater ), PIVOT_PROP_TREE, &tree, NULL );
472 tree = g_list_remove( tree, ( gconstpointer ) item );
473 g_object_set( G_OBJECT( updater ), PIVOT_PROP_TREE, tree, NULL );
479 * na_updater_should_pasted_be_relabeled:
480 * @updater: this #NAUpdater instance.
481 * @object: the considered #NAObject-derived object.
483 * Whether the specified object should be relabeled when pasted ?
485 * Returns: %TRUE if the object should be relabeled, %FALSE else.
487 gboolean
488 na_updater_should_pasted_be_relabeled( const NAUpdater *updater, const NAObject *item )
490 static const gchar *thisfn = "na_updater_should_pasted_be_relabeled";
491 gboolean relabel;
492 NASettings *settings;
494 settings = na_pivot_get_settings( NA_PIVOT( updater ));
496 if( NA_IS_OBJECT_MENU( item )){
497 relabel = na_settings_get_boolean( settings, NA_IPREFS_RELABEL_DUPLICATE_MENU, NULL, NULL );
499 } else if( NA_IS_OBJECT_ACTION( item )){
500 relabel = na_settings_get_boolean( settings, NA_IPREFS_RELABEL_DUPLICATE_ACTION, NULL, NULL );
502 } else if( NA_IS_OBJECT_PROFILE( item )){
503 relabel = na_settings_get_boolean( settings, NA_IPREFS_RELABEL_DUPLICATE_PROFILE, NULL, NULL );
505 } else {
506 g_warning( "%s: unknown item type at %p", thisfn, ( void * ) item );
507 g_return_val_if_reached( FALSE );
510 return( relabel );
514 * na_updater_load_items:
515 * @updater: this #NAUpdater instance.
517 * Loads the items, updating simultaneously their writability status.
519 * Returns: a pointer (not a ref) on the loaded tree.
521 * Since: 3.1.0
523 GList *
524 na_updater_load_items( NAUpdater *updater )
526 static const gchar *thisfn = "na_updater_load_items";
527 GList *tree;
529 g_return_val_if_fail( NA_IS_UPDATER( updater ), NULL );
531 tree = NULL;
533 if( !updater->private->dispose_has_run ){
534 g_debug( "%s: updater=%p (%s)", thisfn, ( void * ) updater, G_OBJECT_TYPE_NAME( updater ));
536 na_pivot_load_items( NA_PIVOT( updater ));
537 tree = na_pivot_get_items( NA_PIVOT( updater ));
538 g_list_foreach( tree, ( GFunc ) set_writability_status, ( gpointer ) updater );
541 return( tree );
544 static void
545 set_writability_status( NAObjectItem *item, const NAUpdater *updater )
547 gboolean writable;
548 guint reason;
549 GList *children;
551 writable = na_updater_check_item_writability_status( updater, item, &reason );
552 na_object_set_writability_status( item, writable, reason );
554 if( NA_IS_OBJECT_MENU( item )){
555 children = na_object_get_items( item );
556 g_list_foreach( children, ( GFunc ) set_writability_status, ( gpointer ) updater );
561 * na_updater_write_item:
562 * @updater: this #NAUpdater instance.
563 * @item: a #NAObjectItem to be written down to the storage subsystem.
564 * @messages: the I/O provider can allocate and store here its error
565 * messages.
567 * Writes an item (an action or a menu).
569 * Returns: the #NAIIOProvider return code.
571 guint
572 na_updater_write_item( const NAUpdater *updater, NAObjectItem *item, GSList **messages )
574 guint ret;
576 ret = NA_IIO_PROVIDER_CODE_PROGRAM_ERROR;
578 g_return_val_if_fail( NA_IS_UPDATER( updater ), ret );
579 g_return_val_if_fail( NA_IS_OBJECT_ITEM( item ), ret );
580 g_return_val_if_fail( messages, ret );
582 if( !updater->private->dispose_has_run ){
584 NAIOProvider *provider = na_object_get_provider( item );
586 if( !provider ){
587 provider = na_io_provider_find_writable_io_provider( NA_PIVOT( updater ));
588 g_return_val_if_fail( provider, NA_IIO_PROVIDER_STATUS_NO_PROVIDER_FOUND );
591 if( provider ){
592 ret = na_io_provider_write_item( provider, item, messages );
596 return( ret );
600 * na_updater_delete_item:
601 * @updater: this #NAUpdater instance.
602 * @item: the #NAObjectItem to be deleted from the storage subsystem.
603 * @messages: the I/O provider can allocate and store here its error
604 * messages.
606 * Deletes an item, action or menu, from the I/O storage subsystem.
608 * Returns: the #NAIIOProvider return code.
610 * Note that a new item, not already written to an I/O subsystem,
611 * doesn't have any attached provider. We so do nothing and return OK...
613 guint
614 na_updater_delete_item( const NAUpdater *updater, const NAObjectItem *item, GSList **messages )
616 guint ret;
618 ret = NA_IIO_PROVIDER_CODE_PROGRAM_ERROR;
620 g_return_val_if_fail( NA_IS_UPDATER( updater ), ret );
621 g_return_val_if_fail( NA_IS_OBJECT_ITEM( item ), ret );
622 g_return_val_if_fail( messages, ret );
624 if( !updater->private->dispose_has_run ){
626 NAIOProvider *provider = na_object_get_provider( item );
627 g_return_val_if_fail( provider, ret );
629 ret = na_io_provider_delete_item( provider, item, messages );
632 return( ret );