[nautilus-actions] Prevent a drop inside of a read-only item



commit 62cd211e9e1001285ae9f5dccd74581ce52b5e5a
Author: Pierre Wieser <pwieser trychlos org>
Date:   Wed Dec 16 22:34:21 2009 +0100

    Prevent a drop inside of a read-only item
    
    The change is accompanied by a modified of plugin nad NAIIOProvider apis.

 ChangeLog                                          |   47 ++++++++
 TODO                                               |   11 +-
 doc/io-provider-id                                 |   15 ++-
 nautilus-actions/api/na-api.h                      |   51 ++++-----
 nautilus-actions/api/na-iio-provider.h             |   17 +++-
 .../io-provider-desktop/nadp-desktop-provider.c    |    9 ++
 nautilus-actions/io-provider-desktop/nadp-module.c |   73 +++++-------
 .../io-provider-gconf/nagp-gconf-provider.c        |    9 ++
 nautilus-actions/io-provider-gconf/nagp-module.c   |   73 +++++-------
 nautilus-actions/nact/nact-tree-model-dnd.c        |   98 ++++++++++++++--
 nautilus-actions/nact/nact-window.c                |    5 +-
 nautilus-actions/runtime/na-io-provider.c          |   73 +++++++++++-
 nautilus-actions/runtime/na-io-provider.h          |   19 ++--
 nautilus-actions/runtime/na-module.c               |  122 ++++++++-----------
 nautilus-actions/runtime/na-module.h               |   35 +++++-
 nautilus-actions/runtime/na-pivot.c                |  114 +++++--------------
 nautilus-actions/runtime/na-pivot.h                |    6 +-
 nautilus-actions/runtime/na-utils.c                |   27 +++++
 nautilus-actions/runtime/na-utils.h                |    2 +
 nautilus-actions/utils/nautilus-actions-new.c      |   13 ++-
 po/POTFILES.in                                     |    2 +
 21 files changed, 500 insertions(+), 321 deletions(-)
---
diff --git a/ChangeLog b/ChangeLog
index 6767952..80a18c9 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,50 @@
+2009-12-16 Pierre Wieser <pwieser trychlos org>
+
+	* nautilus-actions/api/na-api.h (na_api_module_get_name):
+	* nautilus-actions/api/na-iio-provider.h (get_name):
+	The na_api_module_get_name() function is moved to NAIIOProvider
+	interface as get_name().
+
+	* nautilus-actions/io-provider-desktop/nadp-desktop-provider.c
+	* nautilus-actions/io-provider-gconf/nagp-gconf-provider.c
+	(get_name): New function.
+
+	* nautilus-actions/io-provider-desktop/nadp-module.c
+	* nautilus-actions/io-provider-gconf/nagp-module.c
+	(na_api_module_get_name): Removed function.
+
+	* nautilus-actions/nact/nact-tree-model-dnd.c
+	(is_parent_accept_new_childs): New function.
+	Prevent drop inside of a read-only parent.
+
+	* nautilus-actions/nact/nact-window.c
+	(nact_window_has_writable_providers):
+	Updated to no more use na_pivot_has_writable_providers().
+
+	* nautilus-actions/runtime/na-io-provider.c
+	* nautilus-actions/runtime/na-io-provider.h
+	(na_io_provider_get_provider, na_io_provider_get_writable_provider):
+	New functions.
+
+	* nautilus-actions/runtime/na-module.c
+	* nautilus-actions/runtime/na-module.h
+	(na_module_dump): New function.
+	(na_module_get_name): Removed function.
+
+	* nautilus-actions/runtime/na-pivot.c:
+	* nautilus-actions/runtime/na-pivot.h
+	(na_pivot_get_module_name, na_pivot_get_provider,
+	na_pivot_release_provider, na_pivot_has_writable_providers):
+	Removed functions.
+	(na_pivot_is_level_zero_writable): New function.
+
+	* nautilus-actions/runtime/na-utils.c:
+	* nautilus-actions/runtime/na-utils.h
+	(na_utils_remove_suffix): New function.
+
+	* nautilus-actions/utils/nautilus-actions-new.c (write_to_gconf):
+	Updated to find a writable provider.
+
 2009-12-15 Pierre Wieser <pwieser trychlos org>
 
 	Split too big file nact-tree-model.c.
diff --git a/TODO b/TODO
index 51b50bd..616ad66 100644
--- a/TODO
+++ b/TODO
@@ -76,6 +76,7 @@
 
 - nautilus-actions-new:
   give same defaults that when creating an action in NACT
+  choose the target I/O provider
 
 - NACT: unable to really delete an action imported with schemas
   2009-11-21 (2.29.2-provider) not able to reproduce this, whether the
@@ -91,12 +92,12 @@
 
 - have a preference to record order of IO Providers
 
-- do we may have a read-only menu ?
-  this implies dnd of an action inside of the menu would be forbidden
-  id. for reordering if subitems
-
 - nact: new action assistant
 
 - desktop provider: fix default toolbar label
 
-- setup tree-model dnd code when item or parent is readonly
+- DBus service: list current I/O providers
+
+- DBus service: import/export an action or a menu
+
+- tracker: have auto-introspection
diff --git a/doc/io-provider-id b/doc/io-provider-id
index ec28386..8f0fa9a 100644
--- a/doc/io-provider-id
+++ b/doc/io-provider-id
@@ -1,10 +1,13 @@
-Id's of I/O providers.
+Ids of I/O providers.
+=====================
 
-These Id's are allocated by the Nautilus-Actions maintainer team.
+These ids are allocated by the Nautilus-Actions maintainer team.
 If you wish develop a new I/O provider, and so need a unique id,
 please contact the maintainers (see nautilus-actions.doap).
 
-id          label                   holder
-----------  ----------------------  ----------------
-na-desktop  NA Desktop IO Provider  Nautilus-Actions
-na-gconf    NA GConf IO Provider    Nautilus-Actions
+id          label                   holder            allocated
+----------  ----------------------  ----------------  ----------
+na-desktop  NA Desktop IO Provider  Nautilus-Actions  2009-12-16
+na-gconf    NA GConf IO Provider    Nautilus-Actions  2009-12-16
+
+Last updated: 2009, Dec. 16th.
diff --git a/nautilus-actions/api/na-api.h b/nautilus-actions/api/na-api.h
index ec895b9..bd913ed 100644
--- a/nautilus-actions/api/na-api.h
+++ b/nautilus-actions/api/na-api.h
@@ -57,10 +57,25 @@ G_BEGIN_DECLS
  * The dynamically loaded library may benefit of being triggered by
  * initializing itself, registering its internal GTypes, etc.
  * It should at least register module GTypes it provides.
