Define new 'pivot-prop-loadable' property
[nautilus-actions.git] / src / core / na-updater.c
blobb32ad562ed4d6b804b91de8e6156d7225b2b9da7
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 );
206 * na_updater_are_preferences_locked:
207 * @updater: the #NAUpdater application object.
209 * Returns: %TRUE if preferences have been globally locked down by an
210 * admin, %FALSE else.
212 gboolean
213 na_updater_are_preferences_locked( const NAUpdater *updater )
215 gboolean are_locked;
217 g_return_val_if_fail( NA_IS_UPDATER( updater ), TRUE );
219 are_locked = TRUE;
221 if( !updater->private->dispose_has_run ){
223 are_locked = updater->private->are_preferences_locked;
226 return( are_locked );
230 * na_updater_is_item_writable:
231 * @updater: this #NAUpdater object.
232 * @item: the #NAObjectItem to be written.
233 * @reason: the reason for why @item may not be writable.
235 * Returns: %TRUE: if @item is actually writable, given the current
236 * status of its provider, %FALSE else.
238 * For an item be actually writable:
239 * - the item must not be itself in a read-only store, which has been
240 * checked when first reading it
241 * - the provider must be willing (resp. able) to write
242 * - the provider must not has been locked by the admin, nor by the user
244 * Note that this function does not consider if the item is to be written
245 * at the level zero of the tree, which may be a mandatory preference
246 * (i.e. locked by an admin), and so make this item unwritable.
248 gboolean
249 na_updater_is_item_writable( const NAUpdater *updater, const NAObjectItem *item, guint *reason )
251 gboolean writable;
252 NAIOProvider *provider;
254 g_return_val_if_fail( NA_IS_UPDATER( updater ), FALSE );
255 g_return_val_if_fail( NA_IS_OBJECT_ITEM( item ), FALSE );
257 writable = FALSE;
258 if( reason ){
259 *reason = NA_IIO_PROVIDER_STATUS_UNDETERMINED;
262 if( !updater->private->dispose_has_run ){
264 writable = TRUE;
265 if( reason ){
266 *reason = NA_IIO_PROVIDER_STATUS_WRITABLE;
269 /* Writability status of the item has been determined at load time
270 * (cf. e.g. io-desktop/nadp-reader.c:read_done_item_is_writable()).
271 * Though I'm plenty conscious that this status is subject to many
272 * changes during the life of the item (e.g. by modifying permissions
273 * on the underlying store), it is just more efficient to not reevaluate
274 * this status each time we need it, and enough for our needs..
276 if( writable ){
277 if( na_object_is_readonly( item )){
278 writable = FALSE;
279 if( reason ){
280 *reason = NA_IIO_PROVIDER_STATUS_ITEM_READONLY;
285 if( writable ){
286 provider = na_object_get_provider( item );
287 if( provider ){
288 writable = na_io_provider_is_finally_writable( provider, reason );
290 /* the get_writable_provider() api already takes care of above checks
292 } else {
293 provider = na_io_provider_find_writable_io_provider( NA_PIVOT( updater ));
294 if( !provider ){
295 writable = FALSE;
296 if( reason ){
297 *reason = NA_IIO_PROVIDER_STATUS_NO_PROVIDER_FOUND;
304 return( writable );
308 * na_updater_is_level_zero_writable:
309 * @updater: the #NAUpdater application object.
311 * As of 3.1.0, level-zero is written as a user preference.
313 * This function considers that the level_zero is writable if it is not
314 * a mandatory preference.
315 * Whether preferences themselves are or not globally locked is not
316 * considered here (as imho, level zero is not really and semantically
317 * part of user preferences).
319 * This function only considers the case of the level zero itself.
320 * It does not take into account whether the i/o provider (if any)
321 * is writable, or if the item iself is not read only.
323 * Returns: %TRUE if we are able to update the level-zero list of items,
324 * %FALSE else.
326 gboolean
327 na_updater_is_level_zero_writable( const NAUpdater *updater )
329 gboolean is_writable;
331 g_return_val_if_fail( NA_IS_UPDATER( updater ), FALSE );
333 is_writable = FALSE;
335 if( !updater->private->dispose_has_run ){
337 is_writable = updater->private->is_level_zero_writable;
340 return( is_writable );
343 static gboolean
344 are_preferences_locked( const NAUpdater *updater )
346 gboolean are_locked;
347 gboolean mandatory;
348 NASettings *settings;
350 settings = na_pivot_get_settings( NA_PIVOT( updater ));
351 are_locked = na_settings_get_boolean( settings, NA_IPREFS_ADMIN_PREFERENCES_LOCKED, NULL, &mandatory );
353 return( are_locked && mandatory );
356 static gboolean
357 is_level_zero_writable( const NAUpdater *updater )
359 GSList *level_zero;
360 gboolean mandatory;
362 level_zero = na_settings_get_string_list(
363 na_pivot_get_settings( NA_PIVOT( updater )), NA_IPREFS_ITEMS_LEVEL_ZERO_ORDER, NULL, &mandatory );
365 na_core_utils_slist_free( level_zero );
367 return( !mandatory );
371 * na_updater_append_item:
372 * @updater: this #NAUpdater object.
373 * @item: a #NAObjectItem-derived object to be appended to the tree.
375 * Append a new item at the end of the global tree.
377 void
378 na_updater_append_item( NAUpdater *updater, NAObjectItem *item )
380 GList *tree;
382 g_return_if_fail( NA_IS_UPDATER( updater ));
383 g_return_if_fail( NA_IS_OBJECT_ITEM( item ));
385 if( !updater->private->dispose_has_run ){
387 g_object_get( G_OBJECT( updater ), PIVOT_PROP_TREE, &tree, NULL );
388 tree = g_list_append( tree, item );
389 g_object_set( G_OBJECT( updater ), PIVOT_PROP_TREE, tree, NULL );
394 * na_updater_insert_item:
395 * @updater: this #NAUpdater object.
396 * @item: a #NAObjectItem-derived object to be inserted in the tree.
397 * @parent_id: the id of the parent, or %NULL.
398 * @pos: the position in the children of the parent, starting at zero, or -1.
400 * Insert a new item in the global tree.
402 void
403 na_updater_insert_item( NAUpdater *updater, NAObjectItem *item, const gchar *parent_id, gint pos )
405 GList *tree;
406 NAObjectItem *parent;
408 g_return_if_fail( NA_IS_UPDATER( updater ));
409 g_return_if_fail( NA_IS_OBJECT_ITEM( item ));
411 if( !updater->private->dispose_has_run ){
413 parent = NULL;
414 g_object_get( G_OBJECT( updater ), PIVOT_PROP_TREE, &tree, NULL );
416 if( parent_id ){
417 parent = na_pivot_get_item( NA_PIVOT( updater ), parent_id );
420 if( parent ){
421 na_object_insert_at( parent, item, pos );
423 } else {
424 tree = g_list_append( tree, item );
425 g_object_set( G_OBJECT( updater ), PIVOT_PROP_TREE, tree, NULL );
431 * na_updater_remove_item:
432 * @updater: this #NAPivot instance.
433 * @item: the #NAObjectItem to be removed from the list.
435 * Removes a #NAObjectItem from the hierarchical tree. Does not delete it.
437 void
438 na_updater_remove_item( NAUpdater *updater, NAObject *item )
440 GList *tree;
441 NAObjectItem *parent;
443 g_return_if_fail( NA_IS_PIVOT( updater ));
445 if( !updater->private->dispose_has_run ){
447 g_debug( "na_updater_remove_item: updater=%p, item=%p (%s)",
448 ( void * ) updater,
449 ( void * ) item, G_IS_OBJECT( item ) ? G_OBJECT_TYPE_NAME( item ) : "(null)" );
451 parent = na_object_get_parent( item );
452 if( parent ){
453 tree = na_object_get_items( parent );
454 tree = g_list_remove( tree, ( gconstpointer ) item );
455 na_object_set_items( parent, tree );
457 } else {
458 g_object_get( G_OBJECT( updater ), PIVOT_PROP_TREE, &tree, NULL );
459 tree = g_list_remove( tree, ( gconstpointer ) item );
460 g_object_set( G_OBJECT( updater ), PIVOT_PROP_TREE, tree, NULL );
466 * na_updater_should_pasted_be_relabeled:
467 * @updater: this #NAUpdater instance.
468 * @object: the considered #NAObject-derived object.
470 * Whether the specified object should be relabeled when pasted ?
472 * Returns: %TRUE if the object should be relabeled, %FALSE else.
474 gboolean
475 na_updater_should_pasted_be_relabeled( const NAUpdater *updater, const NAObject *item )
477 static const gchar *thisfn = "na_updater_should_pasted_be_relabeled";
478 gboolean relabel;
479 NASettings *settings;
481 settings = na_pivot_get_settings( NA_PIVOT( updater ));
483 if( NA_IS_OBJECT_MENU( item )){
484 relabel = na_settings_get_boolean( settings, NA_IPREFS_RELABEL_DUPLICATE_MENU, NULL, NULL );
486 } else if( NA_IS_OBJECT_ACTION( item )){
487 relabel = na_settings_get_boolean( settings, NA_IPREFS_RELABEL_DUPLICATE_ACTION, NULL, NULL );
489 } else if( NA_IS_OBJECT_PROFILE( item )){
490 relabel = na_settings_get_boolean( settings, NA_IPREFS_RELABEL_DUPLICATE_PROFILE, NULL, NULL );
492 } else {
493 g_warning( "%s: unknown item type at %p", thisfn, ( void * ) item );
494 g_return_val_if_reached( FALSE );
497 return( relabel );
501 * na_updater_load_items:
502 * @updater: this #NAUpdater instance.
504 * Loads the items, updating simultaneously their writability status.
506 * Returns: a pointer (not a ref) on the loaded tree.
508 * Since: 3.1.0
510 GList *
511 na_updater_load_items( NAUpdater *updater )
513 static const gchar *thisfn = "na_updater_load_items";
514 GList *tree;
516 g_return_val_if_fail( NA_IS_UPDATER( updater ), NULL );
518 tree = NULL;
520 if( !updater->private->dispose_has_run ){
521 g_debug( "%s: updater=%p (%s)", thisfn, ( void * ) updater, G_OBJECT_TYPE_NAME( updater ));
523 na_pivot_load_items( NA_PIVOT( updater ));
524 tree = na_pivot_get_items( NA_PIVOT( updater ));
525 g_list_foreach( tree, ( GFunc ) set_writability_status, ( gpointer ) updater );
528 return( tree );
531 static void
532 set_writability_status( NAObjectItem *item, const NAUpdater *updater )
534 gboolean writable;
535 guint reason;
536 GList *children;
538 writable = na_updater_is_item_writable( updater, item, &reason );
539 na_object_set_writability_status( item, writable, reason );
541 if( NA_IS_OBJECT_MENU( item )){
542 children = na_object_get_items( item );
543 g_list_foreach( children, ( GFunc ) set_writability_status, ( gpointer ) updater );
548 * na_updater_write_item:
549 * @updater: this #NAUpdater instance.
550 * @item: a #NAObjectItem to be written down to the storage subsystem.
551 * @messages: the I/O provider can allocate and store here its error
552 * messages.
554 * Writes an item (an action or a menu).
556 * Returns: the #NAIIOProvider return code.
558 guint
559 na_updater_write_item( const NAUpdater *updater, NAObjectItem *item, GSList **messages )
561 guint ret;
563 ret = NA_IIO_PROVIDER_CODE_PROGRAM_ERROR;
565 g_return_val_if_fail( NA_IS_UPDATER( updater ), ret );
566 g_return_val_if_fail( NA_IS_OBJECT_ITEM( item ), ret );
567 g_return_val_if_fail( messages, ret );
569 if( !updater->private->dispose_has_run ){
571 NAIOProvider *provider = na_object_get_provider( item );
573 if( !provider ){
574 provider = na_io_provider_find_writable_io_provider( NA_PIVOT( updater ));
575 g_return_val_if_fail( provider, NA_IIO_PROVIDER_STATUS_NO_PROVIDER_FOUND );
578 if( provider ){
579 ret = na_io_provider_write_item( provider, item, messages );
583 return( ret );
587 * na_updater_delete_item:
588 * @updater: this #NAUpdater instance.
589 * @item: the #NAObjectItem to be deleted from the storage subsystem.
590 * @messages: the I/O provider can allocate and store here its error
591 * messages.
593 * Deletes an item, action or menu, from the I/O storage subsystem.
595 * Returns: the #NAIIOProvider return code.
597 * Note that a new item, not already written to an I/O subsystem,
598 * doesn't have any attached provider. We so do nothing and return OK...
600 guint
601 na_updater_delete_item( const NAUpdater *updater, const NAObjectItem *item, GSList **messages )
603 guint ret;
605 ret = NA_IIO_PROVIDER_CODE_PROGRAM_ERROR;
607 g_return_val_if_fail( NA_IS_UPDATER( updater ), ret );
608 g_return_val_if_fail( NA_IS_OBJECT_ITEM( item ), ret );
609 g_return_val_if_fail( messages, ret );
611 if( !updater->private->dispose_has_run ){
613 NAIOProvider *provider = na_object_get_provider( item );
614 g_return_val_if_fail( provider, ret );
616 ret = na_io_provider_delete_item( provider, item, messages );
619 return( ret );