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.
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)
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"
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
);
70 na_updater_get_type( void )
72 static GType object_type
= 0;
75 object_type
= register_type();
78 return( object_type
);
84 static const gchar
*thisfn
= "na_updater_register_type";
87 static GTypeInfo info
= {
88 sizeof( NAUpdaterClass
),
89 ( GBaseInitFunc
) NULL
,
90 ( GBaseFinalizeFunc
) NULL
,
91 ( GClassInitFunc
) class_init
,
96 ( GInstanceInitFunc
) instance_init
99 g_debug( "%s", thisfn
);
101 type
= g_type_register_static( NA_PIVOT_TYPE
, "NAUpdater", &info
, 0 );
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 );
124 instance_init( GTypeInstance
*instance
, gpointer klass
)
126 static const gchar
*thisfn
= "na_updater_instance_init";
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
;
142 instance_dispose( GObject
*object
)
144 static const gchar
*thisfn
= "na_updater_instance_dispose";
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
);
165 instance_finalize( GObject
*object
)
167 static const gchar
*thisfn
= "na_updater_instance_finalize";
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
);
187 * Returns: a newly allocated #NAUpdater object.
190 na_updater_new( void )
192 static const gchar
*thisfn
= "na_updater_new";
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
);
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.
213 na_updater_are_preferences_locked( const NAUpdater
*updater
)
217 g_return_val_if_fail( NA_IS_UPDATER( updater
), 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.
249 na_updater_is_item_writable( const NAUpdater
*updater
, const NAObjectItem
*item
, guint
*reason
)
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
);
259 *reason
= NA_IIO_PROVIDER_STATUS_UNDETERMINED
;
262 if( !updater
->private->dispose_has_run
){
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..
277 if( na_object_is_readonly( item
)){
280 *reason
= NA_IIO_PROVIDER_STATUS_ITEM_READONLY
;
286 provider
= na_object_get_provider( item
);
288 writable
= na_io_provider_is_finally_writable( provider
, reason
);
290 /* the get_writable_provider() api already takes care of above checks
293 provider
= na_io_provider_find_writable_io_provider( NA_PIVOT( updater
));
297 *reason
= NA_IIO_PROVIDER_STATUS_NO_PROVIDER_FOUND
;
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,
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
);
335 if( !updater
->private->dispose_has_run
){
337 is_writable
= updater
->private->is_level_zero_writable
;
340 return( is_writable
);
344 are_preferences_locked( const NAUpdater
*updater
)
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
);
357 is_level_zero_writable( const NAUpdater
*updater
)
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.
378 na_updater_append_item( NAUpdater
*updater
, NAObjectItem
*item
)
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.
403 na_updater_insert_item( NAUpdater
*updater
, NAObjectItem
*item
, const gchar
*parent_id
, gint pos
)
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
){
414 g_object_get( G_OBJECT( updater
), PIVOT_PROP_TREE
, &tree
, NULL
);
417 parent
= na_pivot_get_item( NA_PIVOT( updater
), parent_id
);
421 na_object_insert_at( parent
, item
, pos
);
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.
438 na_updater_remove_item( NAUpdater
*updater
, NAObject
*item
)
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)",
449 ( void * ) item
, G_IS_OBJECT( item
) ? G_OBJECT_TYPE_NAME( item
) : "(null)" );
451 parent
= na_object_get_parent( item
);
453 tree
= na_object_get_items( parent
);
454 tree
= g_list_remove( tree
, ( gconstpointer
) item
);
455 na_object_set_items( parent
, tree
);
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.
475 na_updater_should_pasted_be_relabeled( const NAUpdater
*updater
, const NAObject
*item
)
477 static const gchar
*thisfn
= "na_updater_should_pasted_be_relabeled";
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
);
493 g_warning( "%s: unknown item type at %p", thisfn
, ( void * ) item
);
494 g_return_val_if_reached( FALSE
);
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.
511 na_updater_load_items( NAUpdater
*updater
)
513 static const gchar
*thisfn
= "na_updater_load_items";
516 g_return_val_if_fail( NA_IS_UPDATER( updater
), 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
);
532 set_writability_status( NAObjectItem
*item
, const NAUpdater
*updater
)
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
554 * Writes an item (an action or a menu).
556 * Returns: the #NAIIOProvider return code.
559 na_updater_write_item( const NAUpdater
*updater
, NAObjectItem
*item
, GSList
**messages
)
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
);
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
);
579 ret
= na_io_provider_write_item( provider
, item
, messages
);
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
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...
601 na_updater_delete_item( const NAUpdater
*updater
, const NAObjectItem
*item
, GSList
**messages
)
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
);