+ *
+ * All N-A modules must implement this function.
+ *
+ * Returns: %TRUE if the initialization is successfull, %FALSE else.
+ * In this later case, the plugin is unloaded.
  */
 gboolean     na_api_module_init       ( GTypeModule *module );
 
 /**
+ * na_api_module_get_version:
+ *
+ * Returns: the version of this API supported by the module.
+ *
+ * If this function is not implemented by the plugin, the loader
+ * considers that the plugin only implements version 1 of this API.
+ */
+guint        na_api_module_get_version( void );
+
+/**
  * na_api_module_list_types:
  * @types: the array of #GType this dynamically library implements.
  *
@@ -68,38 +83,18 @@ gboolean     na_api_module_init       ( GTypeModule *module );
  * internal GTypes implemented by the dynamically loaded library.
  *
  * Returned GTypes should already have been registered in GType system
- * (e.g. via na_api_module_init), and may implement one or more of the
- * interfaces defined in Nautilus-Actions API.
+ * (e.g. at na_api_module_init() time), and may implement one or more of
+ * the interfaces defined in Nautilus-Actions API.
  *
- * One object will be instantiated by Nautilus-Actions for each returned
+ * One GObject will be instantiated by Nautilus-Actions for each returned
  * GType.
  *
- * Returns: the number of GTypes item in the @types array.
- */
-gint         na_api_module_list_types ( const GType **types );
-
-/**
- * na_api_module_get_name:
- * @type: the library #GType for which Nautilus-Actions wish the name.
- *
- * Returns: the name to be associated with this @type.
- *
- * Nautilus-Actions may ask the dynamically loadable library for a
- * name associated to each #GType the library had previously declared.
- * This is generally to be displayed in a user interface ; the name
- * may be localized.
- */
-const gchar *na_api_module_get_name   ( GType type );
-
-/**
- * na_api_module_get_version:
- *
- * Returns: the version of this API supported by the module.
+ * All N-A modules must implement this functon, possibly returning an
+ * empty list.
  *
- * The module should really implement this function as the default is
- * to not implement any API at all.
+ * Returns: the number of GTypes item in the @types array.
  */
-guint        na_api_module_get_version( void );
+guint        na_api_module_list_types ( const GType **types );
 
 /**
  * na_api_module_shutdown:
@@ -109,6 +104,8 @@ guint        na_api_module_get_version( void );
  *
  * The dynamicaly loaded library may benefit of this call to release
  * any resource it may have previously allocated.
+ *
+ * All N-A modules must implement this function.
  */
 void         na_api_module_shutdown   ( void );
 
diff --git a/nautilus-actions/api/na-iio-provider.h b/nautilus-actions/api/na-iio-provider.h
index 014f4b8..8540df8 100644
--- a/nautilus-actions/api/na-iio-provider.h
+++ b/nautilus-actions/api/na-iio-provider.h
@@ -60,7 +60,7 @@ typedef struct {
 	NAIIOProviderInterfacePrivate *private;
 
 	/*
-	 * This is the API the provider has to implement.
+	 * This is the API the I/O providers have to implement.
 	 */
 
 	/**
@@ -75,17 +75,28 @@ typedef struct {
 	 * provider, and so need a new provider id, please contact the
 	 * maintainers (see nautilus-actions.doap).
 	 *
-	 * The provider must implement this function.
+	 * The I/O provider must implement this function.
 	 */
 	gchar *  ( *get_id )             ( const NAIIOProvider *instance );
 
 	/**
+	 * get_name:
+	 * @instance: the #NAIIOProvider provider.
+	 *
+	 * Returns: the name to be displayed for this I/O provider as a
+	 * newly allocated string which should be g_free() by the caller.
+	 *
+	 * Defaults to an empty string.
+	 */
+	gchar *  ( *get_name )           ( const NAIIOProvider *instance );
+
+	/**
 	 * get_version:
 	 * @instance: the #NAIIOProvider provider.
 	 *
 	 * Returns: the version of this API supported by the IO provider.
 	 *
-	 * The provider must implement this function.
+	 * Defaults to 1.
 	 */
 	guint    ( *get_version )        ( const NAIIOProvider *instance );
 
diff --git a/nautilus-actions/io-provider-desktop/nadp-desktop-provider.c b/nautilus-actions/io-provider-desktop/nadp-desktop-provider.c
index 37f1fe5..0dc6acb 100644
--- a/nautilus-actions/io-provider-desktop/nadp-desktop-provider.c
+++ b/nautilus-actions/io-provider-desktop/nadp-desktop-provider.c
@@ -32,6 +32,7 @@
 #include <config.h>
 #endif
 
+#include <glib/gi18n.h>
 #include <string.h>
 
 #include <nautilus-actions/api/na-iio-provider.h>
@@ -62,6 +63,7 @@ static void   instance_dispose( GObject *object );
 static void   instance_finalize( GObject *object );
 
 static gchar *get_id( const NAIIOProvider *provider );
+static gchar *get_name( const NAIIOProvider *provider );
 static guint  get_version( const NAIIOProvider *provider );
 
 GType
@@ -125,6 +127,7 @@ iio_provider_iface_init( NAIIOProviderInterface *iface )
 	g_debug( "%s: iface=%p", thisfn, ( void * ) iface );
 
 	iface->get_id = get_id;
+	iface->get_name = get_name;
 	iface->get_version = get_version;
 	iface->read_items = nadp_iio_provider_read_items;
 	iface->is_willing_to_write = nadp_iio_provider_is_willing_to_write;
@@ -191,6 +194,12 @@ get_id( const NAIIOProvider *provider )
 	return( g_strdup( "na-desktop" ));
 }
 
+static gchar *
+get_name( const NAIIOProvider *provider )
+{
+	return( g_strdup( _( "Nautilus-Actions Desktop I/O Provider" )));
+}
+
 static guint
 get_version( const NAIIOProvider *provider )
 {
diff --git a/nautilus-actions/io-provider-desktop/nadp-module.c b/nautilus-actions/io-provider-desktop/nadp-module.c
index 3561416..f51466f 100644
--- a/nautilus-actions/io-provider-desktop/nadp-module.c
+++ b/nautilus-actions/io-provider-desktop/nadp-module.c
@@ -39,35 +39,46 @@
 #include "nadp-desktop-provider.h"
 
 /*
- * A Nautilus-Actions extension must implement four functions :
+ * na_api_module_init:
  *
- * - na_api_module_init
- * - na_api_module_list_types
- * - na_api_module_get_name
- * - na_api_module_shutdown
- *
- * The first two functions are called at Nautilus-Actions startup.
- *
- * The prototypes for these functions are defined in
- * nautilus-actions/api/na-api.h
+ * mandatory starting with API v. 1.
  */
-
 gboolean
 na_api_module_init( GTypeModule *module )
 {
 	static const gchar *thisfn = "nadp_module_na_api_module_initialize";
-	static const gchar *name = "NadpDesktopIOProvider";
 
 	g_debug( "%s: module=%p", thisfn, ( void * ) module );
 
-	g_type_module_set_name( module, name );
-
 	nadp_desktop_provider_register_type( module );
 
 	return( TRUE );
 }
 
-gint
+/*
+ * na_api_module_get_version:
+ *
+ * optional, defaults to 1.
+ */
+guint
+na_api_module_get_version( void )
+{
+	static const gchar *thisfn = "nadp_module_na_api_module_get_version";
+	guint version;
+
+	version = 1;
+
+	g_debug( "%s: version=%d", thisfn, version );
+
+	return( version );
+}
+
+/*
+ * na_api_module_list_types:
+ *
+ * mandatory starting with v. 1.
+ */
+guint
 na_api_module_list_types( const GType **types )
 {
 	static const gchar *thisfn = "nadp_module_na_api_module_list_types";
@@ -82,33 +93,11 @@ na_api_module_list_types( const GType **types )
 	return( count );
 }
 
-const gchar *
-na_api_module_get_name( GType type )
-{
-	static const gchar *thisfn = "nadp_module_na_api_module_get_name";
-
-	g_debug( "%s: type=%ld", thisfn, ( gulong ) type );
-
-	if( type == NADP_DESKTOP_PROVIDER_TYPE ){
-		return( "Nautilus-Actions Desktop IO Provider" );
-	}
-
-	return( NULL );
-}
-
-guint
-na_api_module_get_version( void )
-{
-	static const gchar *thisfn = "nadp_module_na_api_module_get_version";
-	guint version;
-
-	version = 1;
-
-	g_debug( "%s: version=%d", thisfn, version );
-
-	return( version );
-}
-
+/*
+ * na_api_module_shutdown:
+ *
+ * mandatory starting with v. 1.
+ */
 void
 na_api_module_shutdown( void )
 {
diff --git a/nautilus-actions/io-provider-gconf/nagp-gconf-provider.c b/nautilus-actions/io-provider-gconf/nagp-gconf-provider.c
index b3cef41..5ecd859 100644
--- a/nautilus-actions/io-provider-gconf/nagp-gconf-provider.c
+++ b/nautilus-actions/io-provider-gconf/nagp-gconf-provider.c
@@ -32,6 +32,7 @@
 #include <config.h>
 #endif
 
+#include <glib/gi18n.h>
 #include <string.h>
 
 #include <nautilus-actions/api/na-iio-provider.h>
@@ -60,6 +61,7 @@ static void     instance_dispose( GObject *object );
 static void     instance_finalize( GObject *object );
 
 static gchar   *get_id( const NAIIOProvider *provider );
+static gchar   *get_name( const NAIIOProvider *provider );
 static guint    get_version( const NAIIOProvider *provider );
 
 static GList   *install_monitors( NagpGConfProvider *provider );
@@ -131,6 +133,7 @@ iio_provider_iface_init( NAIIOProviderInterface *iface )
 	g_debug( "%s: iface=%p", thisfn, ( void * ) iface );
 
 	iface->get_id = get_id;
+	iface->get_name = get_name;
 	iface->get_version = get_version;
 	iface->read_items = nagp_iio_provider_read_items;
 	iface->is_willing_to_write = nagp_iio_provider_is_willing_to_write;
@@ -205,6 +208,12 @@ get_id( const NAIIOProvider *provider )
 	return( g_strdup( "na-gconf" ));
 }
 
+static gchar *
+get_name( const NAIIOProvider *provider )
+{
+	return( g_strdup( _( "Nautilus-Actions GConf I/O Provider" )));
+}
+
 static guint
 get_version( const NAIIOProvider *provider )
 {
diff --git a/nautilus-actions/io-provider-gconf/nagp-module.c b/nautilus-actions/io-provider-gconf/nagp-module.c
index 565e8cd..04dd6a0 100644
--- a/nautilus-actions/io-provider-gconf/nagp-module.c
+++ b/nautilus-actions/io-provider-gconf/nagp-module.c
@@ -39,35 +39,46 @@
 #include "nagp-gconf-provider.h"
 
 /*
- * A Nautilus-Actions extension must implement four functions :
+ * na_api_module_init:
  *
- * - na_api_module_init
- * - na_api_module_list_types
- * - na_api_module_get_name
- * - na_api_module_shutdown
- *
- * The first two functions are called at Nautilus-Actions startup.
- *
- * The prototypes for these functions are defined in
- * nautilus-actions/api/na-api.h
+ * mandatory starting with API v. 1.
  */
-
 gboolean
 na_api_module_init( GTypeModule *module )
 {
 	static const gchar *thisfn = "nagp_module_na_api_module_initialize";
-	static const gchar *name = "NagpGConfIOProvider";
 
 	g_debug( "%s: module=%p", thisfn, ( void * ) module );
 
-	g_type_module_set_name( module, name );
-
 	nagp_gconf_provider_register_type( module );
 
 	return( TRUE );
 }
 
-gint
+/*
+ * na_api_module_get_version:
+ *
+ * optional, defaults to 1.
+ */
+guint
+na_api_module_get_version( void )
+{
+	static const gchar *thisfn = "nagp_module_na_api_module_get_version";
+	guint version;
+
+	version = 1;
+
+	g_debug( "%s: version=%d", thisfn, version );
+
+	return( version );
+}
+
+/*
+ * na_api_module_list_types:
+ *
+ * mandatory starting with v. 1.
+ */
+guint
 na_api_module_list_types( const GType **types )
 {
 	static const gchar *thisfn = "nagp_module_na_api_module_list_types";
@@ -82,33 +93,11 @@ na_api_module_list_types( const GType **types )
 	return( count );
 }
 
-const gchar *
-na_api_module_get_name( GType type )
-{
-	static const gchar *thisfn = "nagp_module_na_api_module_get_name";
-
-	g_debug( "%s: type=%ld", thisfn, ( gulong ) type );
-
-	if( type == NAGP_GCONF_PROVIDER_TYPE ){
-		return( "Nautilus-Actions GConf IO Provider" );
-	}
-
-	return( NULL );
-}
-
-guint
-na_api_module_get_version( void )
-{
-	static const gchar *thisfn = "nagp_module_na_api_module_get_version";
-	guint version;
-
-	version = 1;
-
-	g_debug( "%s: version=%d", thisfn, version );
-
-	return( version );
-}
-
+/*
+ * na_api_module_shutdown:
+ *
+ * mandatory starting with v. 1.
+ */
 void
 na_api_module_shutdown( void )
 {
diff --git a/nautilus-actions/nact/nact-tree-model-dnd.c b/nautilus-actions/nact/nact-tree-model-dnd.c
index 8624c4b..98a6066 100644
--- a/nautilus-actions/nact/nact-tree-model-dnd.c
+++ b/nautilus-actions/nact/nact-tree-model-dnd.c
@@ -35,6 +35,7 @@
 #include <api/na-object-api.h>
 
 #include <runtime/na-iprefs.h>
+#include <runtime/na-io-provider.h>
 #include <runtime/na-utils.h>
 
 #include "nact-application.h"
@@ -111,11 +112,17 @@ GtkTargetEntry tree_model_dnd_dest_formats[] = {
 
 guint tree_model_dnd_dest_formats_count = G_N_ELEMENTS( tree_model_dnd_dest_formats );
 
+static const gchar *st_refuse_profile = N_( "Unable to drop a profile here" );
+static const gchar *st_refuse_action_menu = N_( "Unable to drop an action or a menu here" );
+static const gchar *st_parent_not_writable = N_( "Unable to drop here as parent is not writable" );
+static const gchar *st_level_zero_not_writable = N_( "Unable to drop here as level zero is not writable" );
+
 static gboolean     drop_inside( NactTreeModel *model, GtkTreePath *dest, GtkSelectionData  *selection_data );
 static GtkTreePath *drop_inside_adjust_dest( NactTreeModel *model, GtkTreePath *dest, NAObjectAction **parent );
 static void         drop_inside_move_dest( NactTreeModel *model, GList *rows, GtkTreePath **dest );
 static gboolean     drop_uri_list( NactTreeModel *model, GtkTreePath *dest, GtkSelectionData  *selection_data );
 static char        *get_xds_atom_value( GdkDragContext *context );
+static gboolean     is_parent_accept_new_childs( NactTreeModel *model, GtkTreePath *path );
 static guint        target_atom_to_id( GdkAtom atom );
 
 /**
@@ -198,7 +205,9 @@ nact_tree_model_dnd_idrag_dest_drag_data_received( GtkTreeDragDest *drag_dest, G
  * @dest_path:
  * @selection_data:
  *
- * Called when the source and the dest are not at the same tree level ?
+ * Seems to only be called when the drop in _on_ a row (a square is
+ * displayed), but not when dropped between two rows (a line is displayed),
+ * nor during the motion.
  */
 gboolean
 nact_tree_model_dnd_idrag_dest_row_drop_possible( GtkTreeDragDest *drag_dest, GtkTreePath *dest_path, GtkSelectionData *selection_data )
@@ -398,9 +407,12 @@ nact_tree_model_dnd_imulti_drag_source_row_draggable( EggTreeMultiDragSource *dr
 
 /**
  * nact_tree_model_dnd_on_drag_begin:
- * @widget:
+ * @widget: the GtkTreeView from which item is to be dragged.
  * @context:
- * @window:
+ * @window: the parent #NactMainWindow instance.
+ *
+ * This function is called once, at the beginning of the drag operation,
+ * when we are dragging from the IActionsList treeview.
  */
 void
 nact_tree_model_dnd_on_drag_begin( GtkWidget *widget, GdkDragContext *context, BaseWindow *window )
@@ -499,8 +511,6 @@ drop_inside( NactTreeModel *model, GtkTreePath *dest, GtkSelectionData  *selecti
 	 * NACT format (may embed profiles, or not)
 	 * 	with profiles: only valid dest is inside an action
 	 *  without profile: only valid dest is outside (besides of) an action
-	 * URI format only involves actions
-	 *  ony valid dest in outside (besides of) an action
 	 */
 	drop_done = FALSE;
 	parent = NULL;
@@ -569,8 +579,6 @@ static GtkTreePath *
 drop_inside_adjust_dest( NactTreeModel *model, GtkTreePath *dest, NAObjectAction **parent )
 {
 	static const gchar *thisfn = "nact_tree_model_drop_inside_adjust_dest";
-	static const gchar *refuse_profile = N_( "Unable to drop a profile here" );
-	static const gchar *refuse_action_menu = N_( "Unable to drop an action or a menu here" );
 	GtkTreePath *new_dest;
 	gboolean drop_ok;
 	NactApplication *application;
@@ -603,7 +611,7 @@ drop_inside_adjust_dest( NactTreeModel *model, GtkTreePath *dest, NAObjectAction
 				}
 			} else {
 				nact_main_statusbar_display_with_timeout(
-						main_window, TREE_MODEL_STATUSBAR_CONTEXT, refuse_profile );
+						main_window, TREE_MODEL_STATUSBAR_CONTEXT, st_refuse_profile );
 			}
 
 		} else {
@@ -611,7 +619,7 @@ drop_inside_adjust_dest( NactTreeModel *model, GtkTreePath *dest, NAObjectAction
 				drop_ok = TRUE;
 			} else {
 				nact_main_statusbar_display_with_timeout(
-						main_window, TREE_MODEL_STATUSBAR_CONTEXT, refuse_action_menu );
+						main_window, TREE_MODEL_STATUSBAR_CONTEXT, st_refuse_action_menu );
 			}
 		}
 
@@ -620,7 +628,7 @@ drop_inside_adjust_dest( NactTreeModel *model, GtkTreePath *dest, NAObjectAction
 	} else if( gtk_tree_path_get_depth( dest ) == 1 ){
 		if( model->private->drag_has_profiles ){
 			nact_main_statusbar_display_with_timeout(
-						main_window, TREE_MODEL_STATUSBAR_CONTEXT, refuse_profile );
+						main_window, TREE_MODEL_STATUSBAR_CONTEXT, st_refuse_profile );
 		} else {
 			drop_ok = TRUE;
 		}
@@ -653,7 +661,7 @@ drop_inside_adjust_dest( NactTreeModel *model, GtkTreePath *dest, NAObjectAction
 
 					} else {
 						nact_main_statusbar_display_with_timeout(
-								main_window, TREE_MODEL_STATUSBAR_CONTEXT, refuse_profile );
+								main_window, TREE_MODEL_STATUSBAR_CONTEXT, st_refuse_profile );
 					}
 
 				} else {
@@ -661,7 +669,7 @@ drop_inside_adjust_dest( NactTreeModel *model, GtkTreePath *dest, NAObjectAction
 						drop_ok = TRUE;
 					} else {
 						nact_main_statusbar_display_with_timeout(
-								main_window, TREE_MODEL_STATUSBAR_CONTEXT, refuse_action_menu );
+								main_window, TREE_MODEL_STATUSBAR_CONTEXT, st_refuse_action_menu );
 					}
 				}
 			}
@@ -669,6 +677,10 @@ drop_inside_adjust_dest( NactTreeModel *model, GtkTreePath *dest, NAObjectAction
 		gtk_tree_path_free( path );
 	}
 
+	if( drop_ok && !is_parent_accept_new_childs( model, new_dest )){
+		drop_ok = FALSE;
+	}
+
 	if( !drop_ok ){
 		gtk_tree_path_free( new_dest );
 		new_dest = NULL;
@@ -724,6 +736,9 @@ drop_inside_move_dest( NactTreeModel *model, GList *rows, GtkTreePath **dest )
  *
  * Returns: %TRUE if the specified rows were successfully inserted at
  * the given dest, %FALSE else.
+ *
+ * URI format only involves actions
+ *  so ony valid dest in outside (besides of) an action
  */
 static gboolean
 drop_uri_list( NactTreeModel *model, GtkTreePath *dest, GtkSelectionData  *selection_data )
@@ -910,6 +925,65 @@ get_xds_atom_value( GdkDragContext *context )
 	return ret;
 }
 
+/*
+ * when dropping something somewhere, we must ensure that we will be able
+ * to register the new child
+ */
+static gboolean
+is_parent_accept_new_childs( NactTreeModel *model, GtkTreePath *path )
+{
+	gboolean accept_ok;
+	GtkTreePath *parent_path;
+	GtkTreeIter iter;
+	NAObjectItem *parent_item;
+	NactApplication *application;
+	NAPivot *pivot;
+	NAIIOProvider *provider;
+	NactMainWindow *main_window;
+
+	accept_ok = FALSE;
+	application = NACT_APPLICATION( base_window_get_application( model->private->window ));
+	pivot = nact_application_get_pivot( application );
+	main_window = NACT_MAIN_WINDOW( base_application_get_main_window( BASE_APPLICATION( application )));
+
+	/* inserting as a level zero item
+	 * ensure that level zero is writable
+	 */
+	if( gtk_tree_path_get_depth( path ) == 1 ){
+
+		if( na_pivot_is_level_zero_writable( pivot )){
+			accept_ok = TRUE;
+
+		} else {
+			nact_main_statusbar_display_with_timeout(
+						main_window, TREE_MODEL_STATUSBAR_CONTEXT, st_level_zero_not_writable );
+		}
+
+	/* see if the parent is writable
+	 */
+	} else {
+		parent_path = gtk_tree_path_copy( path );
+		if( gtk_tree_model_get_iter( GTK_TREE_MODEL( model ), &iter, parent_path )){
+			gtk_tree_model_get( GTK_TREE_MODEL( model ), &iter, IACTIONS_LIST_NAOBJECT_COLUMN, &parent_item, -1 );
+			if( !na_object_is_readonly( parent_item )){
+				provider = na_object_get_provider( parent_item );
+				if( na_io_provider_is_willing_to_write( pivot, provider )){
+					accept_ok = TRUE;
+				}
+			}
+			g_object_unref( parent_item );
+		}
+		gtk_tree_path_free( parent_path );
+
+		if( !accept_ok ){
+			nact_main_statusbar_display_with_timeout(
+						main_window, TREE_MODEL_STATUSBAR_CONTEXT, st_parent_not_writable );
+		}
+	}
+
+	return( accept_ok );
+}
+
 static guint
 target_atom_to_id( GdkAtom atom )
 {
diff --git a/nautilus-actions/nact/nact-window.c b/nautilus-actions/nact/nact-window.c
index 782f91f..ddeab2e 100644
--- a/nautilus-actions/nact/nact-window.c
+++ b/nautilus-actions/nact/nact-window.c
@@ -242,6 +242,7 @@ nact_window_has_writable_providers( NactWindow *window )
 {
 	gboolean has_writables;
 	NAPivot *pivot;
+	NAIIOProvider *provider;
 
 	has_writables = FALSE;
 
@@ -250,7 +251,9 @@ nact_window_has_writable_providers( NactWindow *window )
 	if( !window->private->dispose_has_run ){
 
 		pivot = nact_window_get_pivot( window );
-		has_writables = na_pivot_has_writable_providers( pivot );
+		provider = na_io_provider_get_writable_provider( pivot );
+		has_writables = ( provider != NULL );
+		g_object_unref( provider );
 	}
 
 	return( has_writables );
diff --git a/nautilus-actions/runtime/na-io-provider.c b/nautilus-actions/runtime/na-io-provider.c
index 1372150..380591b 100644
--- a/nautilus-actions/runtime/na-io-provider.c
+++ b/nautilus-actions/runtime/na-io-provider.c
@@ -77,6 +77,70 @@ na_io_provider_register_callbacks( const NAPivot *pivot )
 }
 
 /**
+ * na_io_provider_get_provider:
+ * @pivot: the #NAPivot object.
+ * @id: the id of the searched I/O provider.
+ *
+ * Returns: the found I/O provider, or NULL.
+ *
+ * The returned provider should be g_object_unref() by the caller.
+ */
+NAIIOProvider *
+na_io_provider_get_provider( const NAPivot *pivot, const gchar *id )
+{
+	NAIIOProvider *provider;
+	GList *providers, *ip;
+	gchar *ip_id;
+
+	provider = NULL;
+	providers = na_pivot_get_providers( pivot, NA_IIO_PROVIDER_TYPE );
+
+	for( ip = providers ; ip && !provider ; ip = ip->next ){
+		ip_id = na_io_provider_get_id( pivot, NA_IIO_PROVIDER( ip->data ));
+		if( ip_id ){
+			if( !strcmp( ip_id, id )){
+				provider = NA_IIO_PROVIDER( ip->data );
+				g_object_ref( provider );
+			}
+			g_free( ip_id );
+		}
+	}
+
+	na_pivot_free_providers( providers );
+
+	return( provider );
+}
+
+/**
+ * na_io_provider_get_writable_provider:
+ * @pivot: the #NAPivot object.
+ *
+ * Returns: the first willing to write I/O provider, or NULL.
+ *
+ * The returned provider should be g_object_unref() by the caller.
+ */
+NAIIOProvider *
+na_io_provider_get_writable_provider( const NAPivot *pivot )
+{
+	NAIIOProvider *provider;
+	GList *providers, *ip;
+
+	provider = NULL;
+	providers = na_pivot_get_providers( pivot, NA_IIO_PROVIDER_TYPE );
+
+	for( ip = providers ; ip && !provider ; ip = ip->next ){
+		if( !na_io_provider_is_willing_to_write( pivot, NA_IIO_PROVIDER( ip->data ))){
+			provider = NA_IIO_PROVIDER( ip->data );
+			g_object_ref( provider );
+		}
+	}
+
+	na_pivot_free_providers( providers );
+
+	return( provider );
+}
+
+/**
  * na_io_provider_get_id:
  * @pivot: the current #NAPivot instance.
  * @provider: the #NAIIOProvider whose id is to be returned.
@@ -110,7 +174,12 @@ na_io_provider_get_name( const NAPivot *pivot, const NAIIOProvider *provider )
 {
 	gchar *name;
 
-	name = na_pivot_get_module_name( pivot, G_OBJECT( provider ));
+	name = NULL;
+	if( NA_IIO_PROVIDER_GET_INTERFACE( provider )->get_name ){
+		name = NA_IIO_PROVIDER_GET_INTERFACE( provider )->get_name( provider );
+	} else {
+		name = g_strdup( "" );
+	}
 
 	return( name );
 }
@@ -127,7 +196,7 @@ na_io_provider_get_version( const NAPivot *pivot, const NAIIOProvider *provider
 {
 	guint version;
 
-	version = 0;
+	version = 1;
 	if( NA_IIO_PROVIDER_GET_INTERFACE( provider )->get_version ){
 		version = NA_IIO_PROVIDER_GET_INTERFACE( provider )->get_version( provider );
 	}
diff --git a/nautilus-actions/runtime/na-io-provider.h b/nautilus-actions/runtime/na-io-provider.h
index 52f0456..e10e6b8 100644
--- a/nautilus-actions/runtime/na-io-provider.h
+++ b/nautilus-actions/runtime/na-io-provider.h
@@ -44,16 +44,19 @@
 
 G_BEGIN_DECLS
 
-void     na_io_provider_register_callbacks( const NAPivot *pivot );
+void           na_io_provider_register_callbacks( const NAPivot *pivot );
 
-gchar   *na_io_provider_get_id( const NAPivot *pivot, const NAIIOProvider *provider );
-gchar   *na_io_provider_get_name( const NAPivot *pivot, const NAIIOProvider *provider );
-guint    na_io_provider_get_version( const NAPivot *pivot, const NAIIOProvider *provider );
-gboolean na_io_provider_is_willing_to_write( const NAPivot *pivot, const NAIIOProvider *provider );
+NAIIOProvider *na_io_provider_get_provider( const NAPivot *pivot, const gchar *id );
+NAIIOProvider *na_io_provider_get_writable_provider( const NAPivot *pivot );
 
-GList   *na_io_provider_read_items( const NAPivot *pivot, GSList **messages );
-guint    na_io_provider_write_item( const NAPivot *pivot, NAObjectItem *item, GSList **messages );
-guint    na_io_provider_delete_item( const NAPivot *pivot, const NAObjectItem *item, GSList **messages );
+gchar         *na_io_provider_get_id( const NAPivot *pivot, const NAIIOProvider *provider );
+gchar         *na_io_provider_get_name( const NAPivot *pivot, const NAIIOProvider *provider );
+guint          na_io_provider_get_version( const NAPivot *pivot, const NAIIOProvider *provider );
+gboolean       na_io_provider_is_willing_to_write( const NAPivot *pivot, const NAIIOProvider *provider );
+
+GList         *na_io_provider_read_items( const NAPivot *pivot, GSList **messages );
+guint          na_io_provider_write_item( const NAPivot *pivot, NAObjectItem *item, GSList **messages );
+guint          na_io_provider_delete_item( const NAPivot *pivot, const NAObjectItem *item, GSList **messages );
 
 G_END_DECLS
 
diff --git a/nautilus-actions/runtime/na-module.c b/nautilus-actions/runtime/na-module.c
index 7e886e4..cc4199a 100644
--- a/nautilus-actions/runtime/na-module.c
+++ b/nautilus-actions/runtime/na-module.c
@@ -34,6 +34,7 @@
 
 #include <gmodule.h>
 
+#include "na-utils.h"
 #include "na-module.h"
 
 /* private class data
@@ -47,15 +48,16 @@ struct NAModuleClassPrivate {
 struct NAModulePrivate {
 	gboolean  dispose_has_run;
 	gchar    *path;						/* full pathname of the plugin */
+	gchar    *name;						/* basename without the extension */
 	GModule  *library;
 	GList    *objects;
 
 	/* api
 	 */
-	gboolean      ( * initialize )( GTypeModule *module );
-	gint          ( * list_types )( const GType **types );
-	const gchar * ( * get_name )  ( GType type );
-	void          ( * shutdown )  ( void );
+	gboolean ( * initialize ) ( GTypeModule *module );
+	guint    ( * get_version )( void );
+	gint     ( * list_types ) ( const GType **types );
+	void     ( * shutdown )   ( void );
 };
 
 static GTypeModuleClass *st_parent_class = NULL;
@@ -76,8 +78,6 @@ static void      object_weak_notify( NAModule *module, GObject *object );
 
 static void      module_unload( GTypeModule *gmodule );
 
-static NAModule *find_module_for_object( GList *modules, GObject *object, GType *type );
-
 GType
 na_module_get_type( void )
 {
@@ -186,6 +186,7 @@ instance_finalize( GObject *object )
 	self = NA_MODULE( object );
 
 	g_free( self->private->path );
+	g_free( self->private->name );
 
 	g_free( self->private );
 
@@ -196,6 +197,27 @@ instance_finalize( GObject *object )
 }
 
 /**
+ * na_module_dump:
+ * @module: this #NAModule instance.
+ *
+ * Dumps the content of the module.
+ */
+void
+na_module_dump( const NAModule *module )
+{
+	static const gchar *thisfn = "na_module_dump";
+	GList *iobj;
+
+	g_debug( "%s:    path=%s", thisfn, module->private->path );
+	g_debug( "%s:    name=%s", thisfn, module->private->name );
+	g_debug( "%s: library=%p", thisfn, ( void * ) module->private->library );
+	g_debug( "%s: objects=%p (count=%d)", thisfn, ( void * ) module->private->objects, g_list_length( module->private->objects ));
+	for( iobj = module->private->objects ; iobj ; iobj = iobj->next ){
+		g_debug( "%s:    iobj=%p (%s)", thisfn, ( void * ) iobj->data, G_OBJECT_TYPE_NAME( iobj->data ));
+	}
+}
+
+/**
  * na_module_load_modules:
  *
  * Load availables dynamically loadable extension libraries (plugins).
@@ -208,6 +230,7 @@ na_module_load_modules( void )
 {
 	static const gchar *thisfn = "na_module_load_modules";
 	const gchar *dirname = PKGLIBDIR;
+	const gchar *suffix = ".so";
 	GList *modules;
 	GDir *api_dir;
 	GError *error;
@@ -228,10 +251,11 @@ na_module_load_modules( void )
 
 	} else {
 		while(( entry = g_dir_read_name( api_dir )) != NULL ){
-			if( g_str_has_suffix( entry, ".so" )){
+			if( g_str_has_suffix( entry, suffix )){
 				fname = g_build_filename( dirname, entry, NULL );
 				module = module_new( fname );
 				if( module ){
+					module->private->name = na_utils_remove_suffix( entry, suffix );
 					modules = g_list_prepend( modules, module );
 					g_debug( "%s: module %s successfully loaded", thisfn, fname );
 				}
@@ -308,10 +332,10 @@ is_a_na_plugin( NAModule *module )
 	gboolean ok;
 
 	ok =
-		plugin_check( module, "na_api_module_init"      , ( gpointer * ) &module->private->initialize) &&
-		plugin_check( module, "na_api_module_list_types", ( gpointer * ) &module->private->list_types ) &&
-		plugin_check( module, "na_api_module_get_name"  , ( gpointer * ) &module->private->get_name ) &&
-		plugin_check( module, "na_api_module_shutdown"  , ( gpointer * ) &module->private->shutdown ) &&
+		plugin_check( module, "na_api_module_init"       , ( gpointer * ) &module->private->initialize) &&
+		plugin_check( module, "na_api_module_get_version", ( gpointer * ) &module->private->get_version ) &&
+		plugin_check( module, "na_api_module_list_types" , ( gpointer * ) &module->private->list_types ) &&
+		plugin_check( module, "na_api_module_shutdown"   , ( gpointer * ) &module->private->shutdown ) &&
 		module->private->initialize( G_TYPE_MODULE( module ));
 
 	return( ok );
@@ -345,7 +369,7 @@ static void
 register_module_types( NAModule *module )
 {
 	const GType *types;
-	gint count, i;
+	guint count, i;
 
 	count = module->private->list_types( &types );
 	module->private->objects = NULL;
@@ -365,7 +389,7 @@ add_module_type( NAModule *module, GType type )
 	GObject *object;
 
 	object = g_object_new( type, NULL );
-	g_object_set_data( object, "na-module-type", ( gpointer ) type );
+	g_debug( "na_module_add_module_type: allocating object=%p (%s)", ( void * ) object, G_OBJECT_TYPE_NAME( object ));
 
 	g_object_weak_ref( object,
 			( GWeakNotify ) object_weak_notify,
@@ -409,8 +433,8 @@ module_unload( GTypeModule *gmodule )
 	}
 
 	module->private->initialize = NULL;
+	module->private->get_version = NULL;
 	module->private->list_types = NULL;
-	module->private->get_name = NULL;
 	module->private->shutdown = NULL;
 }
 
@@ -456,69 +480,25 @@ na_module_free_extensions_list( GList *extensions )
 }
 
 /**
- * na_module_get_name:
- * @module: the #NAModule instance corresponding to a dynamically
- *  loaded library.
- * @type: one of the #GType this @module advertizes it implements.
- *
- * Returns: the name the #NAModule @module applies to itself for this
- * @type, as a newly allocated string which should be g_free() by the
- * caller.
- */
-gchar *
-na_module_get_name( NAModule *module, GType type )
-{
-	gchar *name = NULL;
-
-	g_return_val_if_fail( NA_IS_MODULE( module ), name );
-
-	name = g_strdup( module->private->get_name( type ));
-
-	return( name );
-}
-
-/**
- * na_module_get_name_for_object:
- * @modules: the list of dynamically loaded modules.
- * @object: an object instantiated by one of these modules.
+ * na_module_has_id:
+ * @module: this #NAModule object.
+ * @id: the searched id.
  *
- * Returns: the name of the #NAModule for this @object, as a newly
- * allocated string which should be g_free() by the caller.
+ * Returns: %TRUE if one of the interfaces advertised by the module has
+ * the given id, %FALSE else.
  */
-gchar *
-na_module_get_name_for_object( GList *modules, GObject *object )
+gboolean
+na_module_has_id( NAModule *module, const gchar *id )
 {
-	gchar *name;
-	GType type;
-	NAModule *module;
+	gboolean id_ok;
+	GList *iobj;
 
-	name = NULL;
-	type = ( GType ) 0;
-	module = find_module_for_object( modules, object, &type );
-	if( type ){
-		name = na_module_get_name( module, type );
+	id_ok = FALSE;
+	for( iobj = module->private->objects ; iobj && !id_ok ; iobj = iobj->next ){
+		g_debug( "na_module_has_id: object=%s", G_OBJECT_TYPE_NAME( iobj->data ));
 	}
 
-	return( name );
-}
-
-static NAModule *
-find_module_for_object( GList *modules, GObject *object, GType *type )
-{
-	GList *im;
-	GList *io;
-	NAModule *module = NULL;
-
-	for( im = modules ; im && !module ; im = im->next ){
-		for( io = NA_MODULE( im->data )->private->objects ; io && !module ; io = io->next ){
-			if( io->data == object ){
-				module = NA_MODULE( im->data );
-				*type = ( GType ) g_object_get_data( object, "na-module-type" );
-			}
-		}
-	}
-
-	return( module );
+	return( id_ok );
 }
 
 /**
diff --git a/nautilus-actions/runtime/na-module.h b/nautilus-actions/runtime/na-module.h
index de44513..060b5b8 100644
--- a/nautilus-actions/runtime/na-module.h
+++ b/nautilus-actions/runtime/na-module.h
@@ -42,6 +42,27 @@
  * NAModule
  *  +- is derived from GTypeModule
  *      +- which itself implements GTypePlugin
+ *
+ * Each NAModule physically corresponds to a dynamically loadable library
+ * (i.e. a plugin). A NAModule implements one or more interfaces, and/or
+ * provides one or more services.
+ *
+ * Interfaces (resp. services) are implemented (resp. provided) by GObjects
+ * which are dynamically instantiated at plugin initial-load time.
+ *
+ * So the dynamic is as follows:
+ * - NAPivot scans for the PKGLIBDIR directory, trying to dynamically
+ *   load all found libraries
+ * - to be considered as a N-A plugin, a library must implement some
+ *   functions (see api/na-api.h)
+ * - for each found plugin, NAPivot calls na_api_list_types() which
+ *   returns the type of GObjects implemented in the plugin
+ * - NAPivot dynamically instantiates a GObject for each returned GType.
+ *
+ * After that, when NAPivot wants to access, say to NAIIOProvider
+ * interfaces, it asks each module for its list of objects which implement
+ * this given interface.
+ * Interface API is then called against the returned GObject.
  */
 
 #include <glib.h>
@@ -72,17 +93,17 @@ typedef struct {
 }
 	NAModuleClass;
 
-GType  na_module_get_type               ( void );
+GType    na_module_get_type               ( void );
 
-GList *na_module_load_modules           ( void );
+void     na_module_dump                   ( const NAModule *module );
+GList   *na_module_load_modules           ( void );
 
-GList *na_module_get_extensions_for_type( GList *modules, GType type );
-void   na_module_free_extensions_list   ( GList *extensions );
+GList   *na_module_get_extensions_for_type( GList *modules, GType type );
+void     na_module_free_extensions_list   ( GList *extensions );
 
-gchar *na_module_get_name               ( NAModule *module, GType type );
-gchar *na_module_get_name_for_object    ( GList *modules, GObject *object );
+gboolean na_module_has_id                 ( NAModule *module, const gchar *id );
 
-void   na_module_release_modules        ( GList *modules );
+void     na_module_release_modules        ( GList *modules );
 
 G_END_DECLS
 
diff --git a/nautilus-actions/runtime/na-pivot.c b/nautilus-actions/runtime/na-pivot.c
index d680ccf..9c0513e 100644
--- a/nautilus-actions/runtime/na-pivot.c
+++ b/nautilus-actions/runtime/na-pivot.c
@@ -372,24 +372,6 @@ na_pivot_item_changed_handler( NAIIOProvider *provider, const gchar *id, NAPivot
 }
 
 /**
- * na_pivot_get_module_name:
- * @pivot: this #NAPivot instance.
- * @provider: a #GObject as instantiated by a #NAModule.
- *
- * Returns: the name of the #NAModule, as a newly allocated string which
- * should be g_free() by the caller.
- */
-gchar *
-na_pivot_get_module_name( const NAPivot *pivot, GObject *provider )
-{
-	gchar *name;
-
-	name = na_module_get_name_for_object( pivot->private->modules, provider );
-
-	return( name );
-}
-
-/**
  * na_pivot_get_providers:
  * @pivot: this #NAPivot instance.
  * @type: the type of searched interface.
@@ -421,43 +403,6 @@ na_pivot_get_providers( const NAPivot *pivot, GType type )
 }
 
 /**
- * na_pivot_get_provider:
- * @pivot: this #NAPivot instance.
- * @type: the type of searched interface.
- *
- * Returns: the first available provider for this interface.
- *
- * The returned #GObject should be released by calling na_pivot_release_provider().
- */
-GObject *
-na_pivot_get_provider( const NAPivot *pivot, GType type )
-{
-	GList *providers;
-	GObject *provider;
-
-	provider = NULL;
-	providers = na_pivot_get_providers( pivot, type );
-	if( providers ){
-		provider = g_object_ref( G_OBJECT( providers->data ));
-		na_pivot_free_providers( providers );
-	}
-
-	return( provider );
-}
-
-/**
- * na_pivot_release_provider:
- * @provider: a provider.
- *
- * Release the given provider.
- */
-void
-na_pivot_release_provider( const GObject *provider )
-{
-	g_object_unref(( gpointer ) provider );
-}
-
-/**
  * na_pivot_free_providers:
  * @providers: a list of providers.
  *
@@ -474,36 +419,6 @@ na_pivot_free_providers( GList *providers )
 }
 
 /**
- * na_pivot_has_writable_providers:
- * @pivot: this #NAPivot instance.
- *
- * Returns: %TRUE if at least one I/O provider is writable, %FALSE else.
- */
-gboolean
-na_pivot_has_writable_providers( const NAPivot *pivot )
-{
-	static const gchar *thisfn = "na_pivot_has_writable_providers";
-	gboolean writable;
-	GList *providers, *ip;
-
-	writable = FALSE;
-
-	g_return_val_if_fail( NA_IS_PIVOT( pivot ), writable );
-
-	if( !pivot->private->dispose_has_run ){
-
-		providers = na_pivot_get_providers( pivot, NA_IIO_PROVIDER_TYPE );
-		for( ip = providers ; ip && !writable ; ip = ip->next ){
-			writable = na_io_provider_is_willing_to_write( pivot, NA_IIO_PROVIDER( ip->data ));
-		}
-		na_pivot_free_providers( providers );
-	}
-
-	g_debug( "%s: pivot=%p, writable=%s", thisfn, ( void * ) pivot, writable ? "True":"False" );
-	return( writable );
-}
-
-/**
  * na_pivot_get_items:
  * @pivot: this #NAPivot instance.
  *
@@ -868,6 +783,35 @@ na_pivot_sort_alpha_desc( const NAObjectId *a, const NAObjectId *b )
 }
 
 /**
+ * na_pivot_is_level_zero_writable:
+ * @pivot: this #NAPivot instance.
+ *
+ * Returns: %TRUE if we are able to update the level-zero list of items,
+ * %FALSE else.
+ */
+gboolean
+na_pivot_is_level_zero_writable( const NAPivot *pivot )
+{
+	static const gchar *thisfn = "na_pivot_is_level_zero_writable";
+	gboolean writable;
+	NAIIOProvider *provider;
+
+	writable = FALSE;
+	g_return_val_if_fail( NA_IS_PIVOT( pivot ), writable );
+
+	if( !pivot->private->dispose_has_run ){
+		provider = na_io_provider_get_provider( pivot, "na-gconf" );
+		if( provider ){
+			writable = na_io_provider_is_willing_to_write( pivot, provider );
+			g_debug( "%s: writable=%s", thisfn, writable ? "True":"False" );
+			g_object_unref( provider );
+		}
+	}
+
+	return( writable );
+}
+
+/**
  * na_pivot_write_level_zero:
  * @pivot: this #NAPivot instance.
  * @items: full current tree of items in #NactIActionsList treeview.
diff --git a/nautilus-actions/runtime/na-pivot.h b/nautilus-actions/runtime/na-pivot.h
index 5cd7813..ca666fb 100644
--- a/nautilus-actions/runtime/na-pivot.h
+++ b/nautilus-actions/runtime/na-pivot.h
@@ -121,13 +121,8 @@ void          na_pivot_dump( const NAPivot *pivot );
 
 void          na_pivot_item_changed_handler( NAIIOProvider *provider, const gchar *id, NAPivot *pivot );
 
-gchar        *na_pivot_get_module_name( const NAPivot *pivot, GObject *provider );
-
 GList        *na_pivot_get_providers( const NAPivot *pivot, GType type );
-GObject      *na_pivot_get_provider( const NAPivot *pivot, GType type );
-void          na_pivot_release_provider( const GObject *provider );
 void          na_pivot_free_providers( GList *providers );
-gboolean      na_pivot_has_writable_providers( const NAPivot *pivot );
 
 GList        *na_pivot_get_items( const NAPivot *pivot );
 void          na_pivot_load_items( NAPivot *pivot );
@@ -151,6 +146,7 @@ gboolean      na_pivot_is_invalid_loadable( const NAPivot *pivot );
 gint          na_pivot_sort_alpha_asc( const NAObjectId *a, const NAObjectId *b );
 gint          na_pivot_sort_alpha_desc( const NAObjectId *a, const NAObjectId *b );
 
+gboolean      na_pivot_is_level_zero_writable( const NAPivot *pivot );
 void          na_pivot_write_level_zero( const NAPivot *pivot, GList *items );
 
 /* notification message from NAIIOProvider to NAPivot
diff --git a/nautilus-actions/runtime/na-utils.c b/nautilus-actions/runtime/na-utils.c
index 7322131..5f4aac2 100644
--- a/nautilus-actions/runtime/na-utils.c
+++ b/nautilus-actions/runtime/na-utils.c
@@ -518,6 +518,33 @@ na_utils_prefix_strings( const gchar *prefix, const gchar *str )
 }
 
 /**
+ * na_utils_remove_suffix:
+ * @string: source string.
+ * @suffix: suffix to be removed from @string.
+ *
+ * Returns: a newly allocated string, which is a copy of the source @string,
+ * minus the removed @suffix if present. If @strings doesn't terminate with
+ * @suffix, then the returned string is equal to source @string.
+ *
+ * The returned string should be g_free() by the caller.
+ */
+gchar *
+na_utils_remove_suffix( const gchar *string, const gchar *suffix )
+{
+	gchar *removed;
+	gchar *ptr;
+
+	removed = g_strdup( string );
+
+	if( g_str_has_suffix( string, suffix )){
+		ptr = g_strrstr( removed, suffix );
+		ptr[0] = '\0';
+	}
+
+	return( removed );
+}
+
+/**
  * na_utils_exist_file:
  * @uri: an uri which points to a file.
  *
diff --git a/nautilus-actions/runtime/na-utils.h b/nautilus-actions/runtime/na-utils.h
index 66669b2..3b5ffc8 100644
--- a/nautilus-actions/runtime/na-utils.h
+++ b/nautilus-actions/runtime/na-utils.h
@@ -65,6 +65,8 @@ gchar   *na_utils_gstring_joinv( const gchar *start, const gchar *separator, gch
  */
 gchar   *na_utils_get_first_word( const gchar *string );
 gchar   *na_utils_prefix_strings( const gchar *prefix, const gchar *str );
+gchar   *na_utils_remove_suffix( const gchar *string, const gchar *suffix );
+
 
 /* path manipulations
  */
diff --git a/nautilus-actions/utils/nautilus-actions-new.c b/nautilus-actions/utils/nautilus-actions-new.c
index 67e3d72..2a72df5 100644
--- a/nautilus-actions/utils/nautilus-actions-new.c
+++ b/nautilus-actions/utils/nautilus-actions-new.c
@@ -371,17 +371,20 @@ static gboolean
 write_to_gconf( NAObjectAction *action, GSList **msg )
 {
 	NAPivot *pivot;
-	GObject *provider;
+	NAIIOProvider *provider;
 	guint ret;
 
+	ret = NA_IIO_PROVIDER_NOT_WILLING_TO_WRITE;
 	pivot = na_pivot_new();
-	provider = na_pivot_get_provider( pivot, NA_IIO_PROVIDER_TYPE );
+	provider = na_io_provider_get_writable_provider( pivot );
 
-	na_object_set_provider( action, NA_IIO_PROVIDER( provider ));
+	if( provider ){
 
-	ret = na_io_provider_write_item( pivot, NA_OBJECT_ITEM( action ), msg );
+		na_object_set_provider( action, NA_IIO_PROVIDER( provider ));
+		ret = na_io_provider_write_item( pivot, NA_OBJECT_ITEM( action ), msg );
+		g_object_unref( provider );
+	}
 
-	na_pivot_release_provider( provider );
 	g_object_unref( pivot );
 
 	return( ret == NA_IIO_PROVIDER_WRITE_OK );
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 554f16e..ff9e7d5 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -1,4 +1,6 @@
 data/nautilus-actions.schemas.in
+nautilus-actions/io-provider-desktop/nadp-desktop-provider.c
+nautilus-actions/io-provider-gconf/nadp-gconf-provider.c
 nautilus-actions/nact/base-application.c
 nautilus-actions/nact/base-assistant.c
 nautilus-actions/nact/base-window.c



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]