[nautilus-actions: 17/45] New NAIDuplicable and NactIMenubar interfaces for the new UI



commit f6d0a9dde0d24306b965441f65f91983846c3bec
Author: Pierre Wieser <pwieser trychlos org>
Date:   Sat Jul 25 21:36:52 2009 +0200

    New NAIDuplicable and NactIMenubar interfaces for the new UI

 ChangeLog                                          |   18 +
 src/Makefile.am                                    |    2 +-
 src/common/Makefile.am                             |    8 +-
 .../{na-ipivot-container.h => na-action-class.h}   |   49 +-
 ...pivot-container.h => na-action-profile-class.h} |   49 +-
 src/common/na-action-profile.c                     | 1011 ++++++++++++--------
 src/common/na-action-profile.h                     |   69 +-
 src/common/na-action.c                             |  849 ++++++++++-------
 src/common/na-action.h                             |  111 +--
 src/common/na-gconf.c                              |  918 +++++++++++++-----
 src/common/na-gconf.h                              |    9 +-
 src/common/na-iduplicable.c                        |  422 ++++++++
 src/common/na-iduplicable.h                        |  129 +++
 src/common/na-iio-provider.c                       |  166 ++--
 src/common/na-iio-provider.h                       |   94 ++-
 ...{na-ipivot-container.c => na-ipivot-consumer.c} |   46 +-
 src/common/na-ipivot-consumer.h                    |   82 ++
 src/common/na-object.c                             |  490 +++++++++-
 src/common/na-object.h                             |  124 +++-
 src/common/na-pivot.c                              |  346 +++++--
 src/common/na-pivot.h                              |   69 ++-
 src/common/na-utils.c                              |    2 +-
 src/nact/Makefile.am                               |    2 +
 src/nact/nact-application.c                        |   10 +-
 src/nact/nact-application.h                        |    4 +-
 src/nact/nact-assist-import.c                      |    2 +-
 src/nact/nact-gconf-reader.c                       |    8 +-
 src/nact/nact-iaction-tab.c                        |  115 +++-
 src/nact/nact-iaction-tab.h                        |    8 +-
 src/nact/nact-iactions-list.c                      |  443 ++++++++--
 src/nact/nact-iactions-list.h                      |   16 +-
 src/nact/nact-icommand-tab.c                       |   83 ++-
 src/nact/nact-icommand-tab.h                       |    1 +
 src/nact/nact-iconditions-tab.h                    |    2 +-
 src/nact/nact-imenubar.c                           |  936 ++++++++++++++++++
 src/nact/nact-imenubar.h                           |   85 ++
 src/nact/nact-main-window.c                        |  624 ++++++-------
 src/nact/nact-window.c                             |   41 +-
 src/nact/nact-window.h                             |    6 +-
 src/plugin/nautilus-actions.c                      |   36 +-
 40 files changed, 5577 insertions(+), 1908 deletions(-)
---
diff --git a/ChangeLog b/ChangeLog
index 7148198..099d1dd 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,21 @@
+2009-07-25 Pierre Wieser <pwieser trychlos org>
+
+	* src/common/na-action-class.h:
+	* src/common/na-action-profile-class.h:
+	New files to properly handle forward declarations.
+
+	* src/common/na-ipivot-container.c:
+	* src/common/na-ipivot-container.h:
+	Renamed as na-ipivot-consumer.{c,h}.
+
+	* src/common/na-iduplicable.c:
+	* src/common/na-iduplicable.h:
+	New NAIDuplicable interface implemented by NAObject class.
+
+	* src/nact/nact-imenubar.c:
+	* src/nact/nact-imenubar.h:
+	New NactIMenubar interface implemented by NactMainWindow class.
+
 2009-07-19 Pierre Wieser <pwieser trychlos org>
 
 	* src/nact/nact-action-conditions-editor.c:
diff --git a/src/Makefile.am b/src/Makefile.am
index f86e2a2..75ebe69 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -29,6 +29,6 @@
 SUBDIRS = \
 	common						\
 	nact						\
-	$(OPTIONAL_SUBDIR)			\
 	plugin						\
+	$(OPTIONAL_SUBDIR)			\
 	$(NULL)
diff --git a/src/common/Makefile.am b/src/common/Makefile.am
index b07e308..868da5d 100644
--- a/src/common/Makefile.am
+++ b/src/common/Makefile.am
@@ -37,15 +37,19 @@ AM_CPPFLAGS += \
 libnact_la_SOURCES = \
 	na-action.c									\
 	na-action.h									\
+	na-action-class.h							\
 	na-action-profile.c							\
 	na-action-profile.h							\
+	na-action-profile-class.h					\
 	na-gconf.c									\
 	na-gconf.h									\
 	na-gconf-keys.h								\
+	na-iduplicable.c							\
+	na-iduplicable.h							\
 	na-iio-provider.c							\
 	na-iio-provider.h							\
-	na-ipivot-container.c						\
-	na-ipivot-container.h						\
+	na-ipivot-consumer.c						\
+	na-ipivot-consumer.h						\
 	na-object.c									\
 	na-object.h									\
 	na-pivot.c									\
diff --git a/src/common/na-ipivot-container.h b/src/common/na-action-class.h
similarity index 50%
copy from src/common/na-ipivot-container.h
copy to src/common/na-action-class.h
index 308efe9..a734f5b 100644
--- a/src/common/na-ipivot-container.h
+++ b/src/common/na-action-class.h
@@ -28,43 +28,42 @@
  *   ... and many others (see AUTHORS)
  */
 
-#ifndef __NA_IPIVOT_CONTAINER_H__
-#define __NA_IPIVOT_CONTAINER_H__
+#ifndef __NA_ACTION_CLASS_H__
+#define __NA_ACTION_CLASS_H__
 
-/*
- * NAIPivotContainer interface definition.
- *
- * This interface should be implemented by all classes which embed a
- * NAPivot object, in order to receive modification notification
- * messages.
+/**
+ * SECTION: na_action
  */
 
-#include <glib-object.h>
+#include "na-object.h"
 
 G_BEGIN_DECLS
 
-#define NA_IPIVOT_CONTAINER_TYPE						( na_ipivot_container_get_type())
-#define NA_IPIVOT_CONTAINER( object )					( G_TYPE_CHECK_INSTANCE_CAST( object, NA_IPIVOT_CONTAINER_TYPE, NAIPivotContainer ))
-#define NA_IS_IPIVOT_CONTAINER( object )				( G_TYPE_CHECK_INSTANCE_TYPE( object, NA_IPIVOT_CONTAINER_TYPE ))
-#define NA_IPIVOT_CONTAINER_GET_INTERFACE( instance )	( G_TYPE_INSTANCE_GET_INTERFACE(( instance ), NA_IPIVOT_CONTAINER_TYPE, NAIPivotContainerInterface ))
+#define NA_ACTION_TYPE					( na_action_get_type())
+#define NA_ACTION( object )				( G_TYPE_CHECK_INSTANCE_CAST( object, NA_ACTION_TYPE, NAAction ))
+#define NA_ACTION_CLASS( klass )		( G_TYPE_CHECK_CLASS_CAST( klass, NA_ACTION_TYPE, NAActionClass ))
+#define NA_IS_ACTION( object )			( G_TYPE_CHECK_INSTANCE_TYPE( object, NA_ACTION_TYPE ))
+#define NA_IS_ACTION_CLASS( klass )		( G_TYPE_CHECK_CLASS_TYPE(( klass ), NA_ACTION_TYPE ))
+#define NA_ACTION_GET_CLASS( object )	( G_TYPE_INSTANCE_GET_CLASS(( object ), NA_ACTION_TYPE, NAActionClass ))
 
-typedef struct NAIPivotContainer NAIPivotContainer;
-
-typedef struct NAIPivotContainerInterfacePrivate NAIPivotContainerInterfacePrivate;
+typedef struct NAActionPrivate NAActionPrivate;
 
 typedef struct {
-	GTypeInterface                     parent;
-	NAIPivotContainerInterfacePrivate *private;
-
-	/* api */
-	void ( *on_actions_changed )( NAIPivotContainer *instance, gpointer user_data );
+	NAObject         parent;
+	NAActionPrivate *private;
 }
-	NAIPivotContainerInterface;
+	NAAction;
 
-GType na_ipivot_container_get_type( void );
+typedef struct NAActionClassPrivate NAActionClassPrivate;
+
+typedef struct {
+	NAObjectClass         parent;
+	NAActionClassPrivate *private;
+}
+	NAActionClass;
 
-void  na_ipivot_container_notify( NAIPivotContainer *instance );
+GType na_action_get_type( void );
 
 G_END_DECLS
 
-#endif /* __NA_IPIVOT_CONTAINER_H__ */
+#endif /* __NA_ACTION_CLASS_H__ */
diff --git a/src/common/na-ipivot-container.h b/src/common/na-action-profile-class.h
similarity index 50%
rename from src/common/na-ipivot-container.h
rename to src/common/na-action-profile-class.h
index 308efe9..5f8eaa7 100644
--- a/src/common/na-ipivot-container.h
+++ b/src/common/na-action-profile-class.h
@@ -28,43 +28,42 @@
  *   ... and many others (see AUTHORS)
  */
 
-#ifndef __NA_IPIVOT_CONTAINER_H__
-#define __NA_IPIVOT_CONTAINER_H__
+#ifndef __NA_ACTION_PROFILE_CLASS_H__
+#define __NA_ACTION_PROFILE_CLASS_H__
 
-/*
- * NAIPivotContainer interface definition.
- *
- * This interface should be implemented by all classes which embed a
- * NAPivot object, in order to receive modification notification
- * messages.
+/**
+ * SECTION: na_action_profile
  */
 
-#include <glib-object.h>
+#include "na-object.h"
 
 G_BEGIN_DECLS
 
-#define NA_IPIVOT_CONTAINER_TYPE						( na_ipivot_container_get_type())
-#define NA_IPIVOT_CONTAINER( object )					( G_TYPE_CHECK_INSTANCE_CAST( object, NA_IPIVOT_CONTAINER_TYPE, NAIPivotContainer ))
-#define NA_IS_IPIVOT_CONTAINER( object )				( G_TYPE_CHECK_INSTANCE_TYPE( object, NA_IPIVOT_CONTAINER_TYPE ))
-#define NA_IPIVOT_CONTAINER_GET_INTERFACE( instance )	( G_TYPE_INSTANCE_GET_INTERFACE(( instance ), NA_IPIVOT_CONTAINER_TYPE, NAIPivotContainerInterface ))
+#define NA_ACTION_PROFILE_TYPE					( na_action_profile_get_type())
+#define NA_ACTION_PROFILE( object )				( G_TYPE_CHECK_INSTANCE_CAST( object, NA_ACTION_PROFILE_TYPE, NAActionProfile ))
+#define NA_ACTION_PROFILE_CLASS( klass )		( G_TYPE_CHECK_CLASS_CAST( klass, NA_ACTION_PROFILE_TYPE, NAActionProfileClass ))
+#define NA_IS_ACTION_PROFILE( object )			( G_TYPE_CHECK_INSTANCE_TYPE( object, NA_ACTION_PROFILE_TYPE ))
+#define NA_IS_ACTION_PROFILE_CLASS( klass )		( G_TYPE_CHECK_CLASS_TYPE(( klass ), NA_ACTION_PROFILE_TYPE ))
+#define NA_ACTION_PROFILE_GET_CLASS( object )	( G_TYPE_INSTANCE_GET_CLASS(( object ), NA_ACTION_PROFILE_TYPE, NAActionProfileClass ))
 
-typedef struct NAIPivotContainer NAIPivotContainer;
-
-typedef struct NAIPivotContainerInterfacePrivate NAIPivotContainerInterfacePrivate;
+typedef struct NAActionProfilePrivate NAActionProfilePrivate;
 
 typedef struct {
-	GTypeInterface                     parent;
-	NAIPivotContainerInterfacePrivate *private;
-
-	/* api */
-	void ( *on_actions_changed )( NAIPivotContainer *instance, gpointer user_data );
+	NAObject                parent;
+	NAActionProfilePrivate *private;
 }
-	NAIPivotContainerInterface;
+	NAActionProfile;
 
-GType na_ipivot_container_get_type( void );
+typedef struct NAActionProfileClassPrivate NAActionProfileClassPrivate;
+
+typedef struct {
+	NAObjectClass                parent;
+	NAActionProfileClassPrivate *private;
+}
+	NAActionProfileClass;
 
-void  na_ipivot_container_notify( NAIPivotContainer *instance );
+GType na_action_profile_get_type( void );
 
 G_END_DECLS
 
-#endif /* __NA_IPIVOT_CONTAINER_H__ */
+#endif /* __NA_ACTION_PROFILE_CLASS_H__ */
diff --git a/src/common/na-action-profile.c b/src/common/na-action-profile.c
index a931a9d..ffa233c 100644
--- a/src/common/na-action-profile.c
+++ b/src/common/na-action-profile.c
@@ -53,57 +53,69 @@ struct NAActionProfilePrivate {
 
 	/* the NAAction object
 	 */
-	gpointer  action;
+	NAAction *action;
 
 	/* profile properties
 	 */
-	gchar    *name;
-	gchar    *label;
 	gchar    *path;
 	gchar    *parameters;
 	GSList   *basenames;
 	gboolean  match_case;
-	gboolean  is_dir;
-	gboolean  is_file;
-	gboolean  accept_multiple_files;
 	GSList   *mimetypes;
+	gboolean  is_file;
+	gboolean  is_dir;
+	gboolean  accept_multiple;
 	GSList   *schemes;
 };
 
-/* instance properties
- * please note that property names must have the same spelling as the
- * NactIIOProvider parameters
+/* profile properties
  */
 enum {
-	PROP_PROFILE_ACTION = 1,
-	PROP_PROFILE_NAME,
-	PROP_PROFILE_LABEL,
-	PROP_PROFILE_PATH,
-	PROP_PROFILE_PARAMETERS,
-	PROP_PROFILE_ACCEPT_MULTIPLE,
-	PROP_PROFILE_BASENAMES,
-	PROP_PROFILE_ISDIR,
-	PROP_PROFILE_ISFILE,
-	PROP_PROFILE_MATCHCASE,
-	PROP_PROFILE_MIMETYPES,
-	PROP_PROFILE_SCHEMES
+	PROP_NAPROFILE_ACTION = 1,
+	PROP_NAPROFILE_NAME,
+	PROP_NAPROFILE_LABEL,
+	PROP_NAPROFILE_PATH,
+	PROP_NAPROFILE_PARAMETERS,
+	PROP_NAPROFILE_BASENAMES,
+	PROP_NAPROFILE_MATCHCASE,
+	PROP_NAPROFILE_MIMETYPES,
+	PROP_NAPROFILE_ISFILE,
+	PROP_NAPROFILE_ISDIR,
+	PROP_NAPROFILE_ACCEPT_MULTIPLE,
+	PROP_NAPROFILE_SCHEMES
 };
 
+#define PROP_NAPROFILE_ACTION_STR				"na-profile-action"
+#define PROP_NAPROFILE_NAME_STR					"na-profile-name"
+#define PROP_NAPROFILE_LABEL_STR				"na-profile-desc-name"
+#define PROP_NAPROFILE_PATH_STR					"na-profile-path"
+#define PROP_NAPROFILE_PARAMETERS_STR			"na-profile-parameters"
+#define PROP_NAPROFILE_BASENAMES_STR			"na-profile-basenames"
+#define PROP_NAPROFILE_MATCHCASE_STR			"na-profile-matchcase"
+#define PROP_NAPROFILE_MIMETYPES_STR			"na-profile-mimetypes"
+#define PROP_NAPROFILE_ISFILE_STR				"na-profile-isfile"
+#define PROP_NAPROFILE_ISDIR_STR				"na-profile-isdir"
+#define PROP_NAPROFILE_ACCEPT_MULTIPLE_STR		"na-profile-accept-multiple"
+#define PROP_NAPROFILE_SCHEMES_STR				"na-profile-schemes"
+
 static NAObjectClass *st_parent_class = NULL;
 
-static GType  register_type( void );
-static void   class_init( NAActionProfileClass *klass );
-static void   instance_init( GTypeInstance *instance, gpointer klass );
-static void   instance_get_property( GObject *object, guint property_id, GValue *value, GParamSpec *spec );
-static void   instance_set_property( GObject *object, guint property_id, const GValue *value, GParamSpec *spec );
-static void   instance_dispose( GObject *object );
-static void   instance_finalize( GObject *object );
+static GType     register_type( void );
+static void      class_init( NAActionProfileClass *klass );
+static void      instance_init( GTypeInstance *instance, gpointer klass );
+static void      instance_get_property( GObject *object, guint property_id, GValue *value, GParamSpec *spec );
+static void      instance_set_property( GObject *object, guint property_id, const GValue *value, GParamSpec *spec );
+static void      instance_dispose( GObject *object );
+static void      instance_finalize( GObject *object );
 
-static void   do_dump( const NAObject *profile );
-static void   do_dump_list( const gchar *thisfn, const gchar *label, GSList *list );
-static gchar *do_get_id( const NAObject *object );
-static gchar *do_get_label( const NAObject *object );
-static int    validate_schemes( GSList* schemes2test, NautilusFileInfo* file );
+static void      object_dump( const NAObject *action );
+static void      object_dump_list( const gchar *thisfn, const gchar *label, GSList *list );
+static NAObject *object_duplicate( const NAObject *action );
+static void      object_copy( NAObject *target, const NAObject *source );
+static gboolean  object_are_equal( const NAObject *a, const NAObject *b );
+static gboolean  object_is_valid( const NAObject *action );
+
+static int       validate_schemes( GSList* schemes2test, NautilusFileInfo* file );
 
 GType
 na_action_profile_get_type( void )
@@ -120,6 +132,9 @@ na_action_profile_get_type( void )
 static GType
 register_type( void )
 {
+	static const gchar *thisfn = "na_action_profile_register_type";
+	g_debug( "%s", thisfn );
+
 	static GTypeInfo info = {
 		sizeof( NAActionProfileClass ),
 		( GBaseInitFunc ) NULL,
@@ -151,102 +166,103 @@ class_init( NAActionProfileClass *klass )
 
 	GParamSpec *spec;
 	spec = g_param_spec_pointer(
-			PROP_PROFILE_ACTION_STR,
-			PROP_PROFILE_ACTION_STR,
-			"The NAAction object",
-			G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE );
-	g_object_class_install_property( object_class, PROP_PROFILE_ACTION, spec );
+			PROP_NAPROFILE_ACTION_STR,
+			"NAAction attachment",
+			"The NAAction action to which this profile belongs",
+			G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE );
+	g_object_class_install_property( object_class, PROP_NAPROFILE_ACTION, spec );
 
-	/* the id of the object is marked as G_PARAM_CONSTRUCT_ONLY */
 	spec = g_param_spec_string(
-			PROP_PROFILE_NAME_STR,
-			PROP_PROFILE_NAME_STR,
-			"Internal profile's name", "",
+			PROP_NAPROFILE_NAME_STR,
+			"Profile name",
+			"Internal profile identifiant (ASCII, case insensitive)", "",
 			G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE );
-	g_object_class_install_property( object_class, PROP_PROFILE_NAME, spec );
+	g_object_class_install_property( object_class, PROP_NAPROFILE_NAME, spec );
 
 	spec = g_param_spec_string(
-			PROP_PROFILE_LABEL_STR,
-			PROP_PROFILE_LABEL_STR,
-			"Displayable profile's name", "",
+			PROP_NAPROFILE_LABEL_STR,
+			"Profile label",
+			"Displayable profile's label (UTF-8, localizable)", "",
 			G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE );
-	g_object_class_install_property( object_class, PROP_PROFILE_LABEL, spec );
+	g_object_class_install_property( object_class, PROP_NAPROFILE_LABEL, spec );
 
 	spec = g_param_spec_string(
-			PROP_PROFILE_PATH_STR,
-			PROP_PROFILE_PATH_STR,
+			PROP_NAPROFILE_PATH_STR,
+			"Command path",
 			"Command path", "",
 			G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE );
-	g_object_class_install_property( object_class, PROP_PROFILE_PATH, spec );
+	g_object_class_install_property( object_class, PROP_NAPROFILE_PATH, spec );
 
 	spec = g_param_spec_string(
-			PROP_PROFILE_PARAMETERS_STR,
-			PROP_PROFILE_PARAMETERS_STR,
+			PROP_NAPROFILE_PARAMETERS_STR,
+			"Command parameters",
 			"Command parameters", "",
 			G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE );
-	g_object_class_install_property( object_class, PROP_PROFILE_PARAMETERS, spec );
-
-	spec = g_param_spec_boolean(
-			PROP_PROFILE_ACCEPT_MULTIPLE_STR,
-			PROP_PROFILE_ACCEPT_MULTIPLE_STR,
-			"Whether apply when multiple files may be selected", TRUE,
-			G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE );
-	g_object_class_install_property( object_class, PROP_PROFILE_ACCEPT_MULTIPLE, spec );
+	g_object_class_install_property( object_class, PROP_NAPROFILE_PARAMETERS, spec );
 
 	spec = g_param_spec_pointer(
-			PROP_PROFILE_BASENAMES_STR,
-			PROP_PROFILE_BASENAMES_STR,
+			PROP_NAPROFILE_BASENAMES_STR,
+			"Filenames mask",
 			"Filenames mask",
 			G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE );
-	g_object_class_install_property( object_class, PROP_PROFILE_BASENAMES, spec );
+	g_object_class_install_property( object_class, PROP_NAPROFILE_BASENAMES, spec );
 
 	spec = g_param_spec_boolean(
-			PROP_PROFILE_ISDIR_STR,
-			PROP_PROFILE_ISDIR_STR,
-			"Whether apply when a dir is selected", FALSE,
+			PROP_NAPROFILE_MATCHCASE_STR,
+			"Match case",
+			"Whether the filenames are case sensitive", TRUE,
+			G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE );
+	g_object_class_install_property( object_class, PROP_NAPROFILE_MATCHCASE, spec );
+
+	spec = g_param_spec_pointer(
+			PROP_NAPROFILE_MIMETYPES_STR,
+			"Mimetypes",
+			"List of selectable mimetypes",
 			G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE );
-	g_object_class_install_property( object_class, PROP_PROFILE_ISDIR, spec );
+	g_object_class_install_property( object_class, PROP_NAPROFILE_MIMETYPES, spec );
 
 	spec = g_param_spec_boolean(
-			PROP_PROFILE_ISFILE_STR,
-			PROP_PROFILE_ISFILE_STR,
-			"Whether apply when a file is selected", TRUE,
+			PROP_NAPROFILE_ISFILE_STR,
+			"Only files",
+			"Whether apply when only files are selected", TRUE,
 			G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE );
-	g_object_class_install_property( object_class, PROP_PROFILE_ISFILE, spec );
+	g_object_class_install_property( object_class, PROP_NAPROFILE_ISFILE, spec );
 
 	spec = g_param_spec_boolean(
-			PROP_PROFILE_MATCHCASE_STR,
-			PROP_PROFILE_MATCHCASE_STR,
-			"Whether the filenames are case sensitive", TRUE,
+			PROP_NAPROFILE_ISDIR_STR,
+			"Only dirs",
+			"Whether apply when only dirs are selected", FALSE,
 			G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE );
-	g_object_class_install_property( object_class, PROP_PROFILE_MATCHCASE, spec );
+	g_object_class_install_property( object_class, PROP_NAPROFILE_ISDIR, spec );
 
-	spec = g_param_spec_pointer(
-			PROP_PROFILE_MIMETYPES_STR,
-			PROP_PROFILE_MIMETYPES_STR,
-			"List of selectable mimetypes",
+	spec = g_param_spec_boolean(
+			PROP_NAPROFILE_ACCEPT_MULTIPLE_STR,
+			"Accept multiple selection",
+			"Whether apply when multiple files or folders are selected", TRUE,
 			G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE );
-	g_object_class_install_property( object_class, PROP_PROFILE_MIMETYPES, spec );
+	g_object_class_install_property( object_class, PROP_NAPROFILE_ACCEPT_MULTIPLE, spec );
 
 	spec = g_param_spec_pointer(
-			PROP_PROFILE_SCHEMES_STR,
-			PROP_PROFILE_SCHEMES_STR,
+			PROP_NAPROFILE_SCHEMES_STR,
+			"Schemes",
 			"list of selectable schemes",
 			G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE );
-	g_object_class_install_property( object_class, PROP_PROFILE_SCHEMES, spec );
+	g_object_class_install_property( object_class, PROP_NAPROFILE_SCHEMES, spec );
 
 	klass->private = g_new0( NAActionProfileClassPrivate, 1 );
 
-	NA_OBJECT_CLASS( klass )->dump = do_dump;
-	NA_OBJECT_CLASS( klass )->get_id = do_get_id;
-	NA_OBJECT_CLASS( klass )->get_label = do_get_label;
+	NA_OBJECT_CLASS( klass )->dump = object_dump;
+	NA_OBJECT_CLASS( klass )->duplicate = object_duplicate;
+	NA_OBJECT_CLASS( klass )->copy = object_copy;
+	NA_OBJECT_CLASS( klass )->are_equal = object_are_equal;
+	NA_OBJECT_CLASS( klass )->is_valid = object_is_valid;
 }
 
 static void
 instance_init( GTypeInstance *instance, gpointer klass )
 {
-	static const gchar *thisfn = "na_action_profile_instance_init";
-	g_debug( "%s: instance=%p, klass=%p", thisfn, instance, klass );
+	/*static const gchar *thisfn = "na_action_profile_instance_init";
+	g_debug( "%s: instance=%p, klass=%p", thisfn, instance, klass );*/
 
 	g_assert( NA_IS_ACTION_PROFILE( instance ));
 	NAActionProfile* self = NA_ACTION_PROFILE( instance );
@@ -257,18 +273,16 @@ instance_init( GTypeInstance *instance, gpointer klass )
 
 	/* initialize suitable default values
 	 */
-	/* i18n: default label for the default profile */
-	self->private->label = g_strdup( _( "Default profile" ));
 	self->private->path = g_strdup( "" );
 	self->private->parameters = g_strdup( "" );
-	self->private->accept_multiple_files = FALSE;
 	self->private->basenames = NULL;
 	self->private->basenames = g_slist_append( self->private->basenames, g_strdup( "*" ));
-	self->private->is_dir = FALSE;
-	self->private->is_file = TRUE;
 	self->private->match_case = TRUE;
 	self->private->mimetypes = NULL;
 	self->private->mimetypes = g_slist_append( self->private->mimetypes, g_strdup( "*/*" ));
+	self->private->is_file = TRUE;
+	self->private->is_dir = FALSE;
+	self->private->accept_multiple = FALSE;
 	self->private->schemes = NULL;
 	self->private->schemes = g_slist_append( self->private->schemes, g_strdup( "file" ));
 }
@@ -282,53 +296,53 @@ instance_get_property( GObject *object, guint property_id, GValue *value, GParam
 	GSList *list;
 
 	switch( property_id ){
-		case PROP_PROFILE_ACTION:
+		case PROP_NAPROFILE_ACTION:
 			g_value_set_pointer( value, self->private->action );
 			break;
 
-		case PROP_PROFILE_NAME:
-			g_value_set_string( value, self->private->name );
+		case PROP_NAPROFILE_NAME:
+			G_OBJECT_CLASS( st_parent_class )->get_property( object, PROP_NAOBJECT_ID, value, spec );
 			break;
 
-		case PROP_PROFILE_LABEL:
-			g_value_set_string( value, self->private->label );
+		case PROP_NAPROFILE_LABEL:
+			G_OBJECT_CLASS( st_parent_class )->get_property( object, PROP_NAOBJECT_LABEL, value, spec );
 			break;
 
-		case PROP_PROFILE_PATH:
+		case PROP_NAPROFILE_PATH:
 			g_value_set_string( value, self->private->path );
 			break;
 
-		case PROP_PROFILE_PARAMETERS:
+		case PROP_NAPROFILE_PARAMETERS:
 			g_value_set_string( value, self->private->parameters );
 			break;
 
-		case PROP_PROFILE_ACCEPT_MULTIPLE:
-			g_value_set_boolean( value, self->private->accept_multiple_files );
-			break;
-
-		case PROP_PROFILE_BASENAMES:
+		case PROP_NAPROFILE_BASENAMES:
 			list = na_utils_duplicate_string_list( self->private->basenames );
 			g_value_set_pointer( value, list );
 			break;
 
-		case PROP_PROFILE_ISDIR:
-			g_value_set_boolean( value, self->private->is_dir );
+		case PROP_NAPROFILE_MATCHCASE:
+			g_value_set_boolean( value, self->private->match_case );
+			break;
+
+		case PROP_NAPROFILE_MIMETYPES:
+			list = na_utils_duplicate_string_list( self->private->mimetypes );
+			g_value_set_pointer( value, list );
 			break;
 
-		case PROP_PROFILE_ISFILE:
+		case PROP_NAPROFILE_ISFILE:
 			g_value_set_boolean( value, self->private->is_file );
 			break;
 
-		case PROP_PROFILE_MATCHCASE:
-			g_value_set_boolean( value, self->private->match_case );
+		case PROP_NAPROFILE_ISDIR:
+			g_value_set_boolean( value, self->private->is_dir );
 			break;
 
-		case PROP_PROFILE_MIMETYPES:
-			list = na_utils_duplicate_string_list( self->private->mimetypes );
-			g_value_set_pointer( value, list );
+		case PROP_NAPROFILE_ACCEPT_MULTIPLE:
+			g_value_set_boolean( value, self->private->accept_multiple );
 			break;
 
-		case PROP_PROFILE_SCHEMES:
+		case PROP_NAPROFILE_SCHEMES:
 			list = na_utils_duplicate_string_list( self->private->schemes );
 			g_value_set_pointer( value, list );
 			break;
@@ -346,57 +360,55 @@ instance_set_property( GObject *object, guint property_id, const GValue *value,
 	NAActionProfile *self = NA_ACTION_PROFILE( object );
 
 	switch( property_id ){
-		case PROP_PROFILE_ACTION:
+		case PROP_NAPROFILE_ACTION:
 			self->private->action = g_value_get_pointer( value );
 			break;
 
-		case PROP_PROFILE_NAME:
-			g_free( self->private->name );
-			self->private->name = g_value_dup_string( value );
+		case PROP_NAPROFILE_NAME:
+			G_OBJECT_CLASS( st_parent_class )->set_property( object, PROP_NAOBJECT_ID, value, spec );
 			break;
 
-		case PROP_PROFILE_LABEL:
-			g_free( self->private->label );
-			self->private->label = g_value_dup_string( value );
+		case PROP_NAPROFILE_LABEL:
+			G_OBJECT_CLASS( st_parent_class )->set_property( object, PROP_NAOBJECT_LABEL, value, spec );
 			break;
 
-		case PROP_PROFILE_PATH:
+		case PROP_NAPROFILE_PATH:
 			g_free( self->private->path );
 			self->private->path = g_value_dup_string( value );
 			break;
 
-		case PROP_PROFILE_PARAMETERS:
+		case PROP_NAPROFILE_PARAMETERS:
 			g_free( self->private->parameters );
 			self->private->parameters = g_value_dup_string( value );
 			break;
 
-		case PROP_PROFILE_ACCEPT_MULTIPLE:
-			self->private->accept_multiple_files = g_value_get_boolean( value );
-			break;
-
-		case PROP_PROFILE_BASENAMES:
+		case PROP_NAPROFILE_BASENAMES:
 			na_utils_free_string_list( self->private->basenames );
 			self->private->basenames = na_utils_duplicate_string_list( g_value_get_pointer( value ));
 			break;
 
-		case PROP_PROFILE_ISDIR:
-			self->private->is_dir = g_value_get_boolean( value );
+		case PROP_NAPROFILE_MATCHCASE:
+			self->private->match_case = g_value_get_boolean( value );
+			break;
+
+		case PROP_NAPROFILE_MIMETYPES:
+			na_utils_free_string_list( self->private->mimetypes );
+			self->private->mimetypes = na_utils_duplicate_string_list( g_value_get_pointer( value ));
 			break;
 
-		case PROP_PROFILE_ISFILE:
+		case PROP_NAPROFILE_ISFILE:
 			self->private->is_file = g_value_get_boolean( value );
 			break;
 
-		case PROP_PROFILE_MATCHCASE:
-			self->private->match_case = g_value_get_boolean( value );
+		case PROP_NAPROFILE_ISDIR:
+			self->private->is_dir = g_value_get_boolean( value );
 			break;
 
-		case PROP_PROFILE_MIMETYPES:
-			na_utils_free_string_list( self->private->mimetypes );
-			self->private->mimetypes = na_utils_duplicate_string_list( g_value_get_pointer( value ));
+		case PROP_NAPROFILE_ACCEPT_MULTIPLE:
+			self->private->accept_multiple = g_value_get_boolean( value );
 			break;
 
-		case PROP_PROFILE_SCHEMES:
+		case PROP_NAPROFILE_SCHEMES:
 			na_utils_free_string_list( self->private->schemes );
 			self->private->schemes = na_utils_duplicate_string_list( g_value_get_pointer( value ));
 			break;
@@ -434,8 +446,6 @@ instance_finalize( GObject *object )
 	g_assert( NA_IS_ACTION_PROFILE( object ));
 	NAActionProfile *self = ( NAActionProfile * ) object;
 
-	g_free( self->private->name );
-	g_free( self->private->label );
 	g_free( self->private->path );
 	g_free( self->private->parameters );
 	na_utils_free_string_list( self->private->basenames );
@@ -451,196 +461,98 @@ instance_finalize( GObject *object )
 }
 
 /**
- * Allocates a new profile for an action.
- *
- * @action: the action to which the profile must be attached.
+ * na_action_profile_new:
  *
- * @name: the internal name (identifier) of the profile.
+ * Allocates a new profile of the given name.
  *
- * Returns the newly allocated NAActionProfile object.
+ * Returns: the newly allocated #NAActionProfile profile.
  */
 NAActionProfile *
-na_action_profile_new( const NAObject *action, const gchar *name )
+na_action_profile_new( void )
 {
-	g_assert( NA_IS_ACTION( action ));
-	g_assert( name && strlen( name ));
+	NAActionProfile *profile = g_object_new( NA_ACTION_PROFILE_TYPE, NULL );
 
-	NAActionProfile *profile =
-		g_object_new(
-				NA_ACTION_PROFILE_TYPE,
-				PROP_PROFILE_ACTION_STR, action,
-				PROP_PROFILE_NAME_STR, name,
-				NULL );
+	na_action_profile_set_name( profile, ACTION_PROFILE_PREFIX "zero" );
+
+	/* i18n: default label for a new profile */
+	na_action_profile_set_label( profile, _( "Default profile" ));
 
 	return( profile );
 }
 
 /**
- * Duplicates a profile.
+ * na_action_profile_get_action:
+ * @profile: the #NAActionProfile to be requested.
  *
- * @profile: the profile to be duplicated.
+ * Returns a pointer to the action to which this profile is attached,
+ * or NULL if the profile has never been attached.
  *
- * Returns the newly allocated NAActionProfile object.
+ * Returns: a #NAAction pointer.
  *
- * Note the duplicated profile has the same internal name (identifier)
- * as the initial one, and thus cannot be attached to the same action.
+ * Note that the returned #NAAction pointer is owned by the profile.
+ * The caller should not try to g_free() nor g_object_unref() it.
  */
-NAActionProfile *
-na_action_profile_duplicate( const NAAction *action, const NAActionProfile *profile )
+NAAction *
+na_action_profile_get_action( const NAActionProfile *profile )
 {
 	g_assert( NA_IS_ACTION_PROFILE( profile ));
 
-	NAActionProfile *new =
-		na_action_profile_new( NA_OBJECT( action ), profile->private->name );
-
-	g_object_set( G_OBJECT( new ),
-			PROP_PROFILE_LABEL_STR, profile->private->label,
-			PROP_PROFILE_PATH_STR, profile->private->path,
-			PROP_PROFILE_PARAMETERS_STR, profile->private->parameters,
-			PROP_PROFILE_ACCEPT_MULTIPLE_STR, profile->private->accept_multiple_files,
-			PROP_PROFILE_BASENAMES_STR, profile->private->basenames,
-			PROP_PROFILE_ISDIR_STR, profile->private->is_dir,
-			PROP_PROFILE_ISFILE_STR, profile->private->is_file,
-			PROP_PROFILE_MATCHCASE_STR, profile->private->match_case,
-			PROP_PROFILE_MIMETYPES_STR, profile->private->mimetypes,
-			PROP_PROFILE_SCHEMES_STR, profile->private->schemes,
-			NULL );
+	NAAction *action;
+	g_object_get( G_OBJECT( profile ), PROP_NAPROFILE_ACTION_STR, &action, NULL );
 
-	return( new );
+	return( action );
 }
 
 /**
- * Frees a profile.
+ * na_action_profile_get_name:
+ * @profile: the #NAActionProfile to be requested.
  *
- * @profile: the NAActionProfile object to be freed.
- */
-void
-na_action_profile_free( NAActionProfile *profile )
-{
-	g_assert( NA_IS_ACTION_PROFILE( profile ));
-	g_object_unref( profile );
-}
-
-static void
-do_dump( const NAObject *object )
-{
-	static const gchar *thisfn = "na_action_profile_do_dump";
-
-	g_assert( NA_IS_ACTION_PROFILE( object ));
-	NAActionProfile *self = NA_ACTION_PROFILE( object );
-
-	if( st_parent_class->dump ){
-		st_parent_class->dump( object );
-	}
-
-	g_debug( "%s:               action=%p", thisfn, self->private->action );
-	g_debug( "%s:         profile_name='%s'", thisfn, self->private->name );
-	g_debug( "%s:                label='%s'", thisfn, self->private->label );
-	g_debug( "%s:                 path='%s'", thisfn, self->private->path );
-	g_debug( "%s:           parameters='%s'", thisfn, self->private->parameters );
-	g_debug( "%s: accept_multiple_file='%s'", thisfn, self->private->accept_multiple_files ? "True" : "False" );
-	g_debug( "%s:               is_dir='%s'", thisfn, self->private->is_dir ? "True" : "False" );
-	g_debug( "%s:              is_file='%s'", thisfn, self->private->is_file ? "True" : "False" );
-	g_debug( "%s:           match_case='%s'", thisfn, self->private->match_case ? "True" : "False" );
-	do_dump_list( thisfn, "basenames", self->private->basenames );
-	do_dump_list( thisfn, "mimetypes", self->private->mimetypes );
-	do_dump_list( thisfn, "  schemes", self->private->schemes );
-}
-
-static void
-do_dump_list( const gchar *thisfn, const gchar *label, GSList *list )
-{
-	GString *str;
-	str = g_string_new( "[" );
-	GSList *item;
-	for( item = list ; item != NULL ; item = item->next ){
-		if( item != list ){
-			g_string_append_printf( str, "," );
-		}
-		g_string_append_printf( str, "'%s'", ( gchar * ) item->data );
-	}
-	g_string_append_printf( str, "]" );
-	g_debug( "%s:            %s=%s", thisfn, label, str->str );
-	g_string_free( str, TRUE );
-}
-
-static gchar *
-do_get_id( const NAObject *profile )
-{
-	g_assert( NA_IS_ACTION_PROFILE( profile ));
-
-	gchar *name;
-	g_object_get( G_OBJECT( profile ), PROP_PROFILE_NAME_STR, &name, NULL );
-
-	return( name );
-}
-
-/**
  * Returns the internal name (identifier) of the profile.
  *
- * @action: an NAActionProfile object.
+ * Returns: the name of the profile as a newly allocated string.
+ * The returned string must be g_free() by the caller.
  *
- * The returned string must be g_freed by the caller.
+ * See na_action_profile_set_name() for some rationales about name.
  */
 gchar *
 na_action_profile_get_name( const NAActionProfile *profile )
 {
 	g_assert( NA_IS_ACTION_PROFILE( profile ));
-	return( na_object_get_id( NA_OBJECT( profile )));
-}
-
-static gchar *
-do_get_label( const NAObject *profile )
-{
-	g_assert( NA_IS_ACTION_PROFILE( profile ));
 
-	gchar *label;
-	g_object_get( G_OBJECT( profile ), PROP_PROFILE_LABEL_STR, &label, NULL );
-
-	return( label );
+	gchar *id;
+	g_object_get( G_OBJECT( profile ), PROP_NAPROFILE_NAME_STR, &id, NULL );
+	return( id );
 }
 
 /**
+ * na_action_profile_get_label:
+ * @profile: the #NAActionProfile to be requested.
+ *
  * Returns the descriptive name (label) of the profile.
  *
- * @action: an NAAction object.
+ * Returns: the label of the profile as a newly allocated string.
+ * The returned string must be g_free() by the caller.
  *
- * The returned string must be g_freed by the caller.
+ * See na_action_profile_set_label() for some rationale about label.
  */
 gchar *
 na_action_profile_get_label( const NAActionProfile *profile )
 {
 	g_assert( NA_IS_ACTION_PROFILE( profile ));
-	return( na_object_get_label( NA_OBJECT( profile )));
-}
-
-/**
- * Returns a pointer to the action for this profile.
- *
- * @profile: the NAActionProfile object whose parent action is to be
- * retrieved.
- *
- * Note that the returned NactNaction is owned by the profile. The
- * caller should not try to free or unref it.
- */
-NAObject *
-na_action_profile_get_action( const NAActionProfile *profile )
-{
-	g_assert( NA_IS_ACTION_PROFILE( profile ));
 
-	gpointer action;
-	g_object_get( G_OBJECT( profile ), PROP_PROFILE_ACTION_STR, &action, NULL );
-
-	return( NA_OBJECT( action ));
+	gchar *label;
+	g_object_get( G_OBJECT( profile ), PROP_NAPROFILE_LABEL_STR, &label, NULL );
+	return( label );
 }
 
 /**
- * Returns the path of the command in the profile.
+ * na_action_profile_get_path:
+ * @profile: the #NAActionProfile to be requested.
  *
- * @profile: the NAActionProfile object whose command path is to be
- * retrieved.
+ * Returns the path of the command attached to the profile.
  *
- * The returned string should be g_freed by the caller.
+ * Returns: the command path as a newly allocated string. The returned
+ * string must be g_free() by the caller.
  */
 gchar *
 na_action_profile_get_path( const NAActionProfile *profile )
@@ -648,18 +560,19 @@ na_action_profile_get_path( const NAActionProfile *profile )
 	g_assert( NA_IS_ACTION_PROFILE( profile ));
 
 	gchar *path;
-	g_object_get( G_OBJECT( profile ), PROP_PROFILE_PATH_STR, &path, NULL );
+	g_object_get( G_OBJECT( profile ), PROP_NAPROFILE_PATH_STR, &path, NULL );
 
 	return( path );
 }
 
 /**
- * Returns the parameters of the command in the profile.
+ * na_action_profile_get_parameters:
+ * @profile: the #NAActionProfile to be requested.
  *
- * @profile: the NAActionProfile object whose command parameters are
- * to be retrieved.
+ * Returns the parameters of the command attached to the profile.
  *
- * The returned string should be g_freed by the caller.
+ * Returns: the command parameters as a newly allocated string. The
+ * returned string must be g_free() by the caller.
  */
 gchar *
 na_action_profile_get_parameters( const NAActionProfile *profile )
@@ -667,18 +580,22 @@ na_action_profile_get_parameters( const NAActionProfile *profile )
 	g_assert( NA_IS_ACTION_PROFILE( profile ));
 
 	gchar *parameters;
-	g_object_get( G_OBJECT( profile ), PROP_PROFILE_PARAMETERS_STR, &parameters, NULL );
+	g_object_get( G_OBJECT( profile ), PROP_NAPROFILE_PARAMETERS_STR, &parameters, NULL );
 
 	return( parameters );
 }
 
 /**
- * Returns the list of basenames this profile applies to.
+ * na_action_profile_get_basenames:
+ * @profile: the #NAActionProfile to be requested.
+ *
+ * Returns the basenames of the files to which the profile applies.
  *
- * @profile: this NAActionProfile object.
+ * Returns: a GSList of newly allocated strings. The list must be
+ * na_utils_free_string_list() by the caller.
  *
- * The returned GSList should be freed by the caller by calling
- * na_utils_free_string_list.
+ * See na_action_profile_set_basenames() for some rationale about
+ * basenames.
  */
 GSList *
 na_action_profile_get_basenames( const NAActionProfile *profile )
@@ -686,15 +603,22 @@ na_action_profile_get_basenames( const NAActionProfile *profile )
 	g_assert( NA_IS_ACTION_PROFILE( profile ));
 
 	GSList *basenames;
-	g_object_get( G_OBJECT( profile ), PROP_PROFILE_BASENAMES_STR, &basenames, NULL );
+	g_object_get( G_OBJECT( profile ), PROP_NAPROFILE_BASENAMES_STR, &basenames, NULL );
 
 	return( basenames );
 }
 
 /**
+ * na_action_profile_get_matchcase:
+ * @profile: the #NAActionProfile to be requested.
+ *
  * Are specified basenames case sensitive ?
  *
- * @profile: this NAActionProfile object.
+ * Returns: %TRUE if the provided filenames are case sensitive, %FALSE
+ * else.
+ *
+ * See na_action_profile_set_matchcase() for some rationale about case
+ * sensitivity.
  */
 gboolean
 na_action_profile_get_matchcase( const NAActionProfile *profile )
@@ -702,18 +626,22 @@ na_action_profile_get_matchcase( const NAActionProfile *profile )
 	g_assert( NA_IS_ACTION_PROFILE( profile ));
 
 	gboolean matchcase;
-	g_object_get( G_OBJECT( profile ), PROP_PROFILE_MATCHCASE_STR, &matchcase, NULL );
+	g_object_get( G_OBJECT( profile ), PROP_NAPROFILE_MATCHCASE_STR, &matchcase, NULL );
 
 	return( matchcase );
 }
 
 /**
+ * na_action_profile_get_mimetypes:
+ * @profile: the #NAActionProfile to be requested.
+ *
  * Returns the list of mimetypes this profile applies to.
  *
- * @profile: this NAActionProfile object.
+ * Returns: a GSList of newly allocated strings. The list must be
+ * na_utils_free_string_list() by the caller.
  *
- * The returned GSList should be freed by the caller by calling
- * na_utils_free_string_list.
+ * See na_action_profile_set_mimetypes() for some rationale about
+ * mimetypes.
  */
 GSList *
 na_action_profile_get_mimetypes( const NAActionProfile *profile )
@@ -721,15 +649,21 @@ na_action_profile_get_mimetypes( const NAActionProfile *profile )
 	g_assert( NA_IS_ACTION_PROFILE( profile ));
 
 	GSList *mimetypes;
-	g_object_get( G_OBJECT( profile ), PROP_PROFILE_MIMETYPES_STR, &mimetypes, NULL );
+	g_object_get( G_OBJECT( profile ), PROP_NAPROFILE_MIMETYPES_STR, &mimetypes, NULL );
 
 	return( mimetypes );
 }
 
 /**
- * Does this profile apply to files ?
+ * na_action_profile_get_is_file:
+ * @profile: the #NAActionProfile to be requested.
  *
- * @profile: this NAActionProfile object.
+ * Does this profile apply if the selection contains files ?
+ *
+ * Returns: %TRUE if it applies, %FALSE else.
+ *
+ * See na_action_profile_set_isfiledir() for some rationale about file
+ * selection.
  */
 gboolean
 na_action_profile_get_is_file( const NAActionProfile *profile )
@@ -737,15 +671,21 @@ na_action_profile_get_is_file( const NAActionProfile *profile )
 	g_assert( NA_IS_ACTION_PROFILE( profile ));
 
 	gboolean isfile;
-	g_object_get( G_OBJECT( profile ), PROP_PROFILE_ISFILE_STR, &isfile, NULL );
+	g_object_get( G_OBJECT( profile ), PROP_NAPROFILE_ISFILE_STR, &isfile, NULL );
 
 	return( isfile );
 }
 
 /**
- * Does this profile apply to directories ?
+ * na_action_profile_get_is_dir:
+ * @profile: the #NAActionProfile to be requested.
+ *
+ * Does this profile apply if the selection contains folders ?
  *
- * @profile: this NAActionProfile object.
+ * Returns: %TRUE if it applies, %FALSE else.
+ *
+ * See na_action_profile_set_isfiledir() for some rationale about file
+ * selection.
  */
 gboolean
 na_action_profile_get_is_dir( const NAActionProfile *profile )
@@ -753,15 +693,22 @@ na_action_profile_get_is_dir( const NAActionProfile *profile )
 	g_assert( NA_IS_ACTION_PROFILE( profile ));
 
 	gboolean isdir;
-	g_object_get( G_OBJECT( profile ), PROP_PROFILE_ISDIR_STR, &isdir, NULL );
+	g_object_get( G_OBJECT( profile ), PROP_NAPROFILE_ISDIR_STR, &isdir, NULL );
 
 	return( isdir );
 }
 
 /**
- * Does this profile apply on a multiple selection ?
+ * na_action_profile_get_multiple:
+ * @profile: the #NAActionProfile to be requested.
+ *
+ * Does this profile apply if selection contains multiple files or
+ * folders ?
  *
- * @profile: this NAActionProfile object.
+ * Returns: %TRUE if it applies, %FALSE else.
+ *
+ * See na_action_profile_set_multiple() for some rationale about
+ * multiple selection.
  */
 gboolean
 na_action_profile_get_multiple( const NAActionProfile *profile )
@@ -769,18 +716,22 @@ na_action_profile_get_multiple( const NAActionProfile *profile )
 	g_assert( NA_IS_ACTION_PROFILE( profile ));
 
 	gboolean multiple;
-	g_object_get( G_OBJECT( profile ), PROP_PROFILE_ACCEPT_MULTIPLE_STR, &multiple, NULL );
+	g_object_get( G_OBJECT( profile ), PROP_NAPROFILE_ACCEPT_MULTIPLE_STR, &multiple, NULL );
 
 	return( multiple );
 }
 
 /**
+ * na_action_profile_get_schemes:
+ * @profile: the #NAActionProfile to be requested.
+ *
  * Returns the list of schemes this profile applies to.
  *
- * @profile: this NAActionProfile object.
+ * Returns: a GSList of newly allocated strings. The list must be
+ * na_utils_free_string_list() by the caller.
  *
- * The returned GSList should be freed by the caller by calling
- * na_utils_free_string_list.
+ * See na_action_profile_set_schemes() for some rationale about
+ * schemes.
  */
 GSList *
 na_action_profile_get_schemes( const NAActionProfile *profile )
@@ -788,219 +739,254 @@ na_action_profile_get_schemes( const NAActionProfile *profile )
 	g_assert( NA_IS_ACTION_PROFILE( profile ));
 
 	GSList *schemes;
-	g_object_get( G_OBJECT( profile ), PROP_PROFILE_SCHEMES_STR, &schemes, NULL );
+	g_object_get( G_OBJECT( profile ), PROP_NAPROFILE_SCHEMES_STR, &schemes, NULL );
 
 	return( schemes );
 }
 
 /**
- * Returns TRUE if the profile are the same, excluding action pointer.
- *
- * @first: a NAActionProfile.
+ * na_action_profile_set_action:
+ * @profile: the #NAActionProfile to be updated.
+ * @action: the #NAAction action to which this profile is attached.
  *
- * @second: another NAActionProfile, to be compared with @first.
+ * Sets the action to which this profile is attached.
  */
-gboolean
-na_action_profile_are_equal( NAActionProfile *first, NAActionProfile *second )
+void
+na_action_profile_set_action( NAActionProfile *profile, const NAAction *action )
 {
-	gboolean equal =
-		( g_utf8_collate( first->private->name, second->private->name ) == 0 ) &&
-		( g_utf8_collate( first->private->label, second->private->label ) == 0 ) &&
-		( g_utf8_collate( first->private->path, second->private->path ) == 0 ) &&
-		( g_utf8_collate( first->private->parameters, second->private->parameters ) == 0 );
+	g_assert( NA_IS_ACTION_PROFILE( profile ));
 
-	if( equal ){
-		equal = (( first->private->accept_multiple_files && second->private->accept_multiple_files ) ||
-				( !first->private->accept_multiple_files && !second->private->accept_multiple_files ));
-	}
-	if( equal ){
-		equal = (( first->private->is_dir && second->private->is_dir ) ||
-				( !first->private->is_dir && !second->private->is_dir ));
-	}
-	if( equal ){
-		equal = (( first->private->is_file && second->private->is_file ) ||
-				( !first->private->is_file && !second->private->is_file ));
-	}
-	if( equal ){
-		equal = na_utils_string_lists_are_equal( first->private->basenames, second->private->basenames ) &&
-				na_utils_string_lists_are_equal( first->private->mimetypes, second->private->mimetypes ) &&
-				na_utils_string_lists_are_equal( first->private->schemes, second->private->schemes );
-	}
-	return( equal );
+	g_object_set( G_OBJECT( profile ), PROP_NAPROFILE_ACTION_STR, action, NULL );
 }
 
-static int
-validate_schemes( GSList* schemes2test, NautilusFileInfo* file )
+/**
+ * na_action_profile_set_name:
+ * @profile: the #NAActionProfile to be updated.
+ * @name: the name to be set.
+ *
+ * Sets the name for this profile.
+ *
+ * #NAActionProfile takes a copy of the provided name. This later may
+ * so be g_free() by the caller after this function returns.
+ *
+ * The profile name is an ASCII, case insensitive, string which
+ * uniquely identifies the profile inside of the action.
+ *
+ * This function doesn't check for the unicity of the name. And this
+ * unicity will never be checked until we try to write the action to
+ * GConf.
+ */
+void
+na_action_profile_set_name( NAActionProfile *profile, const gchar *name )
 {
-	int retv = 0;
-	GSList* iter;
-	gboolean found = FALSE;
-
-	iter = schemes2test;
-	while (iter && !found)
-	{
-		gchar* scheme = nautilus_file_info_get_uri_scheme (file);
-
-		if (g_ascii_strncasecmp (scheme, (gchar*)iter->data, strlen ((gchar*)iter->data)) == 0)
-		{
-			found = TRUE;
-			retv = 1;
-		}
-
-		g_free (scheme);
-		iter = iter->next;
-	}
+	g_assert( NA_IS_ACTION_PROFILE( profile ));
 
-	return retv;
+	g_object_set( G_OBJECT( profile ), PROP_NAPROFILE_NAME_STR, name, NULL );
 }
 
 /**
- * Set the label for this profile.
+ * na_action_profile_set_label:
+ * @profile: the #NAActionProfile to be updated.
+ * @label: the label to be set.
  *
- * @profile: this NAActionProfile object.
+ * Sets the label for this profile.
  *
- * @label: label to be set.
+ * #NAActionProfile takes a copy of the provided label. This later may
+ * so be g_free() by the caller after this function returns.
+ *
+ * The label of the #NAActionProfile is an UTF-8 string.
  */
 void
 na_action_profile_set_label( NAActionProfile *profile, const gchar *label )
 {
-	g_object_set( G_OBJECT( profile ), PROP_PROFILE_LABEL_STR, label, NULL );
+	g_assert( NA_IS_ACTION_PROFILE( profile ));
+
+	g_object_set( G_OBJECT( profile ), PROP_NAPROFILE_LABEL_STR, label, NULL );
 }
 
 /**
- * Set the path of the command for this profile.
+ * na_action_profile_set_path:
+ * @profile: the #NAActionProfile to be updated.
+ * @path: the command path to be set.
  *
- * @profile: this NAActionProfile object.
+ * Sets the path of the command for this profile.
  *
- * @path: path to be set.
+ * #NAActionProfile takes a copy of the provided path. This later may
+ * so be g_free() by the caller after this function returns.
  */
 void
 na_action_profile_set_path( NAActionProfile *profile, const gchar *path )
 {
-	g_object_set( G_OBJECT( profile ), PROP_PROFILE_PATH_STR, path, NULL );
+	g_assert( NA_IS_ACTION_PROFILE( profile ));
+
+	g_object_set( G_OBJECT( profile ), PROP_NAPROFILE_PATH_STR, path, NULL );
 }
 
 /**
- * Set the parameters of the command for this profile.
+ * na_action_profile_set_parameters:
+ * @profile: the #NAActionProfile to be updated.
+ * @parameters : the command parameters to be set.
  *
- * @profile: this NAActionProfile object.
+ * Sets the parameters of the command for this profile.
  *
- * @parameters: parameters to be set.
+ * #NAActionProfile takes a copy of the provided parameters. This later
+ * may so be g_free() by the caller after this function returns.
  */
 void
 na_action_profile_set_parameters( NAActionProfile *profile, const gchar *parameters )
 {
-	g_object_set( G_OBJECT( profile ), PROP_PROFILE_PARAMETERS_STR, parameters, NULL );
+	g_assert( NA_IS_ACTION_PROFILE( profile ));
+
+	g_object_set( G_OBJECT( profile ), PROP_NAPROFILE_PARAMETERS_STR, parameters, NULL );
 }
 
 /**
- * Set the basenames on which this profile applies.
+ * na_action_profile_set_basenames:
+ * @profile: the #NAActionProfile to be updated.
+ * @basenames : the basenames to be set.
+ *
+ * Sets the basenames of the elements on which this profile applies.
  *
- * @profile: this NAActionProfile object.
+ * #NAActionProfile takes a copy of the provided basenames. This later
+ * may so be na_utils_free_string_list() by the caller after this
+ * function returns.
  *
- * @basenames: list of basenames to be matched.
+ * The basenames list defaults to the single element "*", which means
+ * that the profile will apply to all basenames.
  */
 void
 na_action_profile_set_basenames( NAActionProfile *profile, GSList *basenames )
 {
-	g_object_set( G_OBJECT( profile ), PROP_PROFILE_BASENAMES_STR, basenames, NULL );
+	g_assert( NA_IS_ACTION_PROFILE( profile ));
+
+	g_object_set( G_OBJECT( profile ), PROP_NAPROFILE_BASENAMES_STR, basenames, NULL );
 }
 
 /**
- * Set the 'match_case' flag, indicating if specified basename patterns
- * are, or not, case sensitive.
+ * na_action_profile_set_matchcase:
+ * @profile: the #NAActionProfile to be updated.
+ * @matchcase : whether the basenames are case sensitive or not.
  *
- * @profile: this NAActionProfile object.
+ * Sets the 'match_case' flag, indicating if specified basename
+ * patterns are, or not, case sensitive.
  *
- * @matchcase: TRUE if basename patterns are case sensitive.
+ * This value defaults to %TRUE, which means that basename patterns
+ * default to be case sensitive.
  */
 void
 na_action_profile_set_matchcase( NAActionProfile *profile, gboolean matchcase )
 {
-	g_object_set( G_OBJECT( profile ), PROP_PROFILE_MATCHCASE_STR, matchcase, NULL );
+	g_assert( NA_IS_ACTION_PROFILE( profile ));
+
+	g_object_set( G_OBJECT( profile ), PROP_NAPROFILE_MATCHCASE_STR, matchcase, NULL );
 }
 
 /**
- * Set the mimetypes on which this profile applies.
+ * na_action_profile_set_mimetypes:
+ * @profile: the #NAActionProfile to be updated.
+ * @mimetypes: list of mimetypes to be matched.
  *
- * @profile: this NAActionProfile object.
+ * Sets the mimetypes on which this profile applies.
  *
- * @mimetypes: list of mimetypes to be matched.
+ * #NAActionProfile takes a copy of the provided mimetypes. This later
+ * may so be na_utils_free_string_list() by the caller after this
+ * function returns.
+ *
+ * The mimetypes list defaults to the single element "* / *", which
+ * means that the profile will apply to all types of files.
  */
 void
 na_action_profile_set_mimetypes( NAActionProfile *profile, GSList *mimetypes )
 {
-	g_object_set( G_OBJECT( profile ), PROP_PROFILE_MIMETYPES_STR, mimetypes, NULL );
+	g_assert( NA_IS_ACTION_PROFILE( profile ));
+
+	g_object_set( G_OBJECT( profile ), PROP_NAPROFILE_MIMETYPES_STR, mimetypes, NULL );
 }
 
 /**
- * Set the 'isfile' flag on which this profile applies.
- *
- * @profile: this NAActionProfile object.
+ * na_action_profile_set_isfile:
+ * @profile: the #NAActionProfile to be updated.
+ * @isfile: whether the profile applies only to files.
  *
- * @isfile: the profile applies only to files.
+ * Sets the 'isfile' flag on which this profile applies.
  */
 void
 na_action_profile_set_isfile( NAActionProfile *profile, gboolean isfile )
 {
-	g_object_set( G_OBJECT( profile ), PROP_PROFILE_ISFILE_STR, isfile, NULL );
+	g_assert( NA_IS_ACTION_PROFILE( profile ));
+
+	g_object_set( G_OBJECT( profile ), PROP_NAPROFILE_ISFILE_STR, isfile, NULL );
 }
 
 /**
- * Set the 'isdir' flag on which this profile applies.
- *
- * @profile: this NAActionProfile object.
- *
+ * na_action_profile_set_isdir:
+ * @profile: the #NAActionProfile to be updated.
  * @isdir: the profile applies only to folders.
+ *
+ * Sets the 'isdir' flag on which this profile applies.
  */
 void
 na_action_profile_set_isdir( NAActionProfile *profile, gboolean isdir )
 {
-	g_object_set( G_OBJECT( profile ), PROP_PROFILE_ISDIR_STR, isdir, NULL );
+	g_assert( NA_IS_ACTION_PROFILE( profile ));
+
+	g_object_set( G_OBJECT( profile ), PROP_NAPROFILE_ISDIR_STR, isdir, NULL );
 }
 
 /**
- * Set the 'isfile' and 'isdir' flags on which this profile applies.
+ * na_action_profile_set_isfiledir:
+ * @profile: the #NAActionProfile to be updated.
+ * @isfile: whether the profile applies only to files.
+ * @isdir: the profile applies only to folders.
  *
- * @profile: this NAActionProfile object.
+ * Sets the 'isfile' and 'isdir' flags on which this profile applies.
  *
- * @isfile: the profile applies only to files.
+ * File selection defaults to %TRUE.
  *
- * @isdir: the profile applies only to folders.
+ * Folder selection defaults to %FALSE, which means that this profile will
+ * not apply if the selection contains folders.
  */
 void
 na_action_profile_set_isfiledir( NAActionProfile *profile, gboolean isfile, gboolean isdir )
 {
-	g_object_set( G_OBJECT( profile ), PROP_PROFILE_ISFILE_STR, isfile, PROP_PROFILE_ISDIR_STR, isdir, NULL );
+	g_assert( NA_IS_ACTION_PROFILE( profile ));
+
+	g_object_set( G_OBJECT( profile ), PROP_NAPROFILE_ISFILE_STR, isfile, PROP_NAPROFILE_ISDIR_STR, isdir, NULL );
 }
 
 /**
- * Does this profile accept multiple selection ?
+ * na_action_profile_set_multiple:
+ * @profile: the #NAActionProfile to be updated.
+ * @multiple: TRUE if it does.
  *
- * @profile: this NAActionProfile object.
+ * Sets if this profile accept multiple selection ?
  *
- * @multiple: TRUE if it does.
+ * This value defaults to %FALSE, which means that this profile will
+ * not apply if the selection contains more than one element.
  */
 void
 na_action_profile_set_multiple( NAActionProfile *profile, gboolean multiple )
 {
-	g_object_set( G_OBJECT( profile ), PROP_PROFILE_ACCEPT_MULTIPLE_STR, multiple, NULL );
+	g_assert( NA_IS_ACTION_PROFILE( profile ));
+
+	g_object_set( G_OBJECT( profile ), PROP_NAPROFILE_ACCEPT_MULTIPLE_STR, multiple, NULL );
 }
 
 /**
- * Set the status of a scheme relative to this profile.
- *
- * @profile: this NAActionProfile object.
- *
- * @scheme: nae of the scheme.
- *
+ * na_action_profile_set_scheme:
+ * @profile: the #NAActionProfile to be updated.
+ * @scheme: name of the scheme.
  * @selected: whether this scheme is candidate to this profile.
+ *
+ * Sets the status of a scheme relative to this profile.
  */
 void
 na_action_profile_set_scheme( NAActionProfile *profile, const gchar *scheme, gboolean selected )
 {
 	/*static const gchar *thisfn = "na_action_profile_set_scheme";*/
 
+	g_assert( NA_IS_ACTION_PROFILE( profile ));
+
 	gboolean exist = na_utils_find_in_list( profile->private->schemes, scheme );
 	/*g_debug( "%s: scheme=%s exist=%s", thisfn, scheme, exist ? "True":"False" );*/
 
@@ -1013,30 +999,45 @@ na_action_profile_set_scheme( NAActionProfile *profile, const gchar *scheme, gbo
 }
 
 /**
- * Set the schemes on which this profile applies.
+ * na_action_profile_set_schemes:
+ * @profile: the #NAActionProfile to be updated.
+ * @schemes: list of schemes which apply.
  *
- * @profile: this NAActionProfile object.
+ * Sets the schemes on which this profile applies.
  *
- * @schemes: list of schemes which apply.
+ * #NAActionProfile takes a copy of the provided mimetypes. This later
+ * may so be na_utils_free_string_list() by the caller after this
+ * function returns.
+ *
+ * The schemes list defaults to the single element "file", which means
+ * that the profile will only apply to local files.
  */
 void
 na_action_profile_set_schemes( NAActionProfile *profile, GSList *schemes )
 {
-	g_object_set( G_OBJECT( profile ), PROP_PROFILE_SCHEMES_STR, schemes, NULL );
+	g_assert( NA_IS_ACTION_PROFILE( profile ));
+
+	g_object_set( G_OBJECT( profile ), PROP_NAPROFILE_SCHEMES_STR, schemes, NULL );
 }
 
 /**
+ * na_action_profile_is_candidate:
+ * @profile: the #NAActionProfile to be checked.
+ * @files: the currently selected items, as provided by Nautilus.
+ *
  * Determines if the given profile is candidate to be displayed in the
  * Nautilus context menu, regarding the list of currently selected
  * items.
  *
- * @profile: the profile to be examined.
- *
- * @files: the list currently selected items, as provided by Nautilus.
+ * Returns: %TRUE if this profile succeeds to all tests and is so a
+ * valid candidate to be displayed in Nautilus context menu, %FALSE
+ * else.
  */
 gboolean
 na_action_profile_is_candidate( const NAActionProfile *profile, GList* files )
 {
+	g_assert( NA_IS_ACTION_PROFILE( profile ));
+
 	gboolean retv = FALSE;
 	gboolean test_multiple_file = FALSE;
 	gboolean test_file_type = FALSE;
@@ -1186,11 +1187,11 @@ na_action_profile_is_candidate( const NAActionProfile *profile, GList* files )
 		total_count++;
 	}
 
-	if ((files != NULL) && (files->next == NULL) && (!profile->private->accept_multiple_files))
+	if ((files != NULL) && (files->next == NULL) && (!profile->private->accept_multiple))
 	{
 		test_multiple_file = TRUE;
 	}
-	else if (profile->private->accept_multiple_files)
+	else if (profile->private->accept_multiple)
 	{
 		test_multiple_file = TRUE;
 	}
@@ -1419,3 +1420,175 @@ na_action_profile_parse_parameters( const NAActionProfile *profile, GList* files
 	parsed = g_string_free( string, FALSE );
 	return( parsed );
 }
+
+static void
+object_dump( const NAObject *object )
+{
+	static const gchar *thisfn = "na_action_profile_object_dump";
+
+	g_assert( NA_IS_ACTION_PROFILE( object ));
+	NAActionProfile *self = NA_ACTION_PROFILE( object );
+
+	if( st_parent_class->dump ){
+		st_parent_class->dump( object );
+	}
+
+	g_debug( "%s:          action=%p", thisfn, self->private->action );
+	g_debug( "%s:            path='%s'", thisfn, self->private->path );
+	g_debug( "%s:      parameters='%s'", thisfn, self->private->parameters );
+	g_debug( "%s: accept_multiple='%s'", thisfn, self->private->accept_multiple ? "True" : "False" );
+	g_debug( "%s:          is_dir='%s'", thisfn, self->private->is_dir ? "True" : "False" );
+	g_debug( "%s:         is_file='%s'", thisfn, self->private->is_file ? "True" : "False" );
+	g_debug( "%s:      match_case='%s'", thisfn, self->private->match_case ? "True" : "False" );
+	object_dump_list( thisfn, "basenames", self->private->basenames );
+	object_dump_list( thisfn, "mimetypes", self->private->mimetypes );
+	object_dump_list( thisfn, "  schemes", self->private->schemes );
+}
+
+static void
+object_dump_list( const gchar *thisfn, const gchar *label, GSList *list )
+{
+	gchar *string = na_utils_gslist_to_schema( list );
+	g_debug( "%s:       %s=%s", thisfn, label, string );
+	g_free( string );
+}
+
+static NAObject *
+object_duplicate( const NAObject *profile )
+{
+	g_assert( NA_IS_ACTION_PROFILE( profile ));
+
+	NAObject *duplicate = NA_OBJECT( na_action_profile_new());
+
+	na_object_copy( duplicate, profile );
+
+	return( duplicate );
+}
+
+static void
+object_copy( NAObject *target, const NAObject *source )
+{
+	g_assert( NA_IS_ACTION_PROFILE( target ));
+	g_assert( NA_IS_ACTION_PROFILE( source ));
+
+	gchar *path, *parameters;
+	gboolean matchcase, isfile, isdir, multiple;
+	GSList *basenames, *mimetypes, *schemes;
+
+	g_object_get( G_OBJECT( source ),
+			PROP_NAPROFILE_PATH_STR, &path,
+			PROP_NAPROFILE_PARAMETERS_STR, &parameters,
+			PROP_NAPROFILE_BASENAMES_STR, &basenames,
+			PROP_NAPROFILE_MATCHCASE_STR, &matchcase,
+			PROP_NAPROFILE_MIMETYPES_STR, &mimetypes,
+			PROP_NAPROFILE_ISFILE_STR, &isfile,
+			PROP_NAPROFILE_ISDIR_STR, &isdir,
+			PROP_NAPROFILE_ACCEPT_MULTIPLE_STR, &multiple,
+			PROP_NAPROFILE_SCHEMES_STR, &schemes,
+			NULL );
+
+	g_object_set( G_OBJECT( target ),
+			PROP_NAPROFILE_PATH_STR, path,
+			PROP_NAPROFILE_PARAMETERS_STR, parameters,
+			PROP_NAPROFILE_BASENAMES_STR, basenames,
+			PROP_NAPROFILE_MATCHCASE_STR, matchcase,
+			PROP_NAPROFILE_MIMETYPES_STR, mimetypes,
+			PROP_NAPROFILE_ISFILE_STR, isfile,
+			PROP_NAPROFILE_ISDIR_STR, isdir,
+			PROP_NAPROFILE_ACCEPT_MULTIPLE_STR, multiple,
+			PROP_NAPROFILE_SCHEMES_STR, schemes,
+			NULL );
+
+	g_free( path );
+	g_free( parameters );
+	na_utils_free_string_list( basenames );
+	na_utils_free_string_list( mimetypes );
+	na_utils_free_string_list( schemes );
+
+	if( st_parent_class->copy ){
+		st_parent_class->copy( target, source );
+	}
+}
+
+gboolean
+object_are_equal( const NAObject *a, const NAObject *b )
+{
+	g_assert( NA_IS_ACTION_PROFILE( a ));
+	g_assert( NA_IS_ACTION_PROFILE( b ));
+
+	NAActionProfile *first = NA_ACTION_PROFILE( a );
+	NAActionProfile *second = NA_ACTION_PROFILE( b );
+
+	gboolean equal =
+		( g_utf8_collate( first->private->path, second->private->path ) == 0 ) &&
+		( g_utf8_collate( first->private->parameters, second->private->parameters ) == 0 );
+
+	if( equal ){
+		equal = (( first->private->accept_multiple && second->private->accept_multiple ) ||
+				( !first->private->accept_multiple && !second->private->accept_multiple ));
+	}
+	if( equal ){
+		equal = (( first->private->is_dir && second->private->is_dir ) ||
+				( !first->private->is_dir && !second->private->is_dir ));
+	}
+	if( equal ){
+		equal = (( first->private->is_file && second->private->is_file ) ||
+				( !first->private->is_file && !second->private->is_file ));
+	}
+	if( equal ){
+		equal = na_utils_string_lists_are_equal( first->private->basenames, second->private->basenames ) &&
+				na_utils_string_lists_are_equal( first->private->mimetypes, second->private->mimetypes ) &&
+				na_utils_string_lists_are_equal( first->private->schemes, second->private->schemes );
+	}
+	if( equal ){
+		if( st_parent_class->are_equal ){
+			equal = st_parent_class->are_equal( a, b );
+		}
+	}
+
+	return( equal );
+}
+
+gboolean
+object_is_valid( const NAObject *profile )
+{
+	g_assert( NA_IS_ACTION_PROFILE( profile ));
+
+	gchar *label;
+	g_object_get( G_OBJECT( profile ), PROP_NAPROFILE_LABEL_STR, &label, NULL );
+	gboolean is_valid = ( label && g_utf8_strlen( label, -1 ) > 0 );
+	g_free( label );
+
+	if( is_valid ){
+		if( st_parent_class->is_valid ){
+			is_valid = st_parent_class->is_valid( profile );
+		}
+	}
+
+	return( is_valid );
+}
+
+static int
+validate_schemes( GSList* schemes2test, NautilusFileInfo* file )
+{
+	int retv = 0;
+	GSList* iter;
+	gboolean found = FALSE;
+
+	iter = schemes2test;
+	while (iter && !found)
+	{
+		gchar* scheme = nautilus_file_info_get_uri_scheme (file);
+
+		if (g_ascii_strncasecmp (scheme, (gchar*)iter->data, strlen ((gchar*)iter->data)) == 0)
+		{
+			found = TRUE;
+			retv = 1;
+		}
+
+		g_free (scheme);
+		iter = iter->next;
+	}
+
+	return retv;
+}
diff --git a/src/common/na-action-profile.h b/src/common/na-action-profile.h
index 407ee2c..fcad4c0 100644
--- a/src/common/na-action-profile.h
+++ b/src/common/na-action-profile.h
@@ -31,71 +31,32 @@
 #ifndef __NA_ACTION_PROFILE_H__
 #define __NA_ACTION_PROFILE_H__
 
-/*
- * NactActionProfile class definition.
+/**
+ * SECTION: na_action_profile
+ * @short_description: #NAActionProfile class definition.
+ * @include: common/na-action-profile.h
  *
- * This is a companion class of NactAction. It embeds the profile
+ * This is a companion class of NAAction. It embeds the profile
  * definition of an action.
  *
- * As NactAction itself, NactActionProfile class is derived from
- * NAObject which takes care of i/o.
+ * As NAAction itself, NAActionProfile class is derived from
+ * NAObject class, which takes care of IDuplicable interface management.
  */
 
-#include "na-object.h"
+#include "na-action-class.h"
+#include "na-action-profile-class.h"
 
 G_BEGIN_DECLS
 
-#define NA_ACTION_PROFILE_TYPE					( na_action_profile_get_type())
-#define NA_ACTION_PROFILE( object )				( G_TYPE_CHECK_INSTANCE_CAST( object, NA_ACTION_PROFILE_TYPE, NAActionProfile ))
-#define NA_ACTION_PROFILE_CLASS( klass )		( G_TYPE_CHECK_CLASS_CAST( klass, NA_ACTION_PROFILE_TYPE, NAActionProfileClass ))
-#define NA_IS_ACTION_PROFILE( object )			( G_TYPE_CHECK_INSTANCE_TYPE( object, NA_ACTION_PROFILE_TYPE ))
-#define NA_IS_ACTION_PROFILE_CLASS( klass )		( G_TYPE_CHECK_CLASS_TYPE(( klass ), NA_ACTION_PROFILE_TYPE ))
-#define NA_ACTION_PROFILE_GET_CLASS( object )	( G_TYPE_INSTANCE_GET_CLASS(( object ), NA_ACTION_PROFILE_TYPE, NAActionProfileClass ))
-
-typedef struct NAActionProfilePrivate NAActionProfilePrivate;
-
-typedef struct {
-	NAObject                parent;
-	NAActionProfilePrivate *private;
-}
-	NAActionProfile;
-
-typedef struct NAActionProfileClassPrivate NAActionProfileClassPrivate;
-
-typedef struct {
-	NAObjectClass                parent;
-	NAActionProfileClassPrivate *private;
-}
-	NAActionProfileClass;
-
-/* instance properties
- */
-#define PROP_PROFILE_ACTION_STR					"profile-action"
-#define PROP_PROFILE_NAME_STR					"profile-name"
-#define PROP_PROFILE_LABEL_STR					"profile-desc-name"
-#define PROP_PROFILE_PATH_STR					"profile-path"
-#define PROP_PROFILE_PARAMETERS_STR				"profile-parameters"
-#define PROP_PROFILE_BASENAMES_STR				"profile-basenames"
-#define PROP_PROFILE_MATCHCASE_STR				"profile-matchcase"
-#define PROP_PROFILE_ISDIR_STR					"profile-isdir"
-#define PROP_PROFILE_ISFILE_STR					"profile-isfile"
-#define PROP_PROFILE_ACCEPT_MULTIPLE_STR		"profile-accept-multiple-files"
-#define PROP_PROFILE_MIMETYPES_STR				"profile-mimetypes"
-#define PROP_PROFILE_SCHEMES_STR				"profile-schemes"
-
 /* internal identifier of profiles must begin with the following prefix
  * this let us identify a profile key versus an action key
  * corollarily, no action entry must begin with this same prefix
  */
-#define ACTION_PROFILE_PREFIX					"profile-"
-
-GType            na_action_profile_get_type( void );
+#define ACTION_PROFILE_PREFIX			"profile-"
 
-NAActionProfile *na_action_profile_new( const NAObject *action, const gchar *name );
-NAActionProfile *na_action_profile_duplicate( const NAAction *action, const NAActionProfile *profile );
-void             na_action_profile_free( NAActionProfile *profile );
+NAActionProfile *na_action_profile_new( void );
 
-NAObject        *na_action_profile_get_action( const NAActionProfile *profile );
+NAAction        *na_action_profile_get_action( const NAActionProfile *profile );
 gchar           *na_action_profile_get_name( const NAActionProfile *profile );
 gchar           *na_action_profile_get_label( const NAActionProfile *profile );
 gchar           *na_action_profile_get_path( const NAActionProfile *profile );
@@ -103,13 +64,13 @@ gchar           *na_action_profile_get_parameters( const NAActionProfile *profil
 GSList          *na_action_profile_get_basenames( const NAActionProfile *profile );
 gboolean         na_action_profile_get_matchcase( const NAActionProfile *profile );
 GSList          *na_action_profile_get_mimetypes( const NAActionProfile *profile );
-gboolean         na_action_profile_get_is_dir( const NAActionProfile *profile );
 gboolean         na_action_profile_get_is_file( const NAActionProfile *profile );
+gboolean         na_action_profile_get_is_dir( const NAActionProfile *profile );
 gboolean         na_action_profile_get_multiple( const NAActionProfile *profile );
 GSList          *na_action_profile_get_schemes( const NAActionProfile *profile );
 
-gboolean         na_action_profile_are_equal( NAActionProfile *first, NAActionProfile *second );
-
+void             na_action_profile_set_action( NAActionProfile *profile, const NAAction *action );
+void             na_action_profile_set_name( NAActionProfile *profile, const gchar *name );
 void             na_action_profile_set_label( NAActionProfile *profile, const gchar *label );
 void             na_action_profile_set_path( NAActionProfile *profile, const gchar *path );
 void             na_action_profile_set_parameters( NAActionProfile *profile, const gchar *parameters );
diff --git a/src/common/na-action.c b/src/common/na-action.c
index ff8df22..7be1555 100644
--- a/src/common/na-action.c
+++ b/src/common/na-action.c
@@ -32,6 +32,7 @@
 #include <config.h>
 #endif
 
+#include <glib/gi18n.h>
 #include <string.h>
 #include <uuid/uuid.h>
 
@@ -47,64 +48,70 @@ struct NAActionClassPrivate {
 /* private instance data
  */
 struct NAActionPrivate {
-	gboolean  dispose_has_run;
+	gboolean       dispose_has_run;
 
 	/* action properties
 	 */
-	gchar    *uuid;
-	gchar    *version;
-	gchar    *label;
-	gchar    *tooltip;
-	gchar    *icon;
+	gchar         *version;
+	gchar         *tooltip;
+	gchar         *icon;
 
 	/* list of action's profiles as NAActionProfile objects
 	 *  (thanks, Frederic ;-))
 	 */
-	GSList   *profiles;
+	GSList        *profiles;
 
 	/* dynamically set when reading the actions from the I/O storage
 	 * subsystem
 	 * defaults to FALSE unless a write has already returned an error
 	 */
-	gboolean  read_only;
+	gboolean       read_only;
 
 	/* the original provider
 	 * required to be able to edit/delete the action
 	 */
-	gpointer  provider;
+	NAIIOProvider *provider;
 };
 
-/* instance properties
- * please note that property names must have the same spelling as the
- * NactIIOProvider parameters
+/* action properties
  */
 enum {
-	PROP_ACTION_UUID = 1,
-	PROP_ACTION_VERSION,
-	PROP_ACTION_LABEL,
-	PROP_ACTION_TOOLTIP,
-	PROP_ACTION_ICON,
-	PROP_ACTION_READONLY,
-	PROP_ACTION_PROVIDER
+	PROP_NAACTION_UUID = 1,
+	PROP_NAACTION_LABEL,
+	PROP_NAACTION_VERSION,
+	PROP_NAACTION_TOOLTIP,
+	PROP_NAACTION_ICON,
+	PROP_NAACTION_READONLY,
+	PROP_NAACTION_PROVIDER
 };
 
-#define NA_ACTION_LATEST_VERSION	"2.0"
+#define PROP_NAACTION_UUID_STR			"na-action-uuid"
+#define PROP_NAACTION_LABEL_STR			"na-action-label"
+#define PROP_NAACTION_VERSION_STR		"na-action-version"
+#define PROP_NAACTION_TOOLTIP_STR		"na-action-tooltip"
+#define PROP_NAACTION_ICON_STR			"na-action-icon"
+#define PROP_NAACTION_READONLY_STR		"na-action-read-only"
+#define PROP_NAACTION_PROVIDER_STR		"na-action-provider"
+
+#define NA_ACTION_LATEST_VERSION		"2.0"
 
 static NAObjectClass *st_parent_class = NULL;
 
-static GType  register_type( void );
-static void   class_init( NAActionClass *klass );
-static void   instance_init( GTypeInstance *instance, gpointer klass );
-static void   instance_get_property( GObject *object, guint property_id, GValue *value, GParamSpec *spec );
-static void   instance_set_property( GObject *object, guint property_id, const GValue *value, GParamSpec *spec );
-static void   instance_dispose( GObject *object );
-static void   instance_finalize( GObject *object );
+static GType     register_type( void );
+static void      class_init( NAActionClass *klass );
+static void      instance_init( GTypeInstance *instance, gpointer klass );
+static void      instance_get_property( GObject *object, guint property_id, GValue *value, GParamSpec *spec );
+static void      instance_set_property( GObject *object, guint property_id, const GValue *value, GParamSpec *spec );
+static void      instance_dispose( GObject *object );
+static void      instance_finalize( GObject *object );
 
-static void   do_dump( const NAObject *action );
-static gchar *do_get_id( const NAObject *action );
-static gchar *do_get_label( const NAObject *action );
+static void      object_dump( const NAObject *action );
+static NAObject *object_duplicate( const NAObject *action );
+static void      object_copy( NAObject *target, const NAObject *source );
+static gboolean  object_are_equal( const NAObject *a, const NAObject *b );
+static gboolean  object_is_valid( const NAObject *action );
 
-static void   free_profiles( NAAction *action );
+static void      free_profiles( NAAction *action );
 
 GType
 na_action_get_type( void )
@@ -121,6 +128,9 @@ na_action_get_type( void )
 static GType
 register_type( void )
 {
+	static const gchar *thisfn = "na_action_register_type";
+	g_debug( "%s", thisfn );
+
 	static GTypeInfo info = {
 		sizeof( NAActionClass ),
 		( GBaseInitFunc ) NULL,
@@ -151,69 +161,69 @@ class_init( NAActionClass *klass )
 	object_class->get_property = instance_get_property;
 
 	GParamSpec *spec;
-
-	/* the id of the object is marked as G_PARAM_CONSTRUCT_ONLY */
 	spec = g_param_spec_string(
-			PROP_ACTION_UUID_STR,
-			PROP_ACTION_UUID_STR,
+			PROP_NAACTION_UUID_STR,
+			"Action UUID",
 			"Globally unique identifier (UUID) of the action", "",
 			G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE );
-	g_object_class_install_property( object_class, PROP_ACTION_UUID, spec );
+	g_object_class_install_property( object_class, PROP_NAACTION_UUID, spec );
 
 	spec = g_param_spec_string(
-			PROP_ACTION_VERSION_STR,
-			PROP_ACTION_VERSION_STR,
-			"Version of the schema", "",
+			PROP_NAACTION_LABEL_STR,
+			"Action label",
+			"Context menu displayable label", "",
 			G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE );
-	g_object_class_install_property( object_class, PROP_ACTION_VERSION, spec );
+	g_object_class_install_property( object_class, PROP_NAACTION_LABEL, spec );
 
 	spec = g_param_spec_string(
-			PROP_ACTION_LABEL_STR,
-			PROP_ACTION_LABEL_STR,
-			"Context menu displayable label", "",
+			PROP_NAACTION_VERSION_STR,
+			"Version",
+			"Version of the schema", "",
 			G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE );
-	g_object_class_install_property( object_class, PROP_ACTION_LABEL, spec );
+	g_object_class_install_property( object_class, PROP_NAACTION_VERSION, spec );
 
 	spec = g_param_spec_string(
-			PROP_ACTION_TOOLTIP_STR,
-			PROP_ACTION_TOOLTIP_STR,
+			PROP_NAACTION_TOOLTIP_STR,
+			"Action tooltip",
 			"Context menu tooltip", "",
 			G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE );
-	g_object_class_install_property( object_class, PROP_ACTION_TOOLTIP, spec );
+	g_object_class_install_property( object_class, PROP_NAACTION_TOOLTIP, spec );
 
 	spec = g_param_spec_string(
-			PROP_ACTION_ICON_STR,
-			PROP_ACTION_ICON_STR,
+			PROP_NAACTION_ICON_STR,
+			"Icon name",
 			"Context menu displayable icon", "",
 			G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE );
-	g_object_class_install_property( object_class, PROP_ACTION_ICON, spec );
+	g_object_class_install_property( object_class, PROP_NAACTION_ICON, spec );
 
 	spec = g_param_spec_boolean(
-			PROP_ACTION_READONLY_STR,
-			PROP_ACTION_READONLY_STR,
+			PROP_NAACTION_READONLY_STR,
+			"Read-only flag",
 			"Is this action only readable", FALSE,
 			G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE );
-	g_object_class_install_property( object_class, PROP_ACTION_READONLY, spec );
+	g_object_class_install_property( object_class, PROP_NAACTION_READONLY, spec );
 
 	spec = g_param_spec_pointer(
-			PROP_ACTION_PROVIDER_STR,
-			PROP_ACTION_PROVIDER_STR,
+			PROP_NAACTION_PROVIDER_STR,
+			"Original provider",
 			"Original provider",
 			G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE );
-	g_object_class_install_property( object_class, PROP_ACTION_PROVIDER, spec );
+	g_object_class_install_property( object_class, PROP_NAACTION_PROVIDER, spec );
 
 	klass->private = g_new0( NAActionClassPrivate, 1 );
 
-	NA_OBJECT_CLASS( klass )->dump = do_dump;
-	NA_OBJECT_CLASS( klass )->get_id = do_get_id;
-	NA_OBJECT_CLASS( klass )->get_label = do_get_label;
+	NA_OBJECT_CLASS( klass )->dump = object_dump;
+	NA_OBJECT_CLASS( klass )->duplicate = object_duplicate;
+	NA_OBJECT_CLASS( klass )->copy = object_copy;
+	NA_OBJECT_CLASS( klass )->are_equal = object_are_equal;
+	NA_OBJECT_CLASS( klass )->is_valid = object_is_valid;
 }
 
 static void
 instance_init( GTypeInstance *instance, gpointer klass )
 {
-	static const gchar *thisfn = "na_action_instance_init";
-	g_debug( "%s: instance=%p, klass=%p", thisfn, instance, klass );
+	/*static const gchar *thisfn = "na_action_instance_init";
+	g_debug( "%s: instance=%p, klass=%p", thisfn, instance, klass );*/
 
 	g_assert( NA_IS_ACTION( instance ));
 	NAAction* self = NA_ACTION( instance );
@@ -225,7 +235,6 @@ instance_init( GTypeInstance *instance, gpointer klass )
 	/* initialize suitable default values
 	 */
 	self->private->version = g_strdup( NA_ACTION_LATEST_VERSION );
-	self->private->label = g_strdup( "" );
 	self->private->tooltip = g_strdup( "" );
 	self->private->icon = g_strdup( "" );
 	self->private->read_only = FALSE;
@@ -239,31 +248,31 @@ instance_get_property( GObject *object, guint property_id, GValue *value, GParam
 	NAAction *self = NA_ACTION( object );
 
 	switch( property_id ){
-		case PROP_ACTION_UUID:
-			g_value_set_string( value, self->private->uuid );
+		case PROP_NAACTION_UUID:
+			G_OBJECT_CLASS( st_parent_class )->get_property( object, PROP_NAOBJECT_ID, value, spec );
 			break;
 
-		case PROP_ACTION_VERSION:
-			g_value_set_string( value, self->private->version );
+		case PROP_NAACTION_LABEL:
+			G_OBJECT_CLASS( st_parent_class )->get_property( object, PROP_NAOBJECT_LABEL, value, spec );
 			break;
 
-		case PROP_ACTION_LABEL:
-			g_value_set_string( value, self->private->label );
+		case PROP_NAACTION_VERSION:
+			g_value_set_string( value, self->private->version );
 			break;
 
-		case PROP_ACTION_TOOLTIP:
+		case PROP_NAACTION_TOOLTIP:
 			g_value_set_string( value, self->private->tooltip );
 			break;
 
-		case PROP_ACTION_ICON:
+		case PROP_NAACTION_ICON:
 			g_value_set_string( value, self->private->icon );
 			break;
 
-		case PROP_ACTION_READONLY:
+		case PROP_NAACTION_READONLY:
 			g_value_set_boolean( value, self->private->read_only );
 			break;
 
-		case PROP_ACTION_PROVIDER:
+		case PROP_NAACTION_PROVIDER:
 			g_value_set_pointer( value, self->private->provider );
 			break;
 
@@ -280,36 +289,34 @@ instance_set_property( GObject *object, guint property_id, const GValue *value,
 	NAAction *self = NA_ACTION( object );
 
 	switch( property_id ){
-		case PROP_ACTION_UUID:
-			g_free( self->private->uuid );
-			self->private->uuid = g_value_dup_string( value );
+		case PROP_NAACTION_UUID:
+			G_OBJECT_CLASS( st_parent_class )->set_property( object, PROP_NAOBJECT_ID, value, spec );
 			break;
 
-		case PROP_ACTION_VERSION:
-			g_free( self->private->version );
-			self->private->version = g_value_dup_string( value );
+		case PROP_NAACTION_LABEL:
+			G_OBJECT_CLASS( st_parent_class )->set_property( object, PROP_NAOBJECT_LABEL, value, spec );
 			break;
 
-		case PROP_ACTION_LABEL:
-			g_free( self->private->label );
-			self->private->label = g_value_dup_string( value );
+		case PROP_NAACTION_VERSION:
+			g_free( self->private->version );
+			self->private->version = g_value_dup_string( value );
 			break;
 
-		case PROP_ACTION_TOOLTIP:
+		case PROP_NAACTION_TOOLTIP:
 			g_free( self->private->tooltip );
 			self->private->tooltip = g_value_dup_string( value );
 			break;
 
-		case PROP_ACTION_ICON:
+		case PROP_NAACTION_ICON:
 			g_free( self->private->icon );
 			self->private->icon = g_value_dup_string( value );
 			break;
 
-		case PROP_ACTION_READONLY:
+		case PROP_NAACTION_READONLY:
 			self->private->read_only = g_value_get_boolean( value );
 			break;
 
-		case PROP_ACTION_PROVIDER:
+		case PROP_NAACTION_PROVIDER:
 			self->private->provider = g_value_get_pointer( value );
 			break;
 
@@ -349,9 +356,7 @@ instance_finalize( GObject *object )
 	g_assert( NA_IS_ACTION( object ));
 	NAAction *self = ( NAAction * ) object;
 
-	g_free( self->private->uuid );
 	g_free( self->private->version );
-	g_free( self->private->label );
 	g_free( self->private->tooltip );
 	g_free( self->private->icon );
 
@@ -364,187 +369,123 @@ instance_finalize( GObject *object )
 }
 
 /**
- * Allocates a new NAAction object.
+ * na_action_new:
  *
- * @uuid: the globally unique identifier (UUID) of the action.
- * If NULL, a new UUID is allocated for this action.
+ * Allocates a new #NAAction object.
  *
- * Return a newly allocated NAAction object.
- */
-NAAction *
-na_action_new( const gchar *uuid )
-{
-	NAAction *action = g_object_new( NA_ACTION_TYPE, PROP_ACTION_UUID_STR, uuid, NULL );
-
-	if( !uuid || !strlen( uuid )){
-		na_action_set_new_uuid( action );
-	}
-
-	return( action );
-}
-
-/**
- * Allocates a new NAAction object along with a default profile.
+ * The new #NAAction object is initialized with suitable default values,
+ * but without any profile.
  *
- * Return a newly allocated NAAction object.
+ * Returns: the newly allocated #NAAction object.
  */
 NAAction *
-na_action_new_with_profile( void )
+na_action_new( void )
 {
-	NAAction *action = na_action_new( NULL );
+	NAAction *action = g_object_new( NA_ACTION_TYPE, NULL );
 
-	NAActionProfile *profile = na_action_profile_new( NA_OBJECT( action ), ACTION_PROFILE_PREFIX "zero" );
+	na_action_set_new_uuid( action );
 
-	action->private->profiles = g_slist_prepend( action->private->profiles, profile );
+	/* i18n: default label for a new action */
+	na_action_set_label( action, _( "New Nautilus action" ));
 
 	return( action );
 }
 
 /**
- * Allocates a new NAAction object, and initializes it as an exact
- * copy of the specified action.
- *
- * @action: the action to be duplicated.
+ * na_action_new_with_profile:
  *
- * Return a newly allocated NAAction object.
+ * Allocates a new #NAAction object along with a default profile.
  *
- * Please note than "an exact copy" here means that the newly allocated
- * returned object has the _same_ UUID than the original one.
+ * Return: the newly allocated #NAAction action.
  */
 NAAction *
-na_action_duplicate( const NAAction *action )
-{
-	g_assert( NA_IS_ACTION( action ));
-
-	gchar *uuid = do_get_id( NA_OBJECT( action ));
-	NAAction *duplicate = g_object_new( NA_ACTION_TYPE, PROP_ACTION_UUID_STR, uuid, NULL );
-	g_free( uuid );
-
-	duplicate->private->version = g_strdup( action->private->version );
-	duplicate->private->label = g_strdup( action->private->label );
-	duplicate->private->tooltip = g_strdup( action->private->tooltip );
-	duplicate->private->icon = g_strdup( action->private->icon );
-	duplicate->private->read_only = action->private->read_only;
-	duplicate->private->provider = action->private->provider;
-
-	GSList *ip;
-	for( ip = action->private->profiles ; ip ; ip = ip->next ){
-		duplicate->private->profiles =
-			g_slist_prepend(
-					duplicate->private->profiles,
-					na_action_profile_duplicate( duplicate, NA_ACTION_PROFILE( ip->data )));
-	}
-
-	return( duplicate );
-}
-
-static void
-do_dump( const NAObject *action )
+na_action_new_with_profile( void )
 {
-	static const gchar *thisfn = "na_action_do_dump";
-
-	g_assert( NA_IS_ACTION( action ));
-	NAAction *self = NA_ACTION( action );
-
-	if( st_parent_class->dump ){
-		st_parent_class->dump( action );
-	}
-
-	g_debug( "%s:      uuid='%s'", thisfn, self->private->uuid );
-	g_debug( "%s:   version='%s'", thisfn, self->private->version );
-	g_debug( "%s:     label='%s'", thisfn, self->private->label );
-	g_debug( "%s:   tooltip='%s'", thisfn, self->private->tooltip );
-	g_debug( "%s:      icon='%s'", thisfn, self->private->icon );
-	g_debug( "%s: read-only='%s'", thisfn, self->private->read_only ? "True" : "False" );
-	g_debug( "%s:  provider=%p", thisfn, self->private->provider );
-
-	/* dump profiles */
-	g_debug( "%s: %d profile(s) at %p", thisfn, na_action_get_profiles_count( self ), self->private->profiles );
-	GSList *item;
-	for( item = self->private->profiles ;	item != NULL ; item = item->next ){
-		na_object_dump(( const NAObject * ) item->data );
-	}
-}
+	NAAction *action = na_action_new();
 
-static gchar *
-do_get_id( const NAObject *action )
-{
-	g_assert( NA_IS_ACTION( action ));
+	NAActionProfile *profile = na_action_profile_new();
 
-	gchar *uuid;
-	g_object_get( G_OBJECT( action ), PROP_ACTION_UUID_STR, &uuid, NULL );
+	na_action_attach_profile( action, profile );
 
-	return( uuid );
+	return( action );
 }
 
 /**
+ * na_action_get_uuid:
+ * @action: the #NAAction object to be requested.
+ *
  * Returns the globally unique identifier (UUID) of the action.
  *
- * @action: an NAAction object.
+ * Returns: the uuid of the action as a newly allocated string. This
+ * returned string must be g_free() by the caller.
  *
- * The returned string must be g_freed by the caller.
+ * See na_action_set_uuid() for some rationale about uuid.
  */
 gchar *
 na_action_get_uuid( const NAAction *action )
 {
 	g_assert( NA_IS_ACTION( action ));
-	return( na_object_get_id( NA_OBJECT( action )));
+
+	gchar *id;
+	g_object_get( G_OBJECT( action ), PROP_NAACTION_UUID_STR, &id, NULL );
+
+	return( id );
 }
 
 /**
- * Returns the version attached to the action.
+ * na_action_get_label:
+ * @action: the #NAAction object to be requested.
  *
- * @action: an NAAction object.
+ * Returns the label of the action.
  *
- * The returned string must be g_freed by the caller.
+ * Returns: the label of the action as a newly allocated string. This
+ * returned string must be g_free() by the caller.
  *
- * The version is always upgraded to the latest when the action is
- * readen from the I/O provider. So we could assert here that the
- * returned version is also the latest.
+ * See na_action_set_label() for some rationale about label.
  */
 gchar *
-na_action_get_version( const NAAction *action )
-{
-	g_assert( NA_IS_ACTION( action ));
-
-	gchar *version;
-	g_object_get( G_OBJECT( action ), PROP_ACTION_VERSION_STR, &version, NULL );
-
-	return( version );
-}
-
-static gchar *
-do_get_label( const NAObject *action )
+na_action_get_label( const NAAction *action )
 {
 	g_assert( NA_IS_ACTION( action ));
 
 	gchar *label;
-	g_object_get( G_OBJECT( action ), PROP_ACTION_LABEL_STR, &label, NULL );
+	g_object_get( G_OBJECT( action ), PROP_NAACTION_LABEL_STR, &label, NULL );
 
 	return( label );
 }
 
 /**
- * Returns the label of the action.
+ * na_action_get_version:
+ * @action: the #NAAction object to be requested.
  *
- * @action: an NAAction object.
+ * Returns the version of the description of the action, as found when
+ * reading it from the I/O storage subsystem.
  *
- * The returned string must be g_freed by the caller.
+ * Returns: the version of the action as a newly allocated string. This
+ * returned string must be g_free() by the caller.
+ *
+ * See na_action_set_version() for some rationale about version.
  */
 gchar *
-na_action_get_label( const NAAction *action )
+na_action_get_version( const NAAction *action )
 {
 	g_assert( NA_IS_ACTION( action ));
-	return( na_object_get_label( NA_OBJECT( action )));
+
+	gchar *version;
+	g_object_get( G_OBJECT( action ), PROP_NAACTION_VERSION_STR, &version, NULL );
+
+	return( version );
 }
 
 /**
- * Returns the tooltip attached to the context menu item for the
- * action.
+ * na_action_get_tooltip:
+ * @action: the #NAAction object to be requested.
  *
- * @action: an NAAction object.
+ * Returns the tooltip which will be display in the Nautilus context
+ * menu item for this action.
  *
- * The returned string must be g_freed by the caller.
+ * Returns: the tooltip of the action as a newly allocated string. This
+ * returned string must be g_free() by the caller.
  */
 gchar *
 na_action_get_tooltip( const NAAction *action )
@@ -552,18 +493,20 @@ na_action_get_tooltip( const NAAction *action )
 	g_assert( NA_IS_ACTION( action ));
 
 	gchar *tooltip;
-	g_object_get( G_OBJECT( action ), PROP_ACTION_TOOLTIP_STR, &tooltip, NULL );
+	g_object_get( G_OBJECT( action ), PROP_NAACTION_TOOLTIP_STR, &tooltip, NULL );
 
 	return( tooltip );
 }
 
 /**
- * Returns the name of the icon attached to the context menu item for
- * the action.
+ * na_action_get_icon:
+ * @action: the #NAAction object to be requested.
  *
- * @action: an NAAction object.
+ * Returns the name of the icon attached to the Nautilus context menu
+ * item for this action.
  *
- * The returned string must be g_freed by the caller.
+ * Returns: the icon name as a newly allocated string. This returned
+ * string must be g_free() by the caller.
  */
 gchar *
 na_action_get_icon( const NAAction *action )
@@ -571,18 +514,13 @@ na_action_get_icon( const NAAction *action )
 	g_assert( NA_IS_ACTION( action ));
 
 	gchar *icon;
-	g_object_get( G_OBJECT( action ), PROP_ACTION_ICON_STR, &icon, NULL );
+	g_object_get( G_OBJECT( action ), PROP_NAACTION_ICON_STR, &icon, NULL );
 
 	return( icon );
 }
 
-/**
- * Returns the icon name attached to the context menu item for the
- * action.
- *
- * @action: an NAAction object.
- *
- * When not NULL, the returned string must be g_free by the caller.
+/*
+ * TODO: remove this function
  */
 gchar *
 na_action_get_verified_icon_name( const NAAction *action )
@@ -590,7 +528,7 @@ na_action_get_verified_icon_name( const NAAction *action )
 	g_assert( NA_IS_ACTION( action ));
 
 	gchar *icon_name;
-	g_object_get( G_OBJECT( action ), PROP_ACTION_ICON_STR, &icon_name, NULL );
+	g_object_get( G_OBJECT( action ), PROP_NAACTION_ICON_STR, &icon_name, NULL );
 
 	if( icon_name[0] == '/' ){
 		if( !g_file_test( icon_name, G_FILE_TEST_IS_REGULAR )){
@@ -606,35 +544,55 @@ na_action_get_verified_icon_name( const NAAction *action )
 }
 
 /**
+ * na_action_is_readonly:
+ * @action: the #NAAction object to be requested.
+ *
  * Is the specified action only readable ?
- * Or, in other words, may this action be edited and then saved ?
+ * Or, in other words, may this action be edited and then saved to the
+ * original I/O storage subsystem ?
  *
- * @action: an NAAction object.
+ * Returns: %TRUE if the action is editable, %FALSE else.
  */
 gboolean
 na_action_is_readonly( const NAAction *action )
 {
 	g_assert( NA_IS_ACTION( action ));
-	return( action->private->read_only );
+
+	gboolean readonly;
+	g_object_get( G_OBJECT( action ), PROP_NAACTION_READONLY_STR, &readonly, NULL );
+
+	return( readonly );
 }
 
 /**
+ * na_action_get_provider:
+ * @action: the #NAAction object to be requested.
+ *
  * Returns the initial provider of the action (or the last which has
- * accepted a write).
+ * accepted a write operation). At the time of this request, this is
+ * the most probable provider willing to accept a next writing
+ * operation.
  *
- * @action: an NAAction object.
+ * Returns: a #NAIIOProvider object. The reference is
+ * owned by #NAPivot pivot and should be g_object_unref() by the
+ * caller.
  */
-gpointer
+NAIIOProvider *
 na_action_get_provider( const NAAction *action )
 {
 	g_assert( NA_IS_ACTION( action ));
-	return( action->private->provider );
+
+	NAIIOProvider *provider;
+	g_object_get( G_OBJECT( action ), PROP_NAACTION_PROVIDER_STR, &provider, NULL );
+
+	return( provider );
 }
 
 /**
- * Set a new UUID for the action.
+ * na_action_set_new_uuid:
+ * @action: the #NAAction object to be updated.
  *
- * @action: action whose UUID is to be set.
+ * Set a new UUID for the action.
  */
 void
 na_action_set_new_uuid( NAAction *action )
@@ -646,134 +604,167 @@ na_action_set_new_uuid( NAAction *action )
 	uuid_generate( uuid );
 	uuid_unparse_lower( uuid, uuid_str );
 
-	g_object_set( G_OBJECT( action ), PROP_ACTION_UUID_STR, uuid_str, NULL );
+	g_object_set( G_OBJECT( action ), PROP_NAACTION_UUID_STR, uuid_str, NULL );
 }
 
 /**
- * Set a new uuid for the action.
+ * na_action_set_uuid:
+ * @action: the #NAAction object to be updated.
+ * @uuid: the uuid to be set.
+ *
+ * Sets a new uuid for the action.
+ *
+ * #NAAction takes a copy of the provided UUID. This later may so be
+ * g_free() by the caller after this function returns.
+ *
+ * This uuid is only required when writing the action to GConf in order
+ * easily have unique subdirectories.
  *
- * @action: action whose uuid is to be set.
+ * This is an ASCII, case insensitive, string.
  *
- * @uuid: new uuid.
+ * UUID is transfered through import/export operations.
+ *
+ * Note that a user may import an action, translate it and then
+ * reexport it : we so may have two different actions with the same
+ * uuid.
  */
 void
 na_action_set_uuid( NAAction *action, const gchar *uuid )
 {
 	g_assert( NA_IS_ACTION( action ));
-	g_object_set( G_OBJECT( action ), PROP_ACTION_UUID_STR, uuid, NULL );
+
+	g_object_set( G_OBJECT( action ), PROP_NAACTION_UUID_STR, uuid, NULL );
 }
 
 /**
- * Set a new version for the action.
+ * na_action_set_label:
+ * @action: the #NAAction object to be updated.
+ * @label: the label to be set.
+ *
+ * Sets a new label for the action.
  *
- * @action: action whose version is to be set.
+ * #NAAction takes a copy of the provided label. This later may so be
+ * g_free() by the caller after this function returns.
  *
- * @version: new version.
+ * The user knows its actions through their labels, as this is the main
+ * visible part (with the icon) in Nautilus context menu and in the
+ * NACT ui.
  */
 void
-na_action_set_version( NAAction *action, const gchar *version )
+na_action_set_label( NAAction *action, const gchar *label )
 {
 	g_assert( NA_IS_ACTION( action ));
-	g_object_set( G_OBJECT( action ), PROP_ACTION_VERSION_STR, version, NULL );
+
+	g_object_set( G_OBJECT( action ), PROP_NAACTION_LABEL_STR, label, NULL );
 }
 
 /**
- * Set a new label for the action.
+ * na_action_set_version:
+ * @action: the #NAAction object to be updated.
+ * @label: the label to be set.
+ *
+ * Sets a new version for the action.
  *
- * @action: action whose label is to be set.
+ * #NAAction takes a copy of the provided version. This later may so be
+ * g_free() by the caller after this function returns.
  *
- * @label: new label.
+ * The version describes the schema of the informations in the I/O
+ * storage subsystem.
+ *
+ * Version is stored in the #NAAction object as readen from the I/O
+ * storage subsystem, even if the #NAAction object itself only reflects
+ * the lastest known version. Conversion is made at load time (cf.
+ * na_gconf_load_action()).
  */
 void
-na_action_set_label( NAAction *action, const gchar *label )
+na_action_set_version( NAAction *action, const gchar *version )
 {
 	g_assert( NA_IS_ACTION( action ));
-	g_object_set( G_OBJECT( action ), PROP_ACTION_LABEL_STR, label, NULL );
+
+	g_object_set( G_OBJECT( action ), PROP_NAACTION_VERSION_STR, version, NULL );
 }
 
 /**
- * Set a new tooltip for the action.
+ * na_action_set_tooltip:
+ * @action: the #NAAction object to be updated.
+ * @tooltip: the tooltip to be set.
  *
- * @action: action whose tooltip is to be set.
+ * Sets a new tooltip for the action. Tooltip will be displayed by
+ * Nautilus when the user move its mouse over the Nautilus context menu
+ * item.
  *
- * @tooltip: new tooltip.
+ * #NAAction takes a copy of the provided tooltip. This later may so be
+ * g_free() by the caller after this function returns.
  */
 void
 na_action_set_tooltip( NAAction *action, const gchar *tooltip )
 {
 	g_assert( NA_IS_ACTION( action ));
-	g_object_set( G_OBJECT( action ), PROP_ACTION_TOOLTIP_STR, tooltip, NULL );
+
+	g_object_set( G_OBJECT( action ), PROP_NAACTION_TOOLTIP_STR, tooltip, NULL );
 }
 
 /**
- * Set a new icon for the action.
+ * na_action_set_icon:
+ * @action: the #NAAction object to be updated.
+ * @icon: the icon name to be set.
  *
- * @action: action whose icon name is to be set.
+ * Sets a new icon name for the action.
  *
- * @icon: new icon name.
+ * #NAAction takes a copy of the provided icon name. This later may so
+ * be g_free() by the caller after this function returns.
  */
 void
 na_action_set_icon( NAAction *action, const gchar *icon )
 {
 	g_assert( NA_IS_ACTION( action ));
-	g_object_set( G_OBJECT( action ), PROP_ACTION_ICON_STR, icon, NULL );
+
+	g_object_set( G_OBJECT( action ), PROP_NAACTION_ICON_STR, icon, NULL );
 }
 
 /**
- * Are the two actions the sames (excluding UUID) ?
+ * na_action_set_readonly:
+ * @action: the #NAAction object to be updated.
+ * @readonly: the indicator to be set.
  *
- * @first: first action to check.
+ * Sets whether the action is readonly.
+ */
+void
+na_action_set_readonly( NAAction *action, gboolean readonly )
+{
+	g_assert( NA_IS_ACTION( action ));
+
+	g_object_set( G_OBJECT( action ), PROP_NAACTION_READONLY_STR, readonly, NULL );
+}
+
+/**
+ * na_action_set_provider:
+ * @action: the #NAAction object to be updated.
+ * @provider: the #NAIIOProvider to be set.
  *
- * @second: second action to be compared to @first.
+ * Sets the I/O provider for this #NAAction.
  */
-gboolean
-na_action_are_equal( const NAAction *first, const NAAction *second )
+void
+na_action_set_provider( NAAction *action, const NAIIOProvider *provider )
 {
-	gboolean equal =
-		( g_utf8_collate( first->private->label, second->private->label ) == 0 ) &&
-		( g_utf8_collate( first->private->tooltip, second->private->tooltip ) == 0 ) &&
-		( g_utf8_collate( first->private->icon, second->private->icon ) == 0 );
+	g_assert( NA_IS_ACTION( action ));
 
-	if( equal ){
-		equal = ( g_slist_length( first->private->profiles ) == g_slist_length( second->private->profiles ));
-	}
-	if( equal ){
-		GSList *ip;
-		for( ip = first->private->profiles ; ip && equal ; ip = ip->next ){
-			NAActionProfile *first_profile = NA_ACTION_PROFILE( ip->data );
-			gchar *first_name = na_action_profile_get_name( first_profile );
-			NAActionProfile *second_profile = NA_ACTION_PROFILE( na_action_get_profile( second, first_name ));
-			if( second_profile ){
-				equal = na_action_profile_are_equal( first_profile, second_profile );
-			} else {
-				equal = FALSE;
-			}
-			g_free( first_name );
-		}
-	}
-	if( equal ){
-		GSList *ip;
-		for( ip = second->private->profiles ; ip && equal ; ip = ip->next ){
-			NAActionProfile *second_profile = NA_ACTION_PROFILE( ip->data );
-			gchar *second_name = na_action_profile_get_name( second_profile );
-			NAActionProfile *first_profile = NA_ACTION_PROFILE( na_action_get_profile( first, second_name ));
-			if( first_profile ){
-				equal = na_action_profile_are_equal( first_profile, second_profile );
-			} else {
-				equal = FALSE;
-			}
-			g_free( second_name );
-		}
-	}
-	return( equal );
+	g_object_set( G_OBJECT( action ), PROP_NAACTION_PROVIDER_STR, provider, NULL );
 }
 
 /**
+ * na_action_get_new_profile_name:
+ * @action: the #NAAction object which will receive a new profile.
+ *
  * Returns a name suitable as a new profile name.
  *
- * @action: the action for which we are searching a new profile name.
+ * The search is made by iterating over the standard profile name
+ * prefix : basically, we increment a counter until finding a unique
+ * name. The provided name is so only suitable for the specified
+ * @action.
  *
- * Basically, we increment a counter until finding a unique name.
+ * Returns: a newly allocated profile name, which should be g_free() by
+ * the caller.
  */
 gchar *
 na_action_get_new_profile_name( const NAAction *action )
@@ -798,27 +789,30 @@ na_action_get_new_profile_name( const NAAction *action )
 }
 
 /**
- * Returns the profile with the required name.
+ * na_action_get_profile:
+ * @action: the #NAAction object which is to be requested.
+ * @name: the name of the searched profile.
  *
- * @action: the action whose profiles has to be retrieved.
+ * Returns the required profile.
  *
- * @name: name of the required profile.
+ * Returns: a pointer to the #NAActionProfile profile with the required
+ * name.
  *
- * The returned pointer is owned by the @action object ; the caller
- * should not try to free or unref it.
+ * The returned #NAActionProfile is owned by the @action object ; the
+ * caller should not try to g_free() nor g_object_unref() it.
  */
-NAObject *
+NAActionProfile *
 na_action_get_profile( const NAAction *action, const gchar *name )
 {
 	g_assert( NA_IS_ACTION( action ));
-	NAObject *found = NULL;
+	NAActionProfile *found = NULL;
 	GSList *ip;
 
 	for( ip = action->private->profiles ; ip && !found ; ip = ip->next ){
 		NAActionProfile *iprofile = NA_ACTION_PROFILE( ip->data );
 		gchar *iname = na_action_profile_get_name( iprofile );
 		if( !strcmp( name, iname )){
-			found = NA_OBJECT( iprofile );
+			found = iprofile;
 		}
 		g_free( iname );
 	}
@@ -827,29 +821,48 @@ na_action_get_profile( const NAAction *action, const gchar *name )
 }
 
 /**
- * Add a profile at the end of the list of profiles.
+ * na_action_attach_profile:
+ * @action: the #NAAction action to which the profile will be attached.
+ * @profile: the #NAActionProfile profile to be attached to @action.
  *
- * @action: the action.
+ * Adds a profile at the end of the list of profiles.
+ */
+void
+na_action_attach_profile( NAAction *action, NAActionProfile *profile )
+{
+	g_assert( NA_IS_ACTION( action ));
+	g_assert( NA_IS_ACTION_PROFILE( profile ));
+
+	action->private->profiles = g_slist_append( action->private->profiles, ( gpointer ) profile );
+
+	na_action_profile_set_action( profile, action );
+}
+
+/**
+ * na_action_remove_profile:
+ * @action: the #NAAction action from which the profile will be removed.
+ * @profile: the #NAActionProfile profile to be removed from @action.
  *
- * @profile: the added profile.
+ * Removes a profile from the list of profiles.
  */
 void
-na_action_add_profile( NAAction *action, NAObject *profile )
+na_action_remove_profile( NAAction *action, NAActionProfile *profile )
 {
 	g_assert( NA_IS_ACTION( action ));
 	g_assert( NA_IS_ACTION_PROFILE( profile ));
 
-	action->private->profiles = g_slist_append( action->private->profiles, profile );
+	action->private->profiles = g_slist_remove( action->private->profiles, ( gconstpointer ) profile );
 }
 
 /**
- * Returns the list of profiles of the actions as a GSList of
- * NAActionProfile GObjects.
+ * na_action_get_profiles:
+ * @action: the #NAAction action whose profiles has to be retrieved.
  *
- * @action: the action whose profiles has to be retrieved.
+ * Returns the list of profiles of the action.
  *
- * The returned pointer is owned by the @action object ; the caller
- * should not try to free or unref it.
+ * Returns: a #GSList of #NAActionProfile objects. The returned pointer
+ * is owned by the @action object ; the caller should not try to
+ * g_free() nor g_object_unref() it.
  */
 GSList *
 na_action_get_profiles( const NAAction *action )
@@ -860,15 +873,16 @@ na_action_get_profiles( const NAAction *action )
 }
 
 /**
- * Set the list of the profiles for the action.
+ * na_action_set_profiles:
+ * @action: the #NAAction action whose profiles has to be set.
+ * @list: a #GSList list of #NAActionProfile objects to be installed in
+ * the @action.
  *
- * @action: the action whose profiles has to be retrieved.
+ * Sets the list of the profiles for the action.
  *
- * @list: a list of NAActionProfile objects to be installed in the
- * action.
- *
- * The provided list is copied to the action, and thus can then be
- * safely freed (see na_action_free_profiles) by the caller.
+ * The provided list removes and replaces the previous profiles list.
+ * This list is then copied to the action, and thus can then be safely
+ * na_action_free_profiles() by the caller.
  */
 void
 na_action_set_profiles( NAAction *action, GSList *list )
@@ -876,19 +890,37 @@ na_action_set_profiles( NAAction *action, GSList *list )
 	g_assert( NA_IS_ACTION( action ));
 
 	free_profiles( action );
+
+	GSList *ip;
+	for( ip = list ; ip ; ip = ip->next ){
+		NAObject *new_profile = na_object_duplicate( NA_OBJECT( ip->data ));
+		na_action_attach_profile( action, NA_ACTION_PROFILE( new_profile ));
+	}
+}
+
+/**
+ * na_action_free_profiles:
+ * @list: a #GSList list of #NAActionProfile objects.
+ *
+ * Frees a profiles list.
+ */
+void
+na_action_free_profiles( GSList *list )
+{
 	GSList *ip;
 	for( ip = list ; ip ; ip = ip->next ){
-		action->private->profiles = g_slist_prepend(
-							action->private->profiles,
-							na_action_profile_duplicate( action, NA_ACTION_PROFILE( ip->data ))
-		);
+		g_object_unref( NA_ACTION_PROFILE( ip->data ));
 	}
+	g_slist_free( list );
 }
 
 /**
+ * na_action_get_profiles_count:
+ * @action: the #NAAction action whose profiles has to be counted.
+ *
  * Returns the number of profiles which are defined for the action.
  *
- * @action: the action whose profiles has to be retrieved.
+ * Returns: the number of profiles defined for @action.
  */
 guint
 na_action_get_profiles_count( const NAAction *action )
@@ -899,26 +931,165 @@ na_action_get_profiles_count( const NAAction *action )
 }
 
 static void
-free_profiles( NAAction *action )
+object_dump( const NAObject *action )
 {
+	static const gchar *thisfn = "na_action_object_dump";
+
 	g_assert( NA_IS_ACTION( action ));
+	NAAction *self = NA_ACTION( action );
 
-	na_action_free_profiles( action->private->profiles );
+	if( st_parent_class->dump ){
+		st_parent_class->dump( action );
+	}
 
-	action->private->profiles = NULL;
+	g_debug( "%s:   version='%s'", thisfn, self->private->version );
+	g_debug( "%s:   tooltip='%s'", thisfn, self->private->tooltip );
+	g_debug( "%s:      icon='%s'", thisfn, self->private->icon );
+	g_debug( "%s: read-only='%s'", thisfn, self->private->read_only ? "True" : "False" );
+	g_debug( "%s:  provider=%p", thisfn, self->private->provider );
+
+	/* dump profiles */
+	g_debug( "%s: %d profile(s) at %p", thisfn, na_action_get_profiles_count( self ), self->private->profiles );
+	GSList *item;
+	for( item = self->private->profiles ;	item != NULL ; item = item->next ){
+		na_object_dump(( const NAObject * ) item->data );
+	}
+}
+
+static NAObject *
+object_duplicate( const NAObject *action )
+{
+	g_assert( NA_IS_ACTION( action ));
+
+	NAObject *duplicate = NA_OBJECT( na_action_new());
+
+	na_object_copy( duplicate, action );
+
+	return( duplicate );
 }
 
-/**
- * Frees a profiles list.
- *
- * @list: a list of NAActionProfile objects.
- */
 void
-na_action_free_profiles( GSList *list )
+object_copy( NAObject *target, const NAObject *source )
 {
+	g_assert( NA_IS_ACTION( source ));
+	g_assert( NA_IS_ACTION( target ));
+
+	gchar *version, *tooltip, *icon;
+	gboolean readonly;
+	gpointer provider;
+
+	g_object_get( G_OBJECT( source ),
+			PROP_NAACTION_VERSION_STR, &version,
+			PROP_NAACTION_TOOLTIP_STR, &tooltip,
+			PROP_NAACTION_ICON_STR, &icon,
+			PROP_NAACTION_READONLY_STR, &readonly,
+			PROP_NAACTION_PROVIDER_STR, &provider,
+			NULL );
+
+	g_object_set( G_OBJECT( target ),
+			PROP_NAACTION_VERSION_STR, version,
+			PROP_NAACTION_TOOLTIP_STR, tooltip,
+			PROP_NAACTION_ICON_STR, icon,
+			PROP_NAACTION_READONLY_STR, readonly,
+			PROP_NAACTION_PROVIDER_STR, provider,
+			NULL );
+
+	g_free( tooltip );
+	g_free( version );
+
 	GSList *ip;
-	for( ip = list ; ip ; ip = ip->next ){
-		g_object_unref( NA_ACTION_PROFILE( ip->data ));
+	for( ip = NA_ACTION( source )->private->profiles ; ip ; ip = ip->next ){
+		NAActionProfile *profile = NA_ACTION_PROFILE( na_object_duplicate( NA_OBJECT( ip->data )));
+		na_action_attach_profile( NA_ACTION( target ), profile );
 	}
-	g_slist_free( list );
+
+	if( st_parent_class->copy ){
+		st_parent_class->copy( target, source );
+	}
+}
+
+static gboolean
+object_are_equal( const NAObject *a, const NAObject *b )
+{
+	g_assert( NA_IS_ACTION( a ));
+	g_assert( NA_IS_ACTION( b ));
+
+	NAAction *first = NA_ACTION( a );
+	NAAction *second = NA_ACTION( b );
+
+	gboolean equal =
+		( g_utf8_collate( first->private->version, second->private->version ) == 0 ) &&
+		( g_utf8_collate( first->private->tooltip, second->private->tooltip ) == 0 ) &&
+		( g_utf8_collate( first->private->icon, second->private->icon ) == 0 );
+
+	if( equal ){
+		equal = ( g_slist_length( first->private->profiles ) == g_slist_length( second->private->profiles ));
+	}
+	if( equal ){
+		GSList *ip;
+		for( ip = first->private->profiles ; ip && equal ; ip = ip->next ){
+			NAActionProfile *first_profile = NA_ACTION_PROFILE( ip->data );
+			gchar *first_name = na_action_profile_get_name( first_profile );
+			NAActionProfile *second_profile = NA_ACTION_PROFILE( na_action_get_profile( second, first_name ));
+			if( second_profile ){
+				equal = na_object_are_equal( NA_OBJECT( first_profile ), NA_OBJECT( second_profile ));
+			} else {
+				equal = FALSE;
+			}
+			g_free( first_name );
+		}
+	}
+	if( equal ){
+		GSList *ip;
+		for( ip = second->private->profiles ; ip && equal ; ip = ip->next ){
+			NAActionProfile *second_profile = NA_ACTION_PROFILE( ip->data );
+			gchar *second_name = na_action_profile_get_name( second_profile );
+			NAActionProfile *first_profile = NA_ACTION_PROFILE( na_action_get_profile( first, second_name ));
+			if( first_profile ){
+				equal = na_object_are_equal( NA_OBJECT( first_profile ), NA_OBJECT( second_profile ));
+			} else {
+				equal = FALSE;
+			}
+			g_free( second_name );
+		}
+	}
+	if( equal ){
+		if( st_parent_class->are_equal ){
+			equal = st_parent_class->are_equal( a, b );
+		}
+	}
+
+	return( equal );
+}
+
+gboolean
+object_is_valid( const NAObject *action )
+{
+	g_assert( NA_IS_ACTION( action ));
+
+	gchar *label;
+	g_object_get( G_OBJECT( action ), PROP_NAACTION_LABEL_STR, &label, NULL );
+	gboolean is_valid = ( label && g_utf8_strlen( label, -1 ) > 0 );
+	g_free( label );
+
+	GSList *ip;
+	for( ip = NA_ACTION( action )->private->profiles ; ip && is_valid ; ip = ip->next ){
+		is_valid = na_object_is_valid( NA_OBJECT( ip->data ));
+	}
+
+	if( is_valid ){
+		if( st_parent_class->is_valid ){
+			is_valid = st_parent_class->is_valid( action );
+		}
+	}
+
+	return( is_valid );
+}
+
+static void
+free_profiles( NAAction *action )
+{
+	na_action_free_profiles( action->private->profiles );
+
+	action->private->profiles = NULL;
 }
diff --git a/src/common/na-action.h b/src/common/na-action.h
index 3a6a6fd..0996d48 100644
--- a/src/common/na-action.h
+++ b/src/common/na-action.h
@@ -31,52 +31,22 @@
 #ifndef __NA_ACTION_H__
 #define __NA_ACTION_H__
 
-/*
- * NAAction class definition.
- *
- * This is the class which maintains an action.
+/**
+ * SECTION: na_action
+ * @short_description: #NAAction class definition.
+ * @include: common/na-action.h
  *
- * NAAction class is derived from NAObject.
+ * This is the class which maintains data and properties of an Nautilus
+ * action.
  */
 
-#include "na-object.h"
-#include "na-pivot.h"
+#include "na-action-class.h"
+#include "na-action-profile-class.h"
+#include "na-iio-provider.h"
 
 G_BEGIN_DECLS
 
-#define NA_ACTION_TYPE					( na_action_get_type())
-#define NA_ACTION( object )				( G_TYPE_CHECK_INSTANCE_CAST( object, NA_ACTION_TYPE, NAAction ))
-#define NA_ACTION_CLASS( klass )		( G_TYPE_CHECK_CLASS_CAST( klass, NA_ACTION_TYPE, NAActionClass ))
-#define NA_IS_ACTION( object )			( G_TYPE_CHECK_INSTANCE_TYPE( object, NA_ACTION_TYPE ))
-#define NA_IS_ACTION_CLASS( klass )		( G_TYPE_CHECK_CLASS_TYPE(( klass ), NA_ACTION_TYPE ))
-#define NA_ACTION_GET_CLASS( object )	( G_TYPE_INSTANCE_GET_CLASS(( object ), NA_ACTION_TYPE, NAActionClass ))
-
-typedef struct NAActionPrivate NAActionPrivate;
-
-typedef struct {
-	NAObject         parent;
-	NAActionPrivate *private;
-}
-	NAAction;
-
-typedef struct NAActionClassPrivate NAActionClassPrivate;
-
-typedef struct {
-	NAObjectClass         parent;
-	NAActionClassPrivate *private;
-}
-	NAActionClass;
-
-/* instance properties
- */
-#define PROP_ACTION_UUID_STR			"action-uuid"
-#define PROP_ACTION_VERSION_STR			"action-version"
-#define PROP_ACTION_LABEL_STR			"action-label"
-#define PROP_ACTION_TOOLTIP_STR			"action-tooltip"
-#define PROP_ACTION_ICON_STR			"action-icon"
-#define PROP_ACTION_READONLY_STR		"action-read-only"
-#define PROP_ACTION_PROVIDER_STR		"action-provider"
-
+/* TODO: move this declaration elsewhere */
 /* export formats
  * used to be only GConf schemas ('gconfschemafile' XML document)
  */
@@ -84,38 +54,35 @@ enum {
 	EXPORT_FORMAT_GCONFSCHEMAFILE = 1
 };
 
-GType     na_action_get_type( void );
-
-NAAction *na_action_new( const gchar *uuid );
-NAAction *na_action_new_with_profile( void );
-NAAction *na_action_duplicate( const NAAction *action );
-
-gchar    *na_action_get_uuid( const NAAction *action );
-gchar    *na_action_get_version( const NAAction *action );
-gchar    *na_action_get_label( const NAAction *action );
-gchar    *na_action_get_tooltip( const NAAction *action );
-gchar    *na_action_get_icon( const NAAction *action );
-gchar    *na_action_get_verified_icon_name( const NAAction *action );
-gboolean  na_action_is_readonly( const NAAction *action );
-gpointer  na_action_get_provider( const NAAction *action );
-
-void      na_action_set_new_uuid( NAAction *action );
-void      na_action_set_uuid( NAAction *action, const gchar *uuid );
-void      na_action_set_version( NAAction *action, const gchar *version );
-void      na_action_set_label( NAAction *action, const gchar *label );
-void      na_action_set_tooltip( NAAction *action, const gchar *tooltip );
-void      na_action_set_icon( NAAction *action, const gchar *icon_name );
-
-gboolean  na_action_are_equal( const NAAction *first, const NAAction *second );
-
-gchar    *na_action_get_new_profile_name( const NAAction *action );
-NAObject *na_action_get_profile( const NAAction *action, const gchar *name );
-GSList   *na_action_get_profiles( const NAAction *action );
-void      na_action_add_profile( NAAction *action, NAObject *profile );
-void      na_action_set_profiles( NAAction *action, GSList *list );
-void      na_action_free_profiles( GSList *list );
-
-guint     na_action_get_profiles_count( const NAAction *action );
+NAAction        *na_action_new( void );
+NAAction        *na_action_new_with_profile( void );
+
+gchar           *na_action_get_uuid( const NAAction *action );
+gchar           *na_action_get_label( const NAAction *action );
+gchar           *na_action_get_version( const NAAction *action );
+gchar           *na_action_get_tooltip( const NAAction *action );
+gchar           *na_action_get_icon( const NAAction *action );
+gchar           *na_action_get_verified_icon_name( const NAAction *action );
+gboolean         na_action_is_readonly( const NAAction *action );
+NAIIOProvider   *na_action_get_provider( const NAAction *action );
+
+void             na_action_set_new_uuid( NAAction *action );
+void             na_action_set_uuid( NAAction *action, const gchar *uuid );
+void             na_action_set_label( NAAction *action, const gchar *label );
+void             na_action_set_version( NAAction *action, const gchar *version );
+void             na_action_set_tooltip( NAAction *action, const gchar *tooltip );
+void             na_action_set_icon( NAAction *action, const gchar *icon_name );
+void             na_action_set_readonly( NAAction *action, gboolean readonly );
+void             na_action_set_provider( NAAction *action, const NAIIOProvider *provider );
+
+gchar           *na_action_get_new_profile_name( const NAAction *action );
+NAActionProfile *na_action_get_profile( const NAAction *action, const gchar *name );
+GSList          *na_action_get_profiles( const NAAction *action );
+void             na_action_attach_profile( NAAction *action, NAActionProfile *profile );
+void             na_action_remove_profile( NAAction *action, NAActionProfile *profile );
+void             na_action_set_profiles( NAAction *action, GSList *list );
+void             na_action_free_profiles( GSList *list );
+guint            na_action_get_profiles_count( const NAAction *action );
 
 G_END_DECLS
 
diff --git a/src/common/na-gconf.c b/src/common/na-gconf.c
index 7029d2a..ef8b283 100644
--- a/src/common/na-gconf.c
+++ b/src/common/na-gconf.c
@@ -32,10 +32,10 @@
 #include <config.h>
 #endif
 
-#include <string.h>
-
 #include <gconf/gconf.h>
 #include <gconf/gconf-client.h>
+#include <glib/gi18n.h>
+#include <string.h>
 
 #include "na-action.h"
 #include "na-action-profile.h"
@@ -53,45 +53,49 @@ struct NAGConfClassPrivate {
  */
 struct NAGConfPrivate {
 	gboolean     dispose_has_run;
-
 	GConfClient *gconf;
-
-	/* instance to be notified of an action modification
-	 */
 	gpointer     notified;
-	guint        notify_id;
+	guint        watch_id;
 };
 
 /* private instance properties
  */
 enum {
-	PROP_NOTIFIED = 1
+	PROP_NAGCONF_GCONF = 1,
+	PROP_NAGCONF_NOTIFIED,
+	PROP_NAGCONF_WATCH_ID
 };
 
-#define PROP_NOTIFIED_STR				"to-be-notified"
+#define PROP_NAGCONF_GCONF_STR			"na-gconf-client"
+#define PROP_NAGCONF_NOTIFIED_STR		"na-gconf-to-be-notified"
+#define PROP_NAGCONF_WATCH_ID_STR		"na-gconf-watch-id"
 
 /* correspondance table for association of GConf entry keys to action
  * and profile properties
  */
-typedef struct {
+/*typedef struct {
 	gchar *gconfkey;
 	gchar *property;
 }
 	KeyToPropertyStruct;
 
 static KeyToPropertyStruct st_key_property[] = {
-	{ ACTION_PROFILE_LABEL_ENTRY, PROP_PROFILE_LABEL_STR           },
-	{ ACTION_PATH_ENTRY         , PROP_PROFILE_PATH_STR            },
-	{ ACTION_PARAMETERS_ENTRY   , PROP_PROFILE_PARAMETERS_STR      },
-	{ ACTION_BASENAMES_ENTRY    , PROP_PROFILE_BASENAMES_STR       },
-	{ ACTION_MATCHCASE_ENTRY    , PROP_PROFILE_MATCHCASE_STR       },
-	{ ACTION_MIMETYPES_ENTRY    , PROP_PROFILE_MIMETYPES_STR       },
-	{ ACTION_ISFILE_ENTRY       , PROP_PROFILE_ISFILE_STR          },
-	{ ACTION_ISDIR_ENTRY        , PROP_PROFILE_ISDIR_STR           },
-	{ ACTION_MULTIPLE_ENTRY     , PROP_PROFILE_ACCEPT_MULTIPLE_STR },
-	{ ACTION_SCHEMES_ENTRY      , PROP_PROFILE_SCHEMES_STR         },
+	{ ACTION_VERSION_ENTRY      , PROP_NAACTION_VERSION_STR          },
+	{ ACTION_LABEL_ENTRY        , PROP_NAACTION_LABEL_STR            },
+	{ ACTION_TOOLTIP_ENTRY      , PROP_NAACTION_TOOLTIP_STR          },
+	{ ACTION_ICON_ENTRY         , PROP_NAACTION_ICON_STR             },
+	{ ACTION_PROFILE_LABEL_ENTRY, PROP_NAPROFILE_LABEL_STR           },
+	{ ACTION_PATH_ENTRY         , PROP_NAPROFILE_PATH_STR            },
+	{ ACTION_PARAMETERS_ENTRY   , PROP_NAPROFILE_PARAMETERS_STR      },
+	{ ACTION_BASENAMES_ENTRY    , PROP_NAPROFILE_BASENAMES_STR       },
+	{ ACTION_MATCHCASE_ENTRY    , PROP_NAPROFILE_MATCHCASE_STR       },
+	{ ACTION_MIMETYPES_ENTRY    , PROP_NAPROFILE_MIMETYPES_STR       },
+	{ ACTION_ISFILE_ENTRY       , PROP_NAPROFILE_ISFILE_STR          },
+	{ ACTION_ISDIR_ENTRY        , PROP_NAPROFILE_ISDIR_STR           },
+	{ ACTION_MULTIPLE_ENTRY     , PROP_NAPROFILE_ACCEPT_MULTIPLE_STR },
+	{ ACTION_SCHEMES_ENTRY      , PROP_NAPROFILE_SCHEMES_STR         },
 	{                       NULL, NULL }
-};
+};*/
 
 static GObjectClass *st_parent_class = NULL;
 
@@ -104,15 +108,35 @@ static void           instance_set_property( GObject *object, guint property_id,
 static void           instance_dispose( GObject *object );
 static void           instance_finalize( GObject *object );
 
-static GSList        *do_read_actions( NAIIOProvider *provider );
-static gboolean       load_action( NAGConf *gconf, NAAction *action, const gchar *uuid );
-/*static void           load_action_properties( NAGConf *gconf, NAAction *action );*/
+static GSList        *iio_provider_read_actions( const NAIIOProvider *provider );
+static gboolean       iio_provider_is_willing_to_write( const NAIIOProvider *provider );
+static gboolean       iio_provider_is_writable( const NAIIOProvider *provider, const NAAction *action );
+static guint          iio_provider_write_action( const NAIIOProvider *provider, NAAction *action, gchar **message );
+static guint          iio_provider_delete_action( const NAIIOProvider *provider, const NAAction *action, gchar **message );
+
+static gboolean       read_action( NAGConf *gconf, NAAction *action, const gchar *path );
+static gboolean       read_profile( NAGConf *gconf, NAActionProfile *profile, const gchar *path );
+static gboolean       fill_action_core_properties( NAGConf *gconf, NAAction *action, GSList *notifies );
+static void           fill_action_v1_properties( NAGConf *gconf, NAAction *action, GSList *notifies );
+static void           fill_profile_properties( NAGConf *gconf, NAActionProfile *profile, GSList *notifies );
+
+static GSList        *get_path_subdirs( const NAGConf *gconf, const gchar *path );
+static GSList        *get_list_entries( const NAGConf *gconf, const gchar *path );
+static void           free_list_entries( GSList *entries );
+static gchar         *path_to_key( const gchar *path );
+static NAPivotNotify *entry_to_notify( const GConfEntry *entry );
+static GSList        *entries_to_notifies( GSList *entries );
+static void           free_list_notifies( GSList *notifies );
+static gboolean       search_for_str( GSList *notifies, const gchar *profile, const gchar *key, gchar **value );
+static gboolean       search_for_bool( GSList *notifies, const gchar *profile, const gchar *key, gboolean *value );
+static gboolean       search_for_list( GSList *notifies, const gchar *profile, const gchar *key, GSList **value );
+
+/*static gboolean       load_action( NAGConf *gconf, NAAction *action, const gchar *path );
+static void           load_action_properties( NAGConf *gconf, NAAction *action );
 static GSList        *load_profiles( NAGConf *gconf, NAAction *action );
 static void           load_profile_properties( NAGConf *gconf, NAActionProfile *profile );
-static GSList        *load_subdirs( const NAGConf *gconf, const gchar *path );
 static GSList        *load_keys_values( const NAGConf *gconf, const gchar *path );
 static void           free_keys_values( GSList *entries );
-static gchar         *path_to_key( const gchar *path );
 static void           set_item_properties( NAObject *object, GSList *properties );
 static const gchar   *key_to_property( const gchar *key );
 static gboolean       set_action_properties( NAGConf *gconf, NAAction *action, GSList *properties );
@@ -121,16 +145,10 @@ static gchar         *search_for_str( GSList *properties, const gchar *profile,
 static gboolean       search_for_bool( GSList *properties, const gchar *profile, const gchar *key );
 static GSList        *search_for_list( GSList *properties, const gchar *profile, const gchar *key );
 static GSList        *keys_to_notify( GSList *entries );
-static NAPivotNotify *entry_to_notify( const GConfEntry *entry );
 static void           free_list_notify( GSList *list );
 static gboolean       remove_v1_keys( NAGConf *gconf, const NAAction *action, gchar **message );
-static gboolean       remove_key( NAGConf *gconf, const gchar *uuid, const gchar *key, gchar **message );
+static gboolean       remove_key( NAGConf *gconf, const gchar *uuid, const gchar *key, gchar **message );*/
 
-static gboolean       do_is_writable( NAIIOProvider *provider );
-static gboolean       do_is_willing_to_write( NAIIOProvider *provider, const GObject *action );
-
-static guint          do_write_action( NAIIOProvider *provider, const GObject *action, gchar **message );
-static guint          do_delete_action( NAIIOProvider *provider, const GObject *action, gchar **message );
 static gboolean       key_is_writable( NAGConf *gconf, const gchar *path );
 static gboolean       write_v2_keys( NAGConf *gconf, const NAAction *action, gchar **message );
 static gboolean       write_str( NAGConf *gconf, const gchar *uuid, const gchar *key, gchar *value, gchar **message );
@@ -160,6 +178,9 @@ na_gconf_get_type( void )
 static GType
 register_type( void )
 {
+	static const gchar *thisfn = "na_gconf_register_type";
+	g_debug( "%s", thisfn );
+
 	static GTypeInfo info = {
 		sizeof( NAGConfClass ),
 		NULL,
@@ -174,6 +195,8 @@ register_type( void )
 
 	GType type = g_type_register_static( G_TYPE_OBJECT, "NAGConf", &info, 0 );
 
+	/* implements IIOProvider interface
+	 */
 	static const GInterfaceInfo iio_provider_iface_info = {
 		( GInterfaceInitFunc ) iio_provider_iface_init,
 		NULL,
@@ -201,11 +224,25 @@ class_init( NAGConfClass *klass )
 
 	GParamSpec *spec;
 	spec = g_param_spec_pointer(
-			PROP_NOTIFIED_STR,
-			PROP_NOTIFIED_STR,
+			PROP_NAGCONF_GCONF_STR,
+			"GConfClient object",
+			"A pointer to the GConfClient object",
+			G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE );
+	g_object_class_install_property( object_class, PROP_NAGCONF_GCONF, spec );
+
+	spec = g_param_spec_pointer(
+			PROP_NAGCONF_NOTIFIED_STR,
+			"Object to be notified",
 			"A pointer to a GObject which will receive action_changed notifications",
-			G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE );
-	g_object_class_install_property( object_class, PROP_NOTIFIED, spec );
+			G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE );
+	g_object_class_install_property( object_class, PROP_NAGCONF_NOTIFIED, spec );
+
+	spec = g_param_spec_uint(
+			PROP_NAGCONF_WATCH_ID_STR,
+			"Watch ID",
+			"The unique ID got when installing the watch monitor on GConf", 0, 0, 0,
+			G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE );
+	g_object_class_install_property( object_class, PROP_NAGCONF_WATCH_ID, spec );
 
 	klass->private = g_new0( NAGConfClassPrivate, 1 );
 }
@@ -216,11 +253,11 @@ iio_provider_iface_init( NAIIOProviderInterface *iface )
 	static const gchar *thisfn = "na_gconf_iio_provider_iface_init";
 	g_debug( "%s: iface=%p", thisfn, iface );
 
-	iface->read_actions = do_read_actions;
-	iface->is_writable = do_is_writable;
-	iface->is_willing_to_write = do_is_willing_to_write;
-	iface->write_action = do_write_action;
-	iface->delete_action = do_delete_action;
+	iface->read_actions = iio_provider_read_actions;
+	iface->is_willing_to_write = iio_provider_is_willing_to_write;
+	iface->is_writable = iio_provider_is_writable;
+	iface->write_action = iio_provider_write_action;
+	iface->delete_action = iio_provider_delete_action;
 }
 
 static void
@@ -236,7 +273,7 @@ instance_init( GTypeInstance *instance, gpointer klass )
 
 	self->private->dispose_has_run = FALSE;
 	self->private->gconf = gconf_client_get_default();
-	self->private->notify_id = install_gconf_watch( self );
+	self->private->watch_id = install_gconf_watch( self );
 }
 
 static void
@@ -246,10 +283,18 @@ instance_get_property( GObject *object, guint property_id, GValue *value, GParam
 	NAGConf *self = NA_GCONF( object );
 
 	switch( property_id ){
-		case PROP_NOTIFIED:
+		case PROP_NAGCONF_GCONF:
+			g_value_set_pointer( value, self->private->gconf );
+			break;
+
+		case PROP_NAGCONF_NOTIFIED:
 			g_value_set_pointer( value, self->private->notified );
 			break;
 
+		case PROP_NAGCONF_WATCH_ID:
+			g_value_set_uint( value, self->private->watch_id );
+			break;
+
 		default:
 			G_OBJECT_WARN_INVALID_PROPERTY_ID( object, property_id, spec );
 			break;
@@ -263,10 +308,18 @@ instance_set_property( GObject *object, guint property_id, const GValue *value,
 	NAGConf *self = NA_GCONF( object );
 
 	switch( property_id ){
-		case PROP_NOTIFIED:
+		case PROP_NAGCONF_GCONF:
+			self->private->gconf = g_value_get_pointer( value );
+			break;
+
+		case PROP_NAGCONF_NOTIFIED:
 			self->private->notified = g_value_get_pointer( value );
 			break;
 
+		case PROP_NAGCONF_WATCH_ID:
+			self->private->watch_id = g_value_get_uint( value );
+			break;
+
 		default:
 			G_OBJECT_WARN_INVALID_PROPERTY_ID( object, property_id, spec );
 			break;
@@ -307,36 +360,32 @@ instance_finalize( GObject *object )
 }
 
 /**
- * Allocate a new GConf object.
+ * na_gconf_new:
+ * @handler: a #GObject-derived object which is to be notified when an
+ * action is added, modified or removed in underlying GConf system.
  *
- * @handler: the GObject which is to be notified when an action is
- * added, modified or removed in underlying GConf system.
+ * Allocates a new #NAGConf object.
  *
- * The object to be notified will receive a
- * "notify_pivot_of_action_changed" message for each detected
- * modification, with a pointer to a newly allocated NAPivotNotify
+ * Is specified, the #GObject-derived object to be notified will
+ * receive a "notify_pivot_of_action_changed" message for each detected
+ * modification, with a pointer to a newly allocated #NAPivotNotify
  * structure describing the change.
  */
 NAGConf *
 na_gconf_new( const GObject *handler )
 {
-	return( g_object_new( NA_GCONF_TYPE, PROP_NOTIFIED_STR, handler, NULL ));
+	return( g_object_new( NA_GCONF_TYPE, PROP_NAGCONF_NOTIFIED_STR, handler, NULL ));
 }
 
 /*
- * NAIIOProviderInterface implementation
- * load the list of actions and returns them as a GSList
- *
- * @provider: this NAGconf object, seen here as a I/O provider.
- *
- * Note that whatever be the version of the readen action, we convert
- * it now to the latest available, possibly updating the GConf storage
- * subsystem.
+ * Note that whatever be the version of the readen action, it will be
+ * stored as a #NAAction and its set of #NAActionProfile of the same,
+ * latest, version of these classes.
  */
 static GSList *
-do_read_actions( NAIIOProvider *provider )
+iio_provider_read_actions( const NAIIOProvider *provider )
 {
-	static const gchar *thisfn = "nacf_gconf_do_read_actions";
+	static const gchar *thisfn = "nacf_gconf_iio_provider_read_actions";
 	g_debug( "%s: provider=%p", thisfn, provider );
 
 	g_assert( NA_IS_IIO_PROVIDER( provider ));
@@ -345,22 +394,33 @@ do_read_actions( NAIIOProvider *provider )
 
 	GSList *items = NULL;
 	GSList *ip;
-	GSList *listpath = load_subdirs( self, NA_GCONF_CONFIG_PATH );
+	GSList *listpath = get_path_subdirs( self, NA_GCONF_CONFIG_PATH );
 
 	for( ip = listpath ; ip ; ip = ip->next ){
 
-		gchar *key = path_to_key(( const gchar * ) ip->data );
+		const gchar *path = ( const gchar * ) ip->data;
 
-		NAAction *action = na_action_new( key );
+		NAAction *action = na_action_new();
 
-		if( load_action( self, action, key )){
+		if( read_action( self, action, path )){
 			items = g_slist_prepend( items, action );
 
 		} else {
 			g_object_unref( action );
 		}
 
-		g_free( key );
+		/*gchar *uuid = path_to_key( path );
+
+		NAAction *action = na_action_new( uuid );
+
+		if( load_action( self, action, path )){
+			items = g_slist_prepend( items, action );
+
+		} else {
+			g_object_unref( action );
+		}
+
+		g_free( uuid );*/
 	}
 
 	na_utils_free_string_list( listpath );
@@ -368,6 +428,81 @@ do_read_actions( NAIIOProvider *provider )
 	return( items );
 }
 
+static gboolean
+iio_provider_is_willing_to_write( const NAIIOProvider *provider )
+{
+	/* TODO: na_gconf_iio_provider_is_willing_to_write */
+	return( TRUE );
+}
+
+static gboolean
+iio_provider_is_writable( const NAIIOProvider *provider, const NAAction *action )
+{
+	/* TODO: na_gconf_iio_provider_is_writable */
+	return( TRUE );
+}
+
+static guint
+iio_provider_write_action( const NAIIOProvider *provider, NAAction *action, gchar **message )
+{
+	static const gchar *thisfn = "na_gconf_iio_provider_write_action";
+	g_debug( "%s: provider=%p, action=%p, message=%p", thisfn, provider, action, message );
+
+	g_assert( NA_IS_IIO_PROVIDER( provider ));
+	g_assert( NA_IS_GCONF( provider ));
+	NAGConf *self = NA_GCONF( provider );
+
+	message = NULL;
+
+	g_assert( NA_IS_ACTION( action ));
+
+	if( !write_v2_keys( self, action, message )){
+		return( NA_IIO_PROVIDER_WRITE_ERROR );
+
+	} else {
+		gconf_client_suggest_sync( self->private->gconf, NULL );
+	}
+
+	na_action_set_provider( action, provider );
+
+	return( NA_IIO_PROVIDER_WRITE_OK );
+}
+
+static guint
+iio_provider_delete_action( const NAIIOProvider *provider, const NAAction *action, gchar **message )
+{
+	static const gchar *thisfn = "na_gconf_iio_provider_delete_action";
+	g_debug( "%s: provider=%p, action=%p, message=%p", thisfn, provider, action, message );
+
+	g_assert( NA_IS_IIO_PROVIDER( provider ));
+	g_assert( NA_IS_GCONF( provider ));
+	NAGConf *self = NA_GCONF( provider );
+
+	message = NULL;
+	guint ret = NA_IIO_PROVIDER_WRITE_OK;
+
+	g_assert( NA_IS_ACTION( action ));
+
+	gchar *uuid = na_action_get_uuid( action );
+	gchar *path = g_strdup_printf( "%s/%s", NA_GCONF_CONFIG_PATH, uuid );
+	GError *error = NULL;
+
+	if( !gconf_client_recursive_unset( self->private->gconf, path, 0, &error )){
+		g_debug( "%s: error=%s", thisfn, error->message );
+		*message = g_strdup( error->message );
+		g_error_free( error );
+		ret = NA_IIO_PROVIDER_WRITE_ERROR;
+
+	} else {
+		gconf_client_suggest_sync( self->private->gconf, NULL );
+		g_debug( "%s: ok for %s", thisfn, path );
+	}
+
+	g_free( path );
+	g_free( uuid );
+	return( ret );
+}
+
 /*
  * load and set the properties of the specified action
  * at least we must have a label, as all other entries can have
@@ -385,8 +520,8 @@ do_read_actions( NAIIOProvider *provider )
  * - version = '2.0' which introduces the 'profile' notion
  *   profile += name+label
  */
-static gboolean
-load_action( NAGConf *gconf, NAAction *action, const gchar *uuid )
+/*static gboolean
+load_action( NAGConf *gconf, NAAction *action, const gchar *path )
 {
 	static const gchar *thisfn = "nacf_gconf_load_action";
 	g_debug( "%s: gconf=%p, action=%p, uuid=%s", thisfn, gconf, action, uuid );
@@ -403,12 +538,445 @@ load_action( NAGConf *gconf, NAAction *action, const gchar *uuid )
 	gboolean ok = set_action_properties( gconf, action, properties );
 
 	if( !key_is_writable( gconf, path )){
-		g_object_set( G_OBJECT( action ), PROP_ACTION_READONLY_STR, TRUE, NULL );
+		g_object_set( G_OBJECT( action ), PROP_NAGCONF_ACTION_READONLY_STR, TRUE, NULL );
 	}
 
 	free_list_notify( properties );
 	g_free( path );
 	return( ok );
+}*/
+static gboolean
+read_action( NAGConf *gconf, NAAction *action, const gchar *path )
+{
+	static const gchar *thisfn = "nacf_gconf_read_action";
+	g_debug( "%s: gconf=%p, action=%p, path=%s", thisfn, gconf, action, path );
+
+	g_assert( NA_IS_GCONF( gconf ));
+	g_assert( NA_IS_ACTION( action ));
+
+	gchar *uuid = path_to_key( path );
+	na_action_set_uuid( action, uuid );
+	g_free( uuid );
+
+	GSList *entries = get_list_entries( gconf, path );
+	GSList *notifies = entries_to_notifies( entries );
+	free_list_entries( entries );
+
+	gboolean ok = fill_action_core_properties( gconf, action, notifies  );
+
+	GSList *ip;
+	GSList *list_profiles = get_path_subdirs( gconf, path );
+	if( list_profiles ){
+		for( ip = list_profiles ; ip ; ip = ip->next ){
+
+			const gchar *profile_path = ( const gchar * ) ip->data;
+			NAActionProfile *profile = na_action_profile_new();
+
+			if( read_profile( gconf, profile, profile_path )){
+				na_action_attach_profile( action, profile );
+
+			} else {
+				g_object_unref( profile );
+			}
+		}
+
+	} else {
+		fill_action_v1_properties( gconf, action, notifies );
+	}
+
+	free_list_notifies( notifies );
+
+	na_action_set_readonly( action, !key_is_writable( gconf, path ));
+
+	return( ok );
+}
+
+static gboolean
+read_profile( NAGConf *gconf, NAActionProfile *profile, const gchar *path )
+{
+	static const gchar *thisfn = "nacf_gconf_read_profile";
+	g_debug( "%s: gconf=%p, profile=%p, path=%s", thisfn, gconf, profile, path );
+
+	g_assert( NA_IS_GCONF( gconf ));
+	g_assert( NA_IS_ACTION_PROFILE( profile ));
+
+	gchar *name = path_to_key( path );
+	na_action_profile_set_name( profile, name );
+	g_free( name );
+
+	GSList *entries = get_list_entries( gconf, path );
+	GSList *notifies = entries_to_notifies( entries );
+	free_list_entries( entries );
+
+	fill_profile_properties( gconf, profile, notifies  );
+
+	free_list_notifies( notifies );
+
+	return( TRUE );
+}
+
+/*
+ * set the item properties into the action, dealing with successive
+ * versions
+ */
+static gboolean
+fill_action_core_properties( NAGConf *gconf, NAAction *action, GSList *notifies )
+{
+	static const gchar *thisfn = "na_gconf_fill_action_properties";
+
+	gchar *label;
+	if( !search_for_str( notifies, NULL, ACTION_LABEL_ENTRY, &label )){
+		gchar *uuid = na_action_get_uuid( action );
+		g_warning( "%s: no label found for action '%s'", thisfn, uuid );
+		g_free( uuid );
+		return( FALSE );
+	}
+	na_action_set_label( action, label );
+	g_free( label );
+
+	gchar *version;
+	if( search_for_str( notifies, NULL, ACTION_VERSION_ENTRY, &version )){
+		na_action_set_version( action, version );
+		g_free( version );
+	}
+
+	gchar *tooltip;
+	if( search_for_str( notifies, NULL, ACTION_TOOLTIP_ENTRY, &tooltip )){
+		na_action_set_tooltip( action, tooltip );
+		g_free( tooltip );
+	}
+
+	gchar *icon;
+	if( search_for_str( notifies, NULL, ACTION_ICON_ENTRY, &icon )){
+		na_action_set_icon( action, icon );
+		g_free( icon );
+	}
+
+	return( TRUE );
+}
+
+/*
+ * version is marked as less than "2.0"
+ * we handle so only one profile, which is already loaded
+ * action+= path+parameters+basenames+isdir+isfile+multiple+schemes
+ * if version greater than "1.0", we have also matchcase+mimetypes
+ */
+static void
+fill_action_v1_properties( NAGConf *gconf, NAAction *action, GSList *notifies )
+{
+	NAActionProfile *profile = na_action_profile_new();
+
+	na_action_attach_profile( action, profile );
+
+	fill_profile_properties( gconf, profile, notifies );
+}
+
+static void
+fill_profile_properties( NAGConf *gconf, NAActionProfile *profile, GSList *notifies )
+{
+	gchar *label;
+	if( !search_for_str( notifies, NULL, ACTION_PROFILE_LABEL_ENTRY, &label )){
+		/* i18n: default profile label */
+		label = g_strdup( _( "Default profile" ));
+	}
+	na_action_profile_set_label( profile, label );
+	g_free( label );
+
+	gchar *path;
+	if( search_for_str( notifies, NULL, ACTION_PATH_ENTRY, &path )){
+		na_action_profile_set_path( profile, path );
+		g_free( path );
+	}
+
+	gchar *parameters;
+	if( search_for_str( notifies, NULL, ACTION_PARAMETERS_ENTRY, &parameters )){
+		na_action_profile_set_parameters( profile, parameters );
+		g_free( parameters );
+	}
+
+	GSList *basenames;
+	if( search_for_list( notifies, NULL, ACTION_BASENAMES_ENTRY, &basenames )){
+		na_action_profile_set_basenames( profile, basenames );
+		na_utils_free_string_list( basenames );
+	}
+
+	gboolean isfile;
+	if( search_for_bool( notifies, NULL, ACTION_ISFILE_ENTRY, &isfile )){
+		na_action_profile_set_isfile( profile, isfile );
+	}
+
+	gboolean isdir;
+	if( search_for_bool( notifies, NULL, ACTION_ISDIR_ENTRY, &isdir )){
+		na_action_profile_set_isdir( profile, isdir );
+	}
+
+	gboolean multiple;
+	if( search_for_bool( notifies, NULL, ACTION_MULTIPLE_ENTRY, &multiple )){
+		na_action_profile_set_multiple( profile, multiple );
+	}
+
+	GSList *schemes;
+	if( search_for_list( notifies, NULL, ACTION_SCHEMES_ENTRY, &schemes )){
+		na_action_profile_set_schemes( profile, schemes );
+		na_utils_free_string_list( schemes );
+	}
+
+	/* handle matchcase+mimetypes
+	 * note that default values for 1.0 version have been set
+	 * in na_action_profile_instance_init
+	 */
+	gboolean matchcase;
+	if( search_for_bool( notifies, NULL, ACTION_MATCHCASE_ENTRY, &matchcase )){
+		na_action_profile_set_matchcase( profile, matchcase );
+	}
+
+	GSList *mimetypes;
+	if( search_for_list( notifies, NULL, ACTION_MIMETYPES_ENTRY, &mimetypes )){
+		na_action_profile_set_mimetypes( profile, mimetypes );
+		na_utils_free_string_list( mimetypes );
+	}
+}
+
+/*
+ * load the keys which are the subdirs of the given path
+ * returns a list of keys as full path
+ */
+/*static GSList *
+load_subdirs( const NAGConf *gconf, const gchar *path )
+{
+	static const gchar *thisfn = "na_gconf_load_subdirs";
+
+	GError *error = NULL;
+	GSList *list = gconf_client_all_dirs( gconf->private->gconf, path, &error );
+	if( error ){
+		g_warning( "%s: path=%s, error=%s", thisfn, path, error->message );
+		g_error_free( error );
+		return(( GSList * ) NULL );
+	}
+
+	return( list );
+}*/
+static GSList *
+get_path_subdirs( const NAGConf *gconf, const gchar *path )
+{
+	static const gchar *thisfn = "na_gconf_get_path_subdirs";
+
+	GError *error = NULL;
+	GSList *list = gconf_client_all_dirs( gconf->private->gconf, path, &error );
+	if( error ){
+		g_warning( "%s: path=%s, error=%s", thisfn, path, error->message );
+		g_error_free( error );
+		return(( GSList * ) NULL );
+	}
+
+	return( list );
+}
+
+/*
+ * load all the key=value pairs of this key (specified as a full path),
+ * returning them as a list of GConfEntry.
+ *
+ * The list is not recursive, it contains only the immediate children of
+ * path. To free the returned list, call free_list_entries().
+ */
+static GSList *
+get_list_entries( const NAGConf *gconf, const gchar *path )
+{
+	static const gchar *thisfn = "na_gconf_get_list_values";
+
+	GError *error = NULL;
+	GSList *list_path = gconf_client_all_entries( gconf->private->gconf, path, &error );
+	if( error ){
+		g_warning( "%s: path=%s, error=%s", thisfn, path, error->message );
+		g_error_free( error );
+		return(( GSList * ) NULL );
+	}
+
+	return( list_path );
+}
+
+static void
+free_list_entries( GSList *list )
+{
+	GSList *item;
+	for( item = list ; item != NULL ; item = item->next ){
+		GConfEntry *entry = ( GConfEntry * ) item->data;
+		gconf_entry_unref( entry );
+	}
+	g_slist_free( list );
+}
+
+/*
+ * extract the key part (the last part) of a full path
+ * returns a newly allocated string which must be g_free() by the caller
+ */
+static gchar *
+path_to_key( const gchar *path )
+{
+	gchar **split = g_strsplit( path, "/", -1 );
+	guint count = g_strv_length( split );
+	gchar *key = g_strdup( split[count-1] );
+	g_strfreev( split );
+	return( key );
+}
+
+/*
+ * convert a GConfEntry to a structure suitable to notify NAPivot
+ *
+ * when created or modified, the entry can be of the forms :
+ *  key=path/uuid/parm
+ *  key=path/uuid/profile/parm with a not null value
+ *
+ * but when removing an entry, it will be of the form :
+ *  key=path/uuid
+ *  key=path/uuid/parm
+ *  key=path/uuid/profile
+ *  key=path/uuid/profile/parm with a null value
+ *
+ * I don't know any way to choose between key/parm and key/profile (*)
+ * as the entry no more exists in GConf and thus cannot be tested
+ * -> we will set this as key/parm, letting pivot try to interpret it
+ *
+ * (*) other than assuming that a profile name begins with 'profile-'
+ * (see action-profile.h)
+ */
+static NAPivotNotify *
+entry_to_notify( const GConfEntry *entry )
+{
+	/*static const gchar *thisfn = "na_gconf_entry_to_notify";*/
+	GSList *listvalues, *iv, *strings;
+
+	g_assert( entry );
+
+	const gchar *path = gconf_entry_get_key( entry );
+	g_assert( path );
+
+	NAPivotNotify *npn = g_new0( NAPivotNotify, 1 );
+
+	const gchar *subpath = path + strlen( NA_GCONF_CONFIG_PATH ) + 1;
+	gchar **split = g_strsplit( subpath, "/", -1 );
+	/*g_debug( "%s: [0]=%s, [1]=%s", thisfn, split[0], split[1] );*/
+	npn->uuid = g_strdup( split[0] );
+	if( g_strv_length( split ) == 2 ){
+		npn->parm = g_strdup( split[1] );
+	} else if( g_strv_length( split ) == 3 ){
+		npn->profile = g_strdup( split[1] );
+		npn->parm = g_strdup( split[2] );
+	}
+	g_strfreev( split );
+
+	const GConfValue *value = gconf_entry_get_value( entry );
+	if( value ){
+		switch( value->type ){
+
+			case GCONF_VALUE_STRING:
+				npn->type = NA_PIVOT_STR;
+				npn->data = ( gpointer ) g_strdup( gconf_value_get_string( value ));
+				break;
+
+			case GCONF_VALUE_BOOL:
+				npn->type = NA_PIVOT_BOOL;
+				npn->data = ( gpointer ) gconf_value_get_bool( value );
+				break;
+
+			case GCONF_VALUE_LIST:
+				listvalues = gconf_value_get_list( value );
+				strings = NULL;
+				for( iv = listvalues ; iv != NULL ; iv = iv->next ){
+					strings = g_slist_prepend( strings,
+							( gpointer ) gconf_value_get_string(( GConfValue * ) iv->data ));
+				}
+
+				npn->type = NA_PIVOT_STRLIST;
+				npn->data = ( gpointer ) na_utils_duplicate_string_list( strings );
+				/*na_utils_free_string_list( strings );*/
+				break;
+
+			default:
+				g_assert_not_reached();
+				break;
+		}
+	}
+	return( npn );
+}
+
+/*
+ * convert a list of GConfEntry to a list of NAPivotNotify.
+ */
+static GSList *
+entries_to_notifies( GSList *entries )
+{
+	GSList *item;
+	GSList *notifies = NULL;
+
+	for( item = entries ; item ; item = item->next ){
+
+		const GConfEntry *entry = ( const GConfEntry * ) item->data;
+		NAPivotNotify *npn = entry_to_notify( entry );
+		notifies = g_slist_prepend( notifies, npn );
+	}
+
+	return( notifies );
+}
+
+static void
+free_list_notifies( GSList *list )
+{
+	GSList *il;
+	for( il = list ; il ; il = il->next ){
+		na_pivot_free_notify(( NAPivotNotify *) il->data );
+	}
+}
+
+static gboolean
+search_for_str( GSList *properties, const gchar *profile, const gchar *key, gchar **value )
+{
+	*value = NULL;
+	GSList *ip;
+	for( ip = properties ; ip ; ip = ip->next ){
+		NAPivotNotify *npn = ( NAPivotNotify * ) ip->data;
+		if( npn->type == NA_PIVOT_STR &&
+		  ( !profile || !g_ascii_strcasecmp( profile, npn->profile )) &&
+		    !g_ascii_strcasecmp( key, npn->parm )){
+				*value = g_strdup(( gchar * ) npn->data );
+				return( TRUE );
+		}
+	}
+	return( FALSE );
+}
+
+static gboolean
+search_for_bool( GSList *properties, const gchar *profile, const gchar *key, gboolean *value )
+{
+	*value = FALSE;
+	GSList *ip;
+	for( ip = properties ; ip ; ip = ip->next ){
+		NAPivotNotify *npn = ( NAPivotNotify * ) ip->data;
+		if( npn->type == NA_PIVOT_BOOL &&
+		  ( !profile || !g_ascii_strcasecmp( profile, npn->profile )) &&
+			!g_ascii_strcasecmp( key, npn->parm )){
+				*value = ( gboolean ) npn->data;
+				return( TRUE );
+		}
+	}
+	return( FALSE );
+}
+
+static gboolean
+search_for_list( GSList *properties, const gchar *profile, const gchar *key, GSList **value )
+{
+	*value = NULL;
+	GSList *ip;
+	for( ip = properties ; ip ; ip = ip->next ){
+		NAPivotNotify *npn = ( NAPivotNotify * ) ip->data;
+		if( npn->type == NA_PIVOT_STRLIST &&
+		  ( !profile || !g_ascii_strcasecmp( profile, npn->profile )) &&
+			!g_ascii_strcasecmp( key, npn->parm )){
+				*value = na_utils_duplicate_string_list(( GSList * ) npn->data );
+				return( TRUE );
+		}
+	}
+	return( FALSE );
 }
 
 /*
@@ -438,13 +1006,13 @@ load_action_properties( NAGConf *gconf, NAAction *action )
 /*
  * load the list of profiles for an action and returns them as a GSList
  */
-static GSList *
+/*static GSList *
 load_profiles( NAGConf *gconf, NAAction *action )
-{
+{*/
 	/*static const gchar *thisfn = "nacf_gconf_load_profiles";
 	g_debug( "%s: gconf=%p, action=%p", thisfn, gconf, action );*/
 
-	g_assert( NA_IS_GCONF( gconf ));
+	/*g_assert( NA_IS_GCONF( gconf ));
 	g_assert( NA_IS_ACTION( action ));
 
 	gchar *uuid = na_action_get_uuid( action );
@@ -468,18 +1036,18 @@ load_profiles( NAGConf *gconf, NAAction *action )
 	g_free( uuid );
 
 	return( items );
-}
+}*/
 
 /*
  * load and set the properties of the specified profile
  */
-static void
+/*static void
 load_profile_properties( NAGConf *gconf, NAActionProfile *profile )
 {
-	/*static const gchar *thisfn = "nacf_gconf_load_profile_properties";
+	*//*static const gchar *thisfn = "nacf_gconf_load_profile_properties";
 	g_debug( "%s: gconf=%p, profile=%p", thisfn, gconf, profile );*/
 
-	g_assert( NA_IS_GCONF( gconf ));
+/*	g_assert( NA_IS_GCONF( gconf ));
 	g_assert( NA_IS_ACTION_PROFILE( profile ));
 
 	NAAction *action =
@@ -497,27 +1065,7 @@ load_profile_properties( NAGConf *gconf, NAActionProfile *profile )
 	free_keys_values( properties );
 	g_free( path );
 	g_free( uuid );
-}
-
-/*
- * load the keys which are the subdirs of the given path
- * returns a list of keys as full path
- */
-static GSList *
-load_subdirs( const NAGConf *gconf, const gchar *path )
-{
-	static const gchar *thisfn = "na_gconf_load_subdirs";
-
-	GError *error = NULL;
-	GSList *list = gconf_client_all_dirs( gconf->private->gconf, path, &error );
-	if( error ){
-		g_warning( "%s: path=%s, error=%s", thisfn, path, error->message );
-		g_error_free( error );
-		return(( GSList * ) NULL );
-	}
-
-	return( list );
-}
+}*/
 
 /*
  * load all the key=value pairs of this key (specified as a full path),
@@ -525,7 +1073,7 @@ load_subdirs( const NAGConf *gconf, const gchar *path )
  * The list is not recursive, it contains only the immediate children of
  * path. To free the returned list, call free_key_values.
  */
-static GSList *
+/*static GSList *
 load_keys_values( const NAGConf *gconf, const gchar *path )
 {
 	static const gchar *thisfn = "na_gconf_load_keys_values";
@@ -550,27 +1098,13 @@ free_keys_values( GSList *list )
 		gconf_entry_unref( entry );
 	}
 	g_slist_free( list );
-}
-
-/*
- * extract the key part (the last part) of a full path
- * returns a newly allocated string which must be g_freed by the caller
- */
-static gchar *
-path_to_key( const gchar *path )
-{
-	gchar **split = g_strsplit( path, "/", -1 );
-	guint count = g_strv_length( split );
-	gchar *key = g_strdup( split[count-1] );
-	g_strfreev( split );
-	return( key );
-}
+}*/
 
 /*
  * set the item properties into the object
  * properties is a list of path to entry
  */
-static void
+/*static void
 set_item_properties( NAObject *object, GSList *properties )
 {
 	static const gchar *thisfn = "na_gconf_set_item_properties";
@@ -605,9 +1139,9 @@ set_item_properties( NAObject *object, GSList *properties )
 
 		na_pivot_free_notify( npn );
 	}
-}
+}*/
 
-static const gchar *
+/*static const gchar *
 key_to_property( const gchar *key )
 {
 	int i;
@@ -621,19 +1155,16 @@ key_to_property( const gchar *key )
 	}
 
 	return( property );
-}
+}*/
 
 /*
  * set the item properties into the action, dealing with successive
  * versions
  */
-static gboolean
+/*static gboolean
 set_action_properties( NAGConf *gconf, NAAction *action, GSList *properties )
 {
-	/*static const gchar *thisfn = "na_gconf_set_action_properties";*/
-
-	/* the last action version we handle here */
-	static const gchar *last_version = "2.0";
+	*//*static const gchar *thisfn = "na_gconf_set_action_properties";*//*
 
 	gchar *label = search_for_str( properties, NULL, ACTION_LABEL_ENTRY );
 	if( !label ){
@@ -645,11 +1176,11 @@ set_action_properties( NAGConf *gconf, NAAction *action, GSList *properties )
 	gchar *icon = search_for_str( properties, NULL, ACTION_ICON_ENTRY );
 
 	g_object_set( G_OBJECT( action ),
-			PROP_ACTION_VERSION_STR, last_version,
-			PROP_ACTION_LABEL_STR, label,
-			PROP_ACTION_TOOLTIP_STR, tooltip,
-			PROP_ACTION_ICON_STR, icon,
-			PROP_ACTION_PROVIDER_STR, gconf,
+			PROP_NAACTION_VERSION_STR, version,
+			PROP_NAACTION_LABEL_STR, label,
+			PROP_NAACTION_TOOLTIP_STR, tooltip,
+			PROP_NAACTION_ICON_STR, icon,
+			PROP_NAACTION_PROVIDER_STR, gconf,
 			NULL );
 
 	g_free( icon );
@@ -677,13 +1208,13 @@ set_action_properties( NAGConf *gconf, NAAction *action, GSList *properties )
 
 	g_free( version );
 	return( TRUE );
-}
+}*/
 
 /*
  * only handle one profile, which is already loaded
  * action+= path+parameters+basenames+isdir+isfile+multiple+schemes
  */
-static void
+/*static void
 load_v1_properties( NAAction *action, const gchar *version, GSList *properties )
 {
 	GSList *profiles = NULL;
@@ -698,13 +1229,13 @@ load_v1_properties( NAAction *action, const gchar *version, GSList *properties )
 	GSList *schemes = search_for_list( properties, NULL, ACTION_SCHEMES_ENTRY );
 
 	g_object_set( G_OBJECT( profile ),
-			PROP_PROFILE_PATH_STR, path,
-			PROP_PROFILE_PARAMETERS_STR, parameters,
-			PROP_PROFILE_BASENAMES_STR, basenames,
-			PROP_PROFILE_ISDIR_STR, isdir,
-			PROP_PROFILE_ISFILE_STR, isfile,
-			PROP_PROFILE_ACCEPT_MULTIPLE_STR, multiple,
-			PROP_PROFILE_SCHEMES_STR, schemes,
+			PROP_NAPROFILE_PATH_STR, path,
+			PROP_NAPROFILE_PARAMETERS_STR, parameters,
+			PROP_NAPROFILE_BASENAMES_STR, basenames,
+			PROP_NAPROFILE_ISDIR_STR, isdir,
+			PROP_NAPROFILE_ISFILE_STR, isfile,
+			PROP_NAPROFILE_ACCEPT_MULTIPLE_STR, multiple,
+			PROP_NAPROFILE_SCHEMES_STR, schemes,
 			NULL );
 
 	g_free( path );
@@ -713,17 +1244,17 @@ load_v1_properties( NAAction *action, const gchar *version, GSList *properties )
 	na_utils_free_string_list( schemes );
 
 	if( g_ascii_strcasecmp( version, "1.0" ) > 0 ){
-
+*/
 		/* handle matchcase+mimetypes
 		 * note that default values for 1.0 version have been set
 		 * in na_action_profile_instance_init
 		 */
-		gboolean matchcase = search_for_bool( properties, "", ACTION_MATCHCASE_ENTRY );
+		/*gboolean matchcase = search_for_bool( properties, "", ACTION_MATCHCASE_ENTRY );
 		GSList *mimetypes = search_for_list( properties, "", ACTION_MIMETYPES_ENTRY );
 
 		g_object_set( G_OBJECT( profile ),
-				PROP_PROFILE_MATCHCASE_STR, matchcase,
-				PROP_PROFILE_MIMETYPES_STR, mimetypes,
+				PROP_NAGCONF_PROFILE_MATCHCASE_STR, matchcase,
+				PROP_NAGCONF_PROFILE_MIMETYPES_STR, mimetypes,
 				NULL );
 
 		na_utils_free_string_list( mimetypes );
@@ -732,9 +1263,9 @@ load_v1_properties( NAAction *action, const gchar *version, GSList *properties )
 	profiles = g_slist_prepend( profiles, profile );
 	na_action_set_profiles( action, profiles );
 	na_action_free_profiles( profiles );
-}
+}*/
 
-static gchar *
+/*static gchar *
 search_for_str( GSList *properties, const gchar *profile, const gchar *key )
 {
 	GSList *ip;
@@ -777,15 +1308,12 @@ search_for_list( GSList *properties, const gchar *profile, const gchar *key )
 		}
 	}
 	return(( GSList * ) NULL );
-}
+}*/
 
 /*
- * load all the key=value pairs of this key (specified as a full path),
- * returning them as a list of GConfEntry.
- * The list is not recursive, it contains only the immediate children of
- * path. To free the returned list, call free_key_values.
+ * convet a list of GConfEntry to a list of NAPivotNotify.
  */
-static GSList *
+/*static GSList *
 keys_to_notify( GSList *entries )
 {
 	GSList *item;
@@ -798,7 +1326,7 @@ keys_to_notify( GSList *entries )
 	}
 
 	return( properties );
-}
+}*/
 
 /*
  * convert a GConfEntry to a structure suitable to notify NAPivot
@@ -817,10 +1345,10 @@ keys_to_notify( GSList *entries )
  * as the entry no more exists in GConf and thus cannot be tested
  * -> we will set this as key/parm, letting pivot try to interpret it
  */
-static NAPivotNotify *
+/*static NAPivotNotify *
 entry_to_notify( const GConfEntry *entry )
 {
-	/*static const gchar *thisfn = "na_gconf_entry_to_notify";*/
+	*//*static const gchar *thisfn = "na_gconf_entry_to_notify";*//*
 	GSList *listvalues, *iv, *strings;
 
 	g_assert( entry );
@@ -832,7 +1360,7 @@ entry_to_notify( const GConfEntry *entry )
 
 	const gchar *subpath = path + strlen( NA_GCONF_CONFIG_PATH ) + 1;
 	gchar **split = g_strsplit( subpath, "/", -1 );
-	/*g_debug( "%s: [0]=%s, [1]=%s", thisfn, split[0], split[1] );*/
+	*//*g_debug( "%s: [0]=%s, [1]=%s", thisfn, split[0], split[1] );*//*
 	npn->uuid = g_strdup( split[0] );
 	if( g_strv_length( split ) == 2 ){
 		npn->parm = g_strdup( split[1] );
@@ -866,7 +1394,7 @@ entry_to_notify( const GConfEntry *entry )
 
 				npn->type = NA_PIVOT_STRLIST;
 				npn->data = ( gpointer ) na_utils_duplicate_string_list( strings );
-				/*na_utils_free_string_list( strings );*/
+				*//*na_utils_free_string_list( strings );*//*
 				break;
 
 			default:
@@ -884,9 +1412,9 @@ free_list_notify( GSList *list )
 	for( il = list ; il ; il = il->next ){
 		na_pivot_free_notify(( NAPivotNotify *) il->data );
 	}
-}
+}*/
 
-static gboolean
+/*static gboolean
 remove_v1_keys( NAGConf *gconf, const NAAction *action, gchar **message )
 {
 	gchar *uuid = na_action_get_uuid( action );
@@ -904,9 +1432,9 @@ remove_v1_keys( NAGConf *gconf, const NAAction *action, gchar **message )
 
 	g_free( uuid );
 	return( ret );
-}
+}*/
 
-static gboolean
+/*static gboolean
 remove_key( NAGConf *gconf, const gchar *uuid, const gchar *key, gchar **message )
 {
 	gboolean ret = TRUE;
@@ -924,74 +1452,7 @@ remove_key( NAGConf *gconf, const gchar *uuid, const gchar *key, gchar **message
 
 	g_free( path );
 	return( ret );
-}
-
-static gboolean
-do_is_writable( NAIIOProvider *provider )
-{
-	return( TRUE );
-}
-
-static gboolean
-do_is_willing_to_write( NAIIOProvider *provider, const GObject *action )
-{
-	return( TRUE );
-}
-
-static guint
-do_write_action( NAIIOProvider *provider, const GObject *obj_action, gchar **message )
-{
-	static const gchar *thisfn = "nacf_gconf_do_write_action";
-	g_debug( "%s: provider=%p, action=%p, message=%p", thisfn, provider, obj_action, message );
-
-	g_assert( NA_IS_IIO_PROVIDER( provider ));
-	g_assert( NA_IS_GCONF( provider ));
-	NAGConf *self = NA_GCONF( provider );
-
-	message = NULL;
-
-	g_assert( NA_IS_ACTION( obj_action ));
-	NAAction *action = NA_ACTION( obj_action );
-
-	if( !write_v2_keys( self, action, message )){
-		return( NA_IIO_PROVIDER_WRITE_ERROR );
-	}
-
-	g_object_set( G_OBJECT( action ), PROP_ACTION_PROVIDER_STR, provider, NULL );
-
-	return( NA_IIO_PROVIDER_WRITE_OK );
-}
-
-static guint
-do_delete_action( NAIIOProvider *provider, const GObject *obj_action, gchar **message )
-{
-	static const gchar *thisfn = "nacf_gconf_do_delete_action";
-	g_debug( "%s: provider=%p, action=%p, message=%p", thisfn, provider, obj_action, message );
-
-	g_assert( NA_IS_IIO_PROVIDER( provider ));
-	g_assert( NA_IS_GCONF( provider ));
-	NAGConf *self = NA_GCONF( provider );
-
-	message = NULL;
-	guint ret = NA_IIO_PROVIDER_WRITE_OK;
-
-	g_assert( NA_IS_ACTION( obj_action ));
-	NAAction *action = NA_ACTION( obj_action );
-
-	gchar *uuid = na_action_get_uuid( action );
-	gchar *path = g_strdup_printf( "%s/%s", NA_GCONF_CONFIG_PATH, uuid );
-	GError *error = NULL;
-
-	if( !gconf_client_recursive_unset( self->private->gconf, path, 0, &error )){
-		*message = g_strdup( error->message );
-		g_error_free( error );
-		ret = NA_IIO_PROVIDER_WRITE_ERROR;
-	}
-
-	g_free( path );
-	g_free( uuid );
-	return( ret );
-}
+}*/
 
 /*
  * gconf_client_key_is_writable doesn't work as I expect: it returns
@@ -1207,8 +1668,8 @@ install_gconf_watched_dir( NAGConf *gconf )
 static void
 remove_gconf_watch( NAGConf *gconf )
 {
-	if( gconf->private->notify_id ){
-		gconf_client_notify_remove( gconf->private->gconf, gconf->private->notify_id );
+	if( gconf->private->watch_id ){
+		gconf_client_notify_remove( gconf->private->gconf, gconf->private->watch_id );
 	}
 
 	remove_gconf_watched_dir( gconf );
@@ -1255,6 +1716,7 @@ action_changed_cb( GConfClient *client, guint cnxn_id, GConfEntry *entry, gpoint
 
 	g_assert( NA_IS_GCONF( user_data ));
 	NAGConf *gconf = NA_GCONF( user_data );
+	g_assert( NA_IS_IIO_PROVIDER( gconf ));
 
 	NAPivotNotify *npn = entry_to_notify( entry );
 	g_signal_emit_by_name( gconf->private->notified, NA_IIO_PROVIDER_SIGNAL_ACTION_CHANGED, npn );
diff --git a/src/common/na-gconf.h b/src/common/na-gconf.h
index 23049ba..0a96487 100644
--- a/src/common/na-gconf.h
+++ b/src/common/na-gconf.h
@@ -31,10 +31,13 @@
 #ifndef __NA_GCONF_H__
 #define __NA_GCONF_H__
 
-/*
- * NAGConf class definition.
+/**
+ * SECTION: na_gconf
+ * @short_description: #NAGConf class definition.
+ * @include: common/na-gconf.h
  *
- * Implements the NactIIOProvider (I/O storage subsystem) interface.
+ * This class manages the GConf I/O storage subsystem.
+ * It should only be used through the NAIIOProvider interface.
  */
 
 #include <glib-object.h>
diff --git a/src/common/na-iduplicable.c b/src/common/na-iduplicable.c
new file mode 100644
index 0000000..33907e5
--- /dev/null
+++ b/src/common/na-iduplicable.c
@@ -0,0 +1,422 @@
+/*
+ * Nautilus Actions
+ * A Nautilus extension which offers configurable context menu actions.
+ *
+ * Copyright (C) 2005 The GNOME Foundation
+ * Copyright (C) 2006, 2007, 2008 Frederic Ruaudel and others (see AUTHORS)
+ * Copyright (C) 2009 Pierre Wieser and others (see AUTHORS)
+ *
+ * This Program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this Library; see the file COPYING.  If not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place,
+ * Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Authors:
+ *   Frederic Ruaudel <grumz grumz net>
+ *   Rodrigo Moya <rodrigo gnome-db org>
+ *   Pierre Wieser <pwieser trychlos org>
+ *   ... and many others (see AUTHORS)
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "na-iduplicable.h"
+
+/* private interface data
+ */
+struct NAIDuplicableInterfacePrivate {
+};
+
+/* data set against GObject
+ */
+#define PROP_IDUPLICABLE_ORIGIN			"na-iduplicable-origin"
+#define PROP_IDUPLICABLE_ISMODIFIED		"na-iduplicable-is-modified"
+#define PROP_IDUPLICABLE_ISVALID		"na-iduplicable-is-valid"
+
+static GType     register_type( void );
+static void      interface_base_init( NAIDuplicableInterface *klass );
+static void      interface_base_finalize( NAIDuplicableInterface *klass );
+
+static NAObject *v_duplicate( const NAObject *object );
+static gboolean  v_are_equal( const NAObject *a, const NAObject *b );
+static gboolean  v_is_valid( const NAObject *object );
+
+static NAObject *get_origin( const NAObject *object );
+static void      set_origin( const NAObject *object, const NAObject *origin );
+static gboolean  get_modified( const NAObject *object );
+static void      set_modified( const NAObject *object, gboolean is_modified );
+static gboolean  get_valid( const NAObject *object );
+static void      set_valid( const NAObject *object, gboolean is_valid );
+
+GType
+na_iduplicable_get_type( void )
+{
+	static GType iface_type = 0;
+
+	if( !iface_type ){
+		iface_type = register_type();
+	}
+
+	return( iface_type );
+}
+
+static GType
+register_type( void )
+{
+	static const gchar *thisfn = "na_iduplicable_register_type";
+	g_debug( "%s", thisfn );
+
+	static const GTypeInfo info = {
+		sizeof( NAIDuplicableInterface ),
+		( GBaseInitFunc ) interface_base_init,
+		( GBaseFinalizeFunc ) interface_base_finalize,
+		NULL,
+		NULL,
+		NULL,
+		0,
+		0,
+		NULL
+	};
+
+	GType type = g_type_register_static( G_TYPE_INTERFACE, "NAIDuplicable", &info, 0 );
+
+	g_type_interface_add_prerequisite( type, G_TYPE_OBJECT );
+
+	return( type );
+}
+
+static void
+interface_base_init( NAIDuplicableInterface *klass )
+{
+	static const gchar *thisfn = "na_iduplicable_interface_base_init";
+	static gboolean initialized = FALSE;
+
+	if( !initialized ){
+		g_debug( "%s: klass=%p", thisfn, klass );
+
+		klass->private = g_new0( NAIDuplicableInterfacePrivate, 1 );
+
+		initialized = TRUE;
+	}
+}
+
+static void
+interface_base_finalize( NAIDuplicableInterface *klass )
+{
+	static const gchar *thisfn = "na_iduplicable_interface_base_finalize";
+	static gboolean finalized = FALSE ;
+
+	if( !finalized ){
+		g_debug( "%s: klass=%p", thisfn, klass );
+
+		g_free( klass->private );
+
+		finalized = TRUE;
+	}
+}
+
+/**
+ * na_iduplicable_init:
+ * @object: the #NAObject object to be initialized.
+ *
+ * Initializes the properties of a IDuplicable object.
+ *
+ * This function should be called when creating the object, e.g. from
+ * instance_init().
+ */
+void
+na_iduplicable_init( NAObject *object )
+{
+	g_assert( NA_IS_OBJECT( object ));
+	g_assert( NA_IS_IDUPLICABLE( object ));
+
+	set_origin( object, NULL );
+	set_modified( object, FALSE );
+	set_valid( object, TRUE );
+}
+
+/**
+ * na_iduplicable_dump:
+ * @object: the #NAObject object to be duplicated.
+ *
+ * Dumps via g_debug the properties of the object.
+ */
+void
+na_iduplicable_dump( const NAObject *object )
+{
+	static const gchar *thisfn = "na_iduplicable_dump";
+
+	NAObject *origin = NULL;
+	gboolean modified = FALSE;
+	gboolean valid = TRUE;
+
+	if( object ){
+		g_assert( NA_IS_OBJECT( object ));
+		g_assert( NA_IS_IDUPLICABLE( object ));
+
+		origin = get_origin( object );
+		modified = get_modified( object );
+		valid = get_valid( object );
+	}
+
+	g_debug( "%s:   origin=%p", thisfn, origin );
+	g_debug( "%s: modified=%s", thisfn, modified ? "True" : "False" );
+	g_debug( "%s:    valid=%s", thisfn, valid ? "True" : "False" );
+}
+
+/**
+ * na_iduplicable_duplicate:
+ * @object: the #NAObject object to be duplicated.
+ *
+ * Exactly duplicates a #NAObject-derived object.
+ * Properties %PROP_IDUPLICABLE_ORIGIN, %PROP_IDUPLICABLE_ISMODIFIED
+ * and %PROP_IDUPLICABLE_ISVALID are initialized to their default
+ * values.
+ *
+ * As %PROP_IDUPLICABLE_ISVALID property is set to %TRUE without any
+ * further check, this suppose that only valid objects are duplicated.
+ *
+ * Returns: a new #NAObject.
+ */
+NAObject *
+na_iduplicable_duplicate( const NAObject *object )
+{
+	static const gchar *thisfn = "na_iduplicable_duplicate";
+	g_debug( "%s: object=%p", thisfn, object );
+
+	NAObject *dup = NULL;
+
+	if( object ){
+		g_assert( NA_IS_OBJECT( object ));
+		g_assert( NA_IS_IDUPLICABLE( object ));
+
+		dup = v_duplicate( object );
+
+		set_origin( dup, object );
+		set_modified( dup, FALSE );
+		set_valid( dup, TRUE );
+	}
+
+	return( dup );
+}
+
+/**
+ * na_iduplicable_check_edited_status:
+ * @object: the #NAObject object to be checked.
+ *
+ * Checks the edition status of the #NAObject object, and set up the
+ * corresponding %PROP_IDUPLICABLE_ISMODIFIED and
+ * %PROP_IDUPLICABLE_ISVALID properties.
+ *
+ * This function is supposed to be called each time the object may have
+ * been modified in order to set these properties. Helper functions
+ * na_iduplicable_is_modified() and na_iduplicable_is_valid() will
+ * then only return the current value of the properties.
+ */
+void
+na_iduplicable_check_edited_status( const NAObject *object )
+{
+	/*static const gchar *thisfn = "na_iduplicable_check_edited_status";
+	g_debug( "%s: object=%p", thisfn, object );*/
+
+	if( object ){
+		g_assert( NA_IS_OBJECT( object ));
+		g_assert( NA_IS_IDUPLICABLE( object ));
+
+		gboolean modified = TRUE;
+		NAObject *origin = get_origin( object );
+		if( origin ){
+			modified = !v_are_equal( object, origin );
+		}
+		set_modified( object, modified );
+
+		gboolean valid = v_is_valid( object );
+		set_valid( object, valid );
+	}
+}
+
+/**
+ * na_iduplicable_is_modified:
+ * @object: the #NAObject object whose status is to be returned.
+ *
+ * Returns the current value of the %PROP_IDUPLICABLE_ISMODIFIED
+ * property without rechecking the edition status itself.
+ *
+ * Returns: %TRUE is the provided object has been modified regarding of
+ * the original one.
+ */
+gboolean
+na_iduplicable_is_modified( const NAObject *object )
+{
+	/*static const gchar *thisfn = "na_iduplicable_is_modified";
+	g_debug( "%s: object=%p", thisfn, object );*/
+
+	gboolean is_modified = FALSE;
+
+	if( object ){
+		g_assert( NA_IS_OBJECT( object ));
+		g_assert( NA_IS_IDUPLICABLE( object ));
+
+		is_modified = get_modified( object );
+	}
+
+	return( is_modified );
+}
+
+/**
+ * na_iduplicable_is_valid:
+ * @object: the #NAObject object whose status is to be returned.
+ *
+ * Returns the current value of the %PROP_IDUPLICABLE_ISVALID property
+ * without rechecking the edition status itself.
+ *
+ * Returns: %TRUE is the provided object is valid.
+ */
+gboolean
+na_iduplicable_is_valid( const NAObject *object )
+{
+	/*static const gchar *thisfn = "na_iduplicable_is_valid";
+	g_debug( "%s: object=%p", thisfn, object );*/
+
+	gboolean is_valid = FALSE;
+
+	if( object ){
+		g_assert( NA_IS_OBJECT( object ));
+		g_assert( NA_IS_IDUPLICABLE( object ));
+
+		is_valid = get_valid( object );
+	}
+
+	return( is_valid );
+}
+
+/**
+ * na_iduplicable_get_origin:
+ * @object: the #NAObject object whose origin is to be returned.
+ *
+ * Returns the origin of a duplicated #NAObject.
+ *
+ * Returns: the original #NAObject, or NULL.
+ */
+NAObject *
+na_iduplicable_get_origin( const NAObject *object )
+{
+	/*static const gchar *thisfn = "na_iduplicable_is_valid";
+	g_debug( "%s: object=%p", thisfn, object );*/
+
+	NAObject *origin = NULL;
+
+	if( object ){
+		g_assert( NA_IS_OBJECT( object ));
+		g_assert( NA_IS_IDUPLICABLE( object ));
+
+		origin = get_origin( object );
+	}
+
+	return( origin );
+}
+
+/**
+ * na_iduplicable_set_origin:
+ * @object: the #NAObject object whose origin is to be returned.
+ * @origin: the new original #NAObject.
+ *
+ * Sets the new origin of a duplicated #NAObject.
+ */
+void
+na_iduplicable_set_origin( NAObject *object, const NAObject *origin )
+{
+	/*static const gchar *thisfn = "na_iduplicable_is_valid";
+	g_debug( "%s: object=%p", thisfn, object );*/
+
+	if( object ){
+		g_assert( NA_IS_OBJECT( object ));
+		g_assert( NA_IS_IDUPLICABLE( object ));
+
+		set_origin( object, origin );
+	}
+}
+
+static NAObject *
+v_duplicate( const NAObject *object )
+{
+	NAIDuplicable *instance = NA_IDUPLICABLE( object );
+
+	if( NA_IDUPLICABLE_GET_INTERFACE( instance )->duplicate ){
+		return( NA_IDUPLICABLE_GET_INTERFACE( instance )->duplicate( object ));
+	}
+
+	return( NULL );
+}
+
+static gboolean
+v_are_equal( const NAObject *a, const NAObject *b )
+{
+	NAIDuplicable *instance = NA_IDUPLICABLE( a );
+
+	if( NA_IDUPLICABLE_GET_INTERFACE( instance )->are_equal ){
+		return( NA_IDUPLICABLE_GET_INTERFACE( instance )->are_equal( a, b ));
+	}
+
+	return( TRUE );
+}
+
+static gboolean
+v_is_valid( const NAObject *object )
+{
+	NAIDuplicable *instance = NA_IDUPLICABLE( object );
+
+	if( NA_IDUPLICABLE_GET_INTERFACE( instance )->is_valid ){
+		return( NA_IDUPLICABLE_GET_INTERFACE( instance )->is_valid( object ));
+	}
+
+	return( TRUE );
+}
+
+static NAObject *
+get_origin( const NAObject *object )
+{
+	return( NA_OBJECT( g_object_get_data( G_OBJECT( object ), PROP_IDUPLICABLE_ORIGIN )));
+}
+
+static void
+set_origin( const NAObject *object, const NAObject *origin )
+{
+	g_object_set_data( G_OBJECT( object ), PROP_IDUPLICABLE_ORIGIN, ( gpointer ) origin );
+}
+
+static gboolean
+get_modified( const NAObject *object )
+{
+	return(( gboolean ) GPOINTER_TO_UINT( g_object_get_data( G_OBJECT( object ), PROP_IDUPLICABLE_ISMODIFIED )));
+}
+
+static void
+set_modified( const NAObject *object, gboolean is_modified )
+{
+	g_object_set_data( G_OBJECT( object ), PROP_IDUPLICABLE_ISMODIFIED, GUINT_TO_POINTER( is_modified ));
+}
+
+static gboolean
+get_valid( const NAObject *object )
+{
+	return(( gboolean ) GPOINTER_TO_UINT( g_object_get_data( G_OBJECT( object ), PROP_IDUPLICABLE_ISVALID )));
+}
+
+static void
+set_valid( const NAObject *object, gboolean is_valid )
+{
+	g_object_set_data( G_OBJECT( object ), PROP_IDUPLICABLE_ISVALID, GUINT_TO_POINTER( is_valid ));
+}
diff --git a/src/common/na-iduplicable.h b/src/common/na-iduplicable.h
new file mode 100644
index 0000000..0536b46
--- /dev/null
+++ b/src/common/na-iduplicable.h
@@ -0,0 +1,129 @@
+/*
+ * Nautilus Actions
+ * A Nautilus extension which offers configurable context menu actions.
+ *
+ * Copyright (C) 2005 The GNOME Foundation
+ * Copyright (C) 2006, 2007, 2008 Frederic Ruaudel and others (see AUTHORS)
+ * Copyright (C) 2009 Pierre Wieser and others (see AUTHORS)
+ *
+ * This Program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this Library; see the file COPYING.  If not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place,
+ * Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Authors:
+ *   Frederic Ruaudel <grumz grumz net>
+ *   Rodrigo Moya <rodrigo gnome-db org>
+ *   Pierre Wieser <pwieser trychlos org>
+ *   ... and many others (see AUTHORS)
+ */
+
+#ifndef __NACT_IDUPLICABLE_H__
+#define __NACT_IDUPLICABLE_H__
+
+/**
+ * SECTION: na_iduplicable
+ * @short_description: #NAObject IDuplicable interface.
+ * @include: common/na-iduplicable.h
+ *
+ * This interface is implemented by #NAObject in order to let
+ * #NAObject-derived instance duplication be easily tracked. This works
+ * by keeping a pointer on the original object at duplication time, and
+ * then only checking status when explictely required.
+ *
+ * As the reference count of the original object is not incremented
+ * here, the caller has to garantee himself that the original object
+ * will stay in life at least as long as the duplicated one.
+ */
+
+#include "na-object.h"
+
+G_BEGIN_DECLS
+
+#define NA_IDUPLICABLE_TYPE							( na_iduplicable_get_type())
+#define NA_IDUPLICABLE( object )					( G_TYPE_CHECK_INSTANCE_CAST( object, NA_IDUPLICABLE_TYPE, NAIDuplicable ))
+#define NA_IS_IDUPLICABLE( object )					( G_TYPE_CHECK_INSTANCE_TYPE( object, NA_IDUPLICABLE_TYPE ))
+#define NA_IDUPLICABLE_GET_INTERFACE( instance )	( G_TYPE_INSTANCE_GET_INTERFACE(( instance ), NA_IDUPLICABLE_TYPE, NAIDuplicableInterface ))
+
+typedef struct NAIDuplicable NAIDuplicable;
+
+typedef struct NAIDuplicableInterfacePrivate NAIDuplicableInterfacePrivate;
+
+typedef struct {
+	GTypeInterface                 parent;
+	NAIDuplicableInterfacePrivate *private;
+
+	/**
+	 * duplicate:
+	 * @object: the #NAObject object to be duplicated.
+	 *
+	 * Allocates an exact copy of the specified #NAObject object.
+	 *
+	 * The implementor should define a duplicate()-equivalent virtual
+	 * function in order the new #NAObject-derived object be allocated
+	 * with the right most-derived class.
+	 *
+	 * The implementor should also define a copy()-equivalent virtual
+	 * function so that each class in the derivation hierarchy be able
+	 * to copy its own data and properties to the target instance.
+	 *
+	 * Returns: a newly allocated #NAObject object, which is an exact
+	 * copy of @object.
+	 */
+	NAObject * ( *duplicate )( const NAObject *object );
+
+	/**
+	 * are_equal:
+	 * @a: a first #NAObject object.
+	 * @b: a second #NAObject object to be compared to the first one.
+	 *
+	 * Compares the two objects.
+	 *
+	 * The implementor should define a are_equal()-equivalent virtual
+	 * function so that each #NAObject-derived class be able to check
+	 * for identity.
+	 *
+	 * Returns: %TRUE if @a and @b are identical, %FALSE else.
+	 */
+	gboolean   ( *are_equal )( const NAObject *a, const NAObject *b );
+
+	/**
+	 * is_valid:
+	 * @object: the #NAObject object to be checked.
+	 *
+	 * Checks @object for validity.
+	 *
+	 * The implementor should define a is_valid()-equivalent virtual
+	 * function so that each #NAObject-derived class be able to check
+	 * for validity.
+	 *
+	 * Returns: %TRUE if @object is valid, %FALSE else.
+	 */
+	gboolean   ( *is_valid ) ( const NAObject *object );
+}
+	NAIDuplicableInterface;
+
+GType     na_iduplicable_get_type( void );
+
+void      na_iduplicable_init( NAObject *object );
+void      na_iduplicable_dump( const NAObject *object );
+NAObject *na_iduplicable_duplicate( const NAObject *object );
+void      na_iduplicable_check_edited_status( const NAObject *object );
+gboolean  na_iduplicable_is_modified( const NAObject *object );
+gboolean  na_iduplicable_is_valid( const NAObject *object );
+NAObject *na_iduplicable_get_origin( const NAObject *object );
+void      na_iduplicable_set_origin( NAObject *object, const NAObject *origin );
+
+G_END_DECLS
+
+#endif /* __NA_IDUPLICABLE_H__ */
diff --git a/src/common/na-iio-provider.c b/src/common/na-iio-provider.c
index f27b911..6cf10f9 100644
--- a/src/common/na-iio-provider.c
+++ b/src/common/na-iio-provider.c
@@ -33,11 +33,10 @@
 #endif
 
 #include <glib.h>
+#include <glib/gi18n.h>
 
 #include "na-action.h"
-#include "na-action-profile.h"
 #include "na-iio-provider.h"
-#include "na-pivot.h"
 
 /* private interface data
  */
@@ -48,8 +47,9 @@ static GType    register_type( void );
 static void     interface_base_init( NAIIOProviderInterface *klass );
 static void     interface_base_finalize( NAIIOProviderInterface *klass );
 
-static gboolean do_is_writable( NAIIOProvider *instance );
-static gboolean do_is_willing_to_write( NAIIOProvider *instance, const GObject *action );
+static gboolean do_is_willing_to_write( const NAIIOProvider *instance );
+static gboolean do_is_writable( const NAIIOProvider *instance, const NAAction *action );
+static guint    write_action( const NAIIOProvider *instance, NAAction *action, gchar **message );
 
 /**
  * Registers the GType of this interface.
@@ -103,9 +103,10 @@ interface_base_init( NAIIOProviderInterface *klass )
 		klass->private = g_new0( NAIIOProviderInterfacePrivate, 1 );
 
 		klass->read_actions = NULL;
-		klass->is_writable = do_is_writable;
 		klass->is_willing_to_write = do_is_willing_to_write;
+		klass->is_writable = do_is_writable;
 		klass->write_action = NULL;
+		klass->delete_action = NULL;
 
 		initialized = TRUE;
 	}
@@ -127,24 +128,28 @@ interface_base_finalize( NAIIOProviderInterface *klass )
 }
 
 /**
- * Loads the actions defined in the system.
+ * na_iio_provider_read_actions:
+ * @pivot: the #NAPivot object which owns the list of registered I/O
+ * storage providers.
+ *
+ * Loads the actions from storage subsystems.
  *
- * @object: the pivot object which owns the list of registered
- * interface providers.
+ * Returns: a #GSList of newly allocated #NAAction objects.
  *
- * Returns a GSList of newly allocated NAAction objects.
+ * na_iio_provider_read_actions() loads the list of #NAAction from each
+ * registered I/O storage provider, and takes care of concatenating
+ * them into the returned global list.
  */
 GSList *
-na_iio_provider_read_actions( const GObject *object )
+na_iio_provider_read_actions( const NAPivot *pivot )
 {
 	static const gchar *thisfn = "na_iio_provider_read_actions";
-	g_debug( "%s", thisfn );
+	g_debug( "%s: pivot=%p", thisfn, pivot );
 
-	g_assert( NA_IS_PIVOT( object ));
-	NAPivot *pivot = NA_PIVOT( object );
+	g_assert( NA_IS_PIVOT( pivot ));
 
 	GSList *actions = NULL;
-	GSList *ip, *il;
+	GSList *ip;
 	GSList *list;
 	NAIIOProvider *instance;
 
@@ -157,59 +162,54 @@ na_iio_provider_read_actions( const GObject *object )
 
 			list = NA_IIO_PROVIDER_GET_INTERFACE( instance )->read_actions( instance );
 
-			for( il = list ; il ; il = il->next ){
-				g_object_set_data( G_OBJECT( il->data ), "provider", instance );
+			GSList *ia;
+			for( ia = list ; ia ; ia = ia->next ){
+
+				na_action_set_provider( NA_ACTION( ia->data ), instance );
+
+				na_object_dump( NA_OBJECT( ia->data ));
 			}
 
 			actions = g_slist_concat( actions, list );
 		}
 	}
 
-#ifdef NACT_MAINTAINER_MODE
-	for( ip = actions ; ip ; ip = ip->next ){
-		na_object_dump( NA_OBJECT( ip->data ));
-	}
-#endif
-
 	return( actions );
 }
 
 /**
- * Writes an action to a willing-to storage subsystem.
- *
- * @obj_pivot: the pivot object which owns the list of registered
- * interface providers.
- *
- * @obj_action: the action to be written.
- *
+ * na_iio_provider_write_action:
+ * @pivot: the #NAPivot object which owns the list of registered I/O
+ * storage providers.
+ * @action: the #NAAction action to be written.
  * @message: the I/O provider can allocate and store here an error
  * message.
  *
- * Returns the IIOProvider return code.
+ * Writes an action to a willing-to storage subsystem.
+ *
+ * Returns: the NAIIOProvider return code.
  */
 guint
-na_iio_provider_write_action( const GObject *obj_pivot, const GObject *obj_action, gchar **message )
+na_iio_provider_write_action( const NAPivot *pivot, NAAction *action, gchar **message )
 {
 	static const gchar *thisfn = "na_iio_provider_write_action";
-	g_debug( "%s", thisfn );
-
-	g_assert( NA_IS_PIVOT( obj_pivot ));
-	NAPivot *pivot = NA_PIVOT( obj_pivot );
+	g_debug( "%s: pivot=%p, action=%p, message=%p", thisfn, pivot, action, message );
 
-	g_assert( NA_IS_ACTION( obj_action ));
+	g_assert( NA_IS_PIVOT( pivot ));
+	g_assert( NA_IS_ACTION( action ));
 
 	guint ret = NA_IIO_PROVIDER_NOT_WRITABLE;
-	NAIIOProvider *instance = NA_IIO_PROVIDER( na_action_get_provider( NA_ACTION( obj_action )));
 
 	/* try to write to the original provider of the action
 	 */
+	NAIIOProvider *instance = NA_IIO_PROVIDER( na_action_get_provider( action ));
+
 	if( instance ){
-		g_assert( NA_IS_IIO_PROVIDER( instance ));
-		if( NA_IIO_PROVIDER_GET_INTERFACE( instance )->write_action ){
-			ret = NA_IIO_PROVIDER_GET_INTERFACE( instance )->write_action( instance, obj_action, message );
-		} else {
-			instance = NULL;
-		}
+		ret = write_action( instance, action, message );
+	}
+
+	if( ret == NA_IIO_PROVIDER_NOT_WILLING_TO_WRITE || ret == NA_IIO_PROVIDER_NOT_WRITABLE ){
+		instance = NULL;
 	}
 
 	/* else, search for a provider which is willing to write the action
@@ -217,15 +217,12 @@ na_iio_provider_write_action( const GObject *obj_pivot, const GObject *obj_actio
 	if( !instance ){
 		GSList *providers = na_pivot_get_providers( pivot, NA_IIO_PROVIDER_TYPE );
 		GSList *ip;
-
 		for( ip = providers ; ip ; ip = ip->next ){
-			instance = NA_IIO_PROVIDER( ip->data );
-			if( NA_IIO_PROVIDER_GET_INTERFACE( instance )->write_action ){
 
-				ret = NA_IIO_PROVIDER_GET_INTERFACE( instance )->write_action( instance, obj_action, message );
-				if( ret == NA_IIO_PROVIDER_WRITE_OK || ret == NA_IIO_PROVIDER_WRITE_ERROR ){
-					break;
-				}
+			instance = NA_IIO_PROVIDER( ip->data );
+			ret = write_action( instance, action, message );
+			if( ret == NA_IIO_PROVIDER_WRITE_OK || ret == NA_IIO_PROVIDER_WRITE_ERROR ){
+				break;
 			}
 		}
 	}
@@ -234,49 +231,84 @@ na_iio_provider_write_action( const GObject *obj_pivot, const GObject *obj_actio
 }
 
 /**
- * Deletes an action from the storage subsystem.
- *
- * @obj_pivot: the pivot object which owns the list of registered
- * interface providers.
- *
- * @obj_action: the action to be deleted.
- *
+ * na_iio_provider_delete_action:
+ * @pivot: the #NAPivot object which owns the list of registered I/O
+ * storage providers.
+ * @action: the #NAAction action to be written.
  * @message: the I/O provider can allocate and store here an error
  * message.
  *
- * Returns the IIOProvider return code.
+ * Deletes an action from the storage subsystem.
+ *
+ * Returns: the NAIIOProvider return code.
+ *
+ * Note that a new action, not already written to an I/O subsystem,
+ * doesn't have any attached provider. We so do nothing...
  */
 guint
-na_iio_provider_delete_action( const GObject *obj_pivot, const GObject *obj_action, gchar **message )
+na_iio_provider_delete_action( const NAPivot *pivot, const NAAction *action, gchar **message )
 {
 	static const gchar *thisfn = "na_iio_provider_delete_action";
-	g_debug( "%s: pivot=%p, action=%p, message=%p", thisfn, obj_pivot, obj_action, message );
+	g_debug( "%s: pivot=%p, action=%p, message=%p", thisfn, pivot, action, message );
+
+	g_assert( NA_IS_PIVOT( pivot ));
+	g_assert( NA_IS_ACTION( action ));
 
-	g_assert( NA_IS_ACTION( obj_action ));
 	guint ret = NA_IIO_PROVIDER_NOT_WRITABLE;
+	NAIIOProvider *instance = NA_IIO_PROVIDER( na_action_get_provider( action ));
 
-	NAIIOProvider *instance = NA_IIO_PROVIDER( na_action_get_provider( NA_ACTION( obj_action )));
 	if( instance ){
 		g_assert( NA_IS_IIO_PROVIDER( instance ));
 
 		if( NA_IIO_PROVIDER_GET_INTERFACE( instance )->delete_action ){
-			ret = NA_IIO_PROVIDER_GET_INTERFACE( instance )->delete_action( instance, obj_action, message );
+			ret = NA_IIO_PROVIDER_GET_INTERFACE( instance )->delete_action( instance, action, message );
 		}
-	} else {
-		g_assert_not_reached();
+	/*} else {
+		*message = g_strdup( _( "Unable to delete the action: no I/O provider." ));
+		ret = NA_IIO_PROVIDER_NO_PROVIDER;*/
 	}
 
 	return( ret );
 }
 
 static gboolean
-do_is_writable( NAIIOProvider *instance )
+do_is_willing_to_write( const NAIIOProvider *instance )
 {
 	return( FALSE );
 }
 
 static gboolean
-do_is_willing_to_write( NAIIOProvider *instance, const GObject *action )
+do_is_writable( const NAIIOProvider *instance, const NAAction *action )
 {
 	return( FALSE );
 }
+
+static guint
+write_action( const NAIIOProvider *provider, NAAction *action, gchar **message )
+{
+	static const gchar *thisfn = "na_iio_provider_write_action";
+	g_debug( "%s: provider=%p, action=%p, message=%p", thisfn, provider, action, message );
+
+	if( !NA_IIO_PROVIDER_GET_INTERFACE( provider )->is_willing_to_write( provider )){
+		return( NA_IIO_PROVIDER_NOT_WILLING_TO_WRITE );
+	}
+
+	if( !NA_IIO_PROVIDER_GET_INTERFACE( provider )->is_writable( provider, action )){
+		return( NA_IIO_PROVIDER_NOT_WRITABLE );
+	}
+
+	if( !NA_IIO_PROVIDER_GET_INTERFACE( provider )->delete_action ){
+		return( NA_IIO_PROVIDER_NOT_WILLING_TO_WRITE );
+	}
+
+	guint ret = NA_IIO_PROVIDER_GET_INTERFACE( provider )->delete_action( provider, action, message );
+	if( ret != NA_IIO_PROVIDER_WRITE_OK ){
+		return( ret );
+	}
+
+	if( !NA_IIO_PROVIDER_GET_INTERFACE( provider )->write_action ){
+		return( NA_IIO_PROVIDER_NOT_WILLING_TO_WRITE );
+	}
+
+	return( NA_IIO_PROVIDER_GET_INTERFACE( provider )->write_action( provider, action, message ));
+}
diff --git a/src/common/na-iio-provider.h b/src/common/na-iio-provider.h
index 4c691cc..728031b 100644
--- a/src/common/na-iio-provider.h
+++ b/src/common/na-iio-provider.h
@@ -31,11 +31,13 @@
 #ifndef __NA_IIO_PROVIDER_H__
 #define __NA_IIO_PROVIDER_H__
 
-/*
- * NAIIOProvider interface definition.
+/**
+ * SECTION: na_iio_provider
+ * @short_description: #NAIIOProvider interface definition.
+ * @include: common/na-iio-provider.h
  *
  * This is the API all storage subsystems should implement in order to
- * provide i/o resources to NautilusActions.
+ * provide I/O resources to NautilusActions.
  *
  * In a near or far future, provider subsystems may be extended by
  * creating extension libraries, this class loading the modules at
@@ -44,6 +46,8 @@
 
 #include <glib-object.h>
 
+#include "na-pivot.h"
+
 G_BEGIN_DECLS
 
 #define NA_IIO_PROVIDER_TYPE						( na_iio_provider_get_type())
@@ -51,7 +55,7 @@ G_BEGIN_DECLS
 #define NA_IS_IIO_PROVIDER( object )				( G_TYPE_CHECK_INSTANCE_TYPE( object, NA_IIO_PROVIDER_TYPE ))
 #define NA_IIO_PROVIDER_GET_INTERFACE( instance )	( G_TYPE_INSTANCE_GET_INTERFACE(( instance ), NA_IIO_PROVIDER_TYPE, NAIIOProviderInterface ))
 
-typedef struct NAIIOProvider NAIIOProvider;
+typedef struct NAIIOProvider                 NAIIOProvider;
 
 typedef struct NAIIOProviderInterfacePrivate NAIIOProviderInterfacePrivate;
 
@@ -59,33 +63,89 @@ typedef struct {
 	GTypeInterface                 parent;
 	NAIIOProviderInterfacePrivate *private;
 
-	/* i/o api */
-	GSList * ( *read_actions )       ( NAIIOProvider *instance );
-	gboolean ( *is_writable )        ( NAIIOProvider *instance );
-	gboolean ( *is_willing_to_write )( NAIIOProvider *instance, const GObject *action );
-	guint    ( *write_action )       ( NAIIOProvider *instance, const GObject *action, gchar **message );
-	guint    ( *delete_action )      ( NAIIOProvider *instance, const GObject *action, gchar **message );
+	/**
+	 * read_actions:
+	 * @instance: the #NAIIOProvider provider.
+	 *
+	 * Reads actions from the specified I/O provider.
+	 *
+	 * Returns: a #GSList of #NAAction actions.
+	 */
+	GSList * ( *read_actions )       ( const NAIIOProvider *instance );
+
+	/**
+	 * is_willing_to_write:
+	 * @instance: the #NAIIOProvider provider.
+	 *
+	 * Checks for global writability of the I/O provider.
+	 *
+	 * Returns: %TRUE if we are able to update/write/delete a #NAAction
+	 * into this I/O provider, %FALSE else.
+	 *
+	 * Note that the I/O provider may return a positive writability
+	 * flag when considering the whole I/O storage subsystem, while not
+	 * being able to update/write/delete a particular #NAAction.
+	 */
+	gboolean ( *is_willing_to_write )( const NAIIOProvider *instance );
+
+	/**
+	 * is_writable:
+	 * @instance: the #NAIIOProvider provider.
+	 * @action: a #NAAction action.
+	 *
+	 * Checks for writability of this particular #NAAction.
+	 *
+	 * Returns: %TRUE if we are able to update/write/delete the
+	 * #NAAction, %FALSE else.
+	 */
+	gboolean ( *is_writable )        ( const NAIIOProvider *instance, const NAAction *action );
+
+	/**
+	 * write_action:
+	 * @instance: the #NAIIOProvider provider.
+	 * @action: a #NAAction action.
+	 * @message: warning/error messages detected in the operation.
+	 *
+	 * Updates an existing #NAAction or write a new #NAAction.
+	 *
+	 * Returns: %NA_IIO_PROVIDER_WRITE_OK if the update/write operation
+	 * was successfull, or another code depending of the detected error.
+	 */
+	guint    ( *write_action )       ( const NAIIOProvider *instance, NAAction *action, gchar **message );
+
+	/**
+	 * delete_action:
+	 * @instance: the #NAIIOProvider provider.
+	 * @action: a #NAAction action.
+	 * @message: warning/error messages detected in the operation.
+	 *
+	 * Deletes an existing #NAAction from the I/O subsystem.
+	 *
+	 * Returns: %NA_IIO_PROVIDER_WRITE_OK if the delete operation was
+	 * successfull, or another code depending of the detected error.
+	 */
+	guint    ( *delete_action )      ( const NAIIOProvider *instance, const NAAction *action, gchar **message );
 }
 	NAIIOProviderInterface;
 
-GType    na_iio_provider_get_type( void );
-
-GSList  *na_iio_provider_read_actions( const GObject *pivot );
+GType   na_iio_provider_get_type( void );
 
-guint    na_iio_provider_write_action( const GObject *pivot, const GObject *action, gchar **message );
-guint    na_iio_provider_delete_action( const GObject *pivot, const GObject *action, gchar **message );
+GSList *na_iio_provider_read_actions( const NAPivot *pivot );
+guint   na_iio_provider_write_action( const NAPivot *pivot, NAAction *action, gchar **message );
+guint   na_iio_provider_delete_action( const NAPivot *pivot, const NAAction *action, gchar **message );
 
 /* modification notification message to NAPivot
  */
 #define NA_IIO_PROVIDER_SIGNAL_ACTION_CHANGED		"notify_pivot_of_action_changed"
 
-/* return code of write_action function
+/* return code of update/write/delete operations
  */
 enum {
 	NA_IIO_PROVIDER_WRITE_OK = 0,
 	NA_IIO_PROVIDER_NOT_WRITABLE,
 	NA_IIO_PROVIDER_NOT_WILLING_TO_WRITE,
-	NA_IIO_PROVIDER_WRITE_ERROR
+	NA_IIO_PROVIDER_WRITE_ERROR,
+	NA_IIO_PROVIDER_NO_PROVIDER,
 };
 
 G_END_DECLS
diff --git a/src/common/na-ipivot-container.c b/src/common/na-ipivot-consumer.c
similarity index 63%
rename from src/common/na-ipivot-container.c
rename to src/common/na-ipivot-consumer.c
index 8b323ca..e0e2ec2 100644
--- a/src/common/na-ipivot-container.c
+++ b/src/common/na-ipivot-consumer.c
@@ -34,24 +34,24 @@
 
 #include <glib.h>
 
-#include "na-ipivot-container.h"
+#include "na-ipivot-consumer.h"
 
 /* private interface data
  */
-struct NAIPivotContainerInterfacePrivate {
+struct NAIPivotConsumerInterfacePrivate {
 };
 
 static GType register_type( void );
-static void  interface_base_init( NAIPivotContainerInterface *klass );
-static void  interface_base_finalize( NAIPivotContainerInterface *klass );
+static void  interface_base_init( NAIPivotConsumerInterface *klass );
+static void  interface_base_finalize( NAIPivotConsumerInterface *klass );
 
-/*static void  do_actions_changed( NAIPivotContainer *instance, gpointer user_data );*/
+/*static void  do_actions_changed( NAIPivotConsumer *instance, gpointer user_data );*/
 
 /**
  * Registers the GType of this interface.
  */
 GType
-na_ipivot_container_get_type( void )
+na_ipivot_consumer_get_type( void )
 {
 	static GType object_type = 0;
 
@@ -65,11 +65,11 @@ na_ipivot_container_get_type( void )
 static GType
 register_type( void )
 {
-	static const gchar *thisfn = "na_ipivot_container_register_type";
+	static const gchar *thisfn = "na_ipivot_consumer_register_type";
 	g_debug( "%s", thisfn );
 
 	static const GTypeInfo info = {
-		sizeof( NAIPivotContainerInterface ),
+		sizeof( NAIPivotConsumerInterface ),
 		( GBaseInitFunc ) interface_base_init,
 		( GBaseFinalizeFunc ) interface_base_finalize,
 		NULL,
@@ -80,7 +80,7 @@ register_type( void )
 		NULL
 	};
 
-	GType type = g_type_register_static( G_TYPE_INTERFACE, "NAIPivotContainer", &info, 0 );
+	GType type = g_type_register_static( G_TYPE_INTERFACE, "NAIPivotConsumer", &info, 0 );
 
 	g_type_interface_add_prerequisite( type, G_TYPE_OBJECT );
 
@@ -88,15 +88,15 @@ register_type( void )
 }
 
 static void
-interface_base_init( NAIPivotContainerInterface *klass )
+interface_base_init( NAIPivotConsumerInterface *klass )
 {
-	static const gchar *thisfn = "na_ipivot_container_interface_base_init";
+	static const gchar *thisfn = "na_ipivot_consumer_interface_base_init";
 	static gboolean initialized = FALSE;
 
 	if( !initialized ){
 		g_debug( "%s: klass=%p", thisfn, klass );
 
-		klass->private = g_new0( NAIPivotContainerInterfacePrivate, 1 );
+		klass->private = g_new0( NAIPivotConsumerInterfacePrivate, 1 );
 
 		klass->on_actions_changed = NULL /*do_actions_changed*/;
 
@@ -105,9 +105,9 @@ interface_base_init( NAIPivotContainerInterface *klass )
 }
 
 static void
-interface_base_finalize( NAIPivotContainerInterface *klass )
+interface_base_finalize( NAIPivotConsumerInterface *klass )
 {
-	static const gchar *thisfn = "na_ipivot_container_interface_base_finalize";
+	static const gchar *thisfn = "na_ipivot_consumer_interface_base_finalize";
 	static gboolean finalized = FALSE ;
 
 	if( !finalized ){
@@ -120,21 +120,25 @@ interface_base_finalize( NAIPivotContainerInterface *klass )
 }
 
 /**
- * Notify the container that the actions have been modified.
+ * na_ipivot_consumer_notify:
+ * @instance: the #NAIPivotConsumer instance to be notified of the end
+ * of the modifications.
+ *
+ * Notifies the consumers that the actions have been modified.
  */
-void na_ipivot_container_notify( NAIPivotContainer *instance )
+void na_ipivot_consumer_notify( NAIPivotConsumer *instance )
 {
-	static const gchar *thisfn = "na_ipivot_container_notify";
+	static const gchar *thisfn = "na_ipivot_consumer_notify";
 	g_debug( "%s: instance=%p", thisfn, instance );
 
-	if( NA_IPIVOT_CONTAINER_GET_INTERFACE( instance )->on_actions_changed ){
-		NA_IPIVOT_CONTAINER_GET_INTERFACE( instance )->on_actions_changed( instance, NULL );
+	if( NA_IPIVOT_CONSUMER_GET_INTERFACE( instance )->on_actions_changed ){
+		NA_IPIVOT_CONSUMER_GET_INTERFACE( instance )->on_actions_changed( instance, NULL );
 	}
 }
 
 /*static void
-do_actions_changed( NAIPivotContainer *instance, gpointer user_data )
+do_actions_changed( NAIPivotConsumer *instance, gpointer user_data )
 {
-	static const gchar *thisfn = "na_ipivot_container_do_actions_changed";
+	static const gchar *thisfn = "na_ipivot_consumer_do_actions_changed";
 	g_debug( "%s: instance=%p, user_data=%p", thisfn, instance, user_data );
 }*/
diff --git a/src/common/na-ipivot-consumer.h b/src/common/na-ipivot-consumer.h
new file mode 100644
index 0000000..da84f4d
--- /dev/null
+++ b/src/common/na-ipivot-consumer.h
@@ -0,0 +1,82 @@
+/*
+ * Nautilus Actions
+ * A Nautilus extension which offers configurable context menu actions.
+ *
+ * Copyright (C) 2005 The GNOME Foundation
+ * Copyright (C) 2006, 2007, 2008 Frederic Ruaudel and others (see AUTHORS)
+ * Copyright (C) 2009 Pierre Wieser and others (see AUTHORS)
+ *
+ * This Program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this Library; see the file COPYING.  If not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place,
+ * Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Authors:
+ *   Frederic Ruaudel <grumz grumz net>
+ *   Rodrigo Moya <rodrigo gnome-db org>
+ *   Pierre Wieser <pwieser trychlos org>
+ *   ... and many others (see AUTHORS)
+ */
+
+#ifndef __NA_IPIVOT_CONSUMER_H__
+#define __NA_IPIVOT_CONSUMER_H__
+
+/**
+ * SECTION: na_ipivot_consumer
+ * @short_description: #NAIPivotConsumer interface definition.
+ * @include: common/na-ipivot-consumer.h
+ *
+ * This interface should be implemented by all classes which embed a
+ * #NAPivot object, in order to receive modification notification
+ * messages.
+ */
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define NA_IPIVOT_CONSUMER_TYPE							( na_ipivot_consumer_get_type())
+#define NA_IPIVOT_CONSUMER( object )					( G_TYPE_CHECK_INSTANCE_CAST( object, NA_IPIVOT_CONSUMER_TYPE, NAIPivotConsumer ))
+#define NA_IS_IPIVOT_CONSUMER( object )					( G_TYPE_CHECK_INSTANCE_TYPE( object, NA_IPIVOT_CONSUMER_TYPE ))
+#define NA_IPIVOT_CONSUMER_GET_INTERFACE( instance )	( G_TYPE_INSTANCE_GET_INTERFACE(( instance ), NA_IPIVOT_CONSUMER_TYPE, NAIPivotConsumerInterface ))
+
+typedef struct NAIPivotConsumer NAIPivotConsumer;
+
+typedef struct NAIPivotConsumerInterfacePrivate NAIPivotConsumerInterfacePrivate;
+
+typedef struct {
+	GTypeInterface                     parent;
+	NAIPivotConsumerInterfacePrivate *private;
+
+	/**
+	 * on_actions_changed:
+	 * @instance: the #NAIPivotConsumer instance which implements this
+	 * interface.
+	 * user_data: user data set when emitting the message. Currently,
+	 * not used.
+	 *
+	 * This function is triggered once when #NAPivot detects the end of
+	 * a bunch of modifications. At this time, the embedded list of
+	 * #NAAction has been updated to be up to date.
+	 */
+	void ( *on_actions_changed )( NAIPivotConsumer *instance, gpointer user_data );
+}
+	NAIPivotConsumerInterface;
+
+GType na_ipivot_consumer_get_type( void );
+
+void  na_ipivot_consumer_notify( NAIPivotConsumer *instance );
+
+G_END_DECLS
+
+#endif /* __NA_IPIVOT_CONSUMER_H__ */
diff --git a/src/common/na-object.c b/src/common/na-object.c
index ac6b8be..48426e5 100644
--- a/src/common/na-object.c
+++ b/src/common/na-object.c
@@ -32,7 +32,10 @@
 #include <config.h>
 #endif
 
+#include <string.h>
+
 #include "na-object.h"
+#include "na-iduplicable.h"
 
 /* private class data
  */
@@ -42,20 +45,41 @@ struct NAObjectClassPrivate {
 /* private instance data
  */
 struct NAObjectPrivate {
-	gboolean dispose_has_run;
+	gboolean  dispose_has_run;
+	gchar    *id;
+	gchar    *label;
 };
 
-static GObjectClass *st_parent_class = NULL;
+/* instance properties
+ */
+#define PROP_NAOBJECT_ID_STR			"na-object-id"
+#define PROP_NAOBJECT_LABEL_STR			"na-object-label"
 
-static GType  register_type( void );
-static void   class_init( NAObjectClass *klass );
-static void   instance_init( GTypeInstance *instance, gpointer klass );
-static void   instance_dispose( GObject *object );
-static void   instance_finalize( GObject *object );
+static GObjectClass *st_parent_class = NULL;
 
-static void   do_dump( const NAObject *object );
-static gchar *do_get_id( const NAObject *object );
-static gchar *do_get_label( const NAObject *object );
+static GType     register_type( void );
+static void      class_init( NAObjectClass *klass );
+static void      iduplicable_iface_init( NAIDuplicableInterface *iface );
+static void      instance_init( GTypeInstance *instance, gpointer klass );
+static void      instance_constructed( GObject *object );
+static void      instance_get_property( GObject *object, guint property_id, GValue *value, GParamSpec *spec );
+static void      instance_set_property( GObject *object, guint property_id, const GValue *value, GParamSpec *spec );
+static void      instance_dispose( GObject *object );
+static void      instance_finalize( GObject *object );
+
+static NAObject *v_duplicate( const NAObject *object );
+static void      v_copy( NAObject *target, const NAObject *source );
+static gboolean  v_are_equal( const NAObject *a, const NAObject *b );
+static gboolean  v_is_valid( const NAObject *object );
+
+static void      do_dump( const NAObject *object );
+static void      do_copy( NAObject *target, const NAObject *source );
+static gboolean  do_are_equal( const NAObject *a, const NAObject *b );
+static gboolean  do_is_valid( const NAObject *object );
+
+static NAObject *iduplicable_duplicate( const NAObject *object );
+static gboolean  iduplicable_are_equal( const NAObject *a, const NAObject *b );
+static gboolean  iduplicable_is_valid( const NAObject *object );
 
 GType
 na_object_get_type( void )
@@ -72,6 +96,9 @@ na_object_get_type( void )
 static GType
 register_type( void )
 {
+	static const gchar *thisfn = "na_object_register_type";
+	g_debug( "%s", thisfn );
+
 	static GTypeInfo info = {
 		sizeof( NAObjectClass ),
 		( GBaseInitFunc ) NULL,
@@ -84,7 +111,19 @@ register_type( void )
 		( GInstanceInitFunc ) instance_init
 	};
 
-	return( g_type_register_static( G_TYPE_OBJECT, "NAObject", &info, 0 ));
+	GType type = g_type_register_static( G_TYPE_OBJECT, "NAObject", &info, 0 );
+
+	/* implements IDuplicable interface
+	 */
+	static const GInterfaceInfo idupicable_iface_info = {
+		( GInterfaceInitFunc ) iduplicable_iface_init,
+		NULL,
+		NULL
+	};
+
+	g_type_add_interface_static( type, NA_IDUPLICABLE_TYPE, &idupicable_iface_info );
+
+	return( type );
 }
 
 static void
@@ -96,14 +135,45 @@ class_init( NAObjectClass *klass )
 	st_parent_class = g_type_class_peek_parent( klass );
 
 	GObjectClass *object_class = G_OBJECT_CLASS( klass );
+	object_class->constructed = instance_constructed;
 	object_class->dispose = instance_dispose;
 	object_class->finalize = instance_finalize;
+	object_class->set_property = instance_set_property;
+	object_class->get_property = instance_get_property;
+
+	GParamSpec *spec;
+	spec = g_param_spec_string(
+			PROP_NAOBJECT_ID_STR,
+			"NAObject identifiant",
+			"Internal identifiant of the NAObject object (ASCII, case insensitive)", "",
+			G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE );
+	g_object_class_install_property( object_class, PROP_NAOBJECT_ID, spec );
+
+	spec = g_param_spec_string(
+			PROP_NAOBJECT_LABEL_STR,
+			"NAObject libelle",
+			"Libelle of the NAObject object (UTF-8, localizable)", "",
+			G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE );
+	g_object_class_install_property( object_class, PROP_NAOBJECT_LABEL, spec );
 
 	klass->private = g_new0( NAObjectClassPrivate, 1 );
 
 	klass->dump = do_dump;
-	klass->get_id = do_get_id;
-	klass->get_label = do_get_label;
+	klass->duplicate = NULL;
+	klass->copy = do_copy;
+	klass->are_equal = do_are_equal;
+	klass->is_valid = do_is_valid;
+}
+
+static void
+iduplicable_iface_init( NAIDuplicableInterface *iface )
+{
+	static const gchar *thisfn = "na_object_iduplicable_iface_init";
+	g_debug( "%s: iface=%p", thisfn, iface );
+
+	iface->duplicate = iduplicable_duplicate;
+	iface->are_equal = iduplicable_are_equal;
+	iface->is_valid = iduplicable_is_valid;
 }
 
 static void
@@ -121,6 +191,61 @@ instance_init( GTypeInstance *instance, gpointer klass )
 }
 
 static void
+instance_constructed( GObject *object )
+{
+	na_iduplicable_init( NA_OBJECT( object ));
+
+	/* chain call to parent class */
+	if( st_parent_class->constructed ){
+		G_OBJECT_CLASS( st_parent_class )->constructed( object );
+	}
+}
+
+static void
+instance_get_property( GObject *object, guint property_id, GValue *value, GParamSpec *spec )
+{
+	g_assert( NA_IS_OBJECT( object ));
+	NAObject *self = NA_OBJECT( object );
+
+	switch( property_id ){
+		case PROP_NAOBJECT_ID:
+			g_value_set_string( value, self->private->id );
+			break;
+
+		case PROP_NAOBJECT_LABEL:
+			g_value_set_string( value, self->private->label );
+			break;
+
+		default:
+			G_OBJECT_WARN_INVALID_PROPERTY_ID( object, property_id, spec );
+			break;
+	}
+}
+
+static void
+instance_set_property( GObject *object, guint property_id, const GValue *value, GParamSpec *spec )
+{
+	g_assert( NA_IS_OBJECT( object ));
+	NAObject *self = NA_OBJECT( object );
+
+	switch( property_id ){
+		case PROP_NAOBJECT_ID:
+			g_free( self->private->id );
+			self->private->id = g_value_dup_string( value );
+			break;
+
+		case PROP_NAOBJECT_LABEL:
+			g_free( self->private->label );
+			self->private->label = g_value_dup_string( value );
+			break;
+
+		default:
+			G_OBJECT_WARN_INVALID_PROPERTY_ID( object, property_id, spec );
+			break;
+	}
+}
+
+static void
 instance_dispose( GObject *object )
 {
 	g_assert( NA_IS_OBJECT( object ));
@@ -141,6 +266,9 @@ instance_finalize( GObject *object )
 	g_assert( NA_IS_OBJECT( object ));
 	NAObject *self = ( NAObject * ) object;
 
+	g_free( self->private->id );
+	g_free( self->private->label );
+
 	g_free( self->private );
 
 	/* chain call to parent class */
@@ -149,75 +277,349 @@ instance_finalize( GObject *object )
 	}
 }
 
-static void
-do_dump( const NAObject *object )
+/**
+ * na_object_dump:
+ * @object: the #NAObject object to be dumped.
+ *
+ * Dumps via g_debug the content of the object.
+ */
+void
+na_object_dump( const NAObject *object )
+{
+	if( object ){
+		g_assert( NA_IS_OBJECT( object ));
+
+		NA_OBJECT_GET_CLASS( object )->dump( object );
+	}
+}
+
+/**
+ * na_object_duplicate:
+ * @object: the #NAObject object to be dumped.
+ *
+ * Exactly duplicates a #NAObject-derived object.
+ *
+ * Returns: the new #NAObject.
+ */
+NAObject *
+na_object_duplicate( const NAObject *object )
 {
-	static const char *thisfn = "na_object_do_dump";
 	g_assert( NA_IS_OBJECT( object ));
-	g_debug( "%s: object=%p", thisfn, object );
+
+	return( na_iduplicable_duplicate( object ));
+}
+
+/**
+ * na_object_copy:
+ * @target: the #NAObject-derived object which will receive data.
+ * @source: the #NAObject-derived object which will provide data.
+ *
+ * Copies data and properties from @source to @target.
+ */
+void
+na_object_copy( NAObject *target, const NAObject *source )
+{
+	g_assert( NA_IS_OBJECT( target ));
+	g_assert( NA_IS_OBJECT( source ));
+
+	v_copy( target, source );
 }
 
 /**
- * Dump the content of the object via g_debug output.
+ * na_object_check_edited_status:
+ * @object: the #NAObject object to be checked.
  *
- * This is a virtual function which may be implemented by the derived
- * class ; the derived class may also call its parent class to get a
- * dump of parent object.
+ * Checks for the edition status of @object.
  *
- * @object: object to be dumped.
+ * Internally set some properties which may be requested later. This
+ * two-steps check-request let us optimize some work in the UI.
  */
 void
-na_object_dump( const NAObject *object )
+na_object_check_edited_status( const NAObject *object )
+{
+	g_assert( NA_IS_OBJECT( object ));
+
+	na_iduplicable_check_edited_status( object );
+}
+
+/**
+ * na_object_are_equal:
+ * @a: a first #NAObject object.
+ * @b: a second #NAObject object to be compared to the first one.
+ *
+ * Compares the two #NAObject objects.
+ *
+ * At least when it finds that @a and @b are equal, each derived
+ * class should call its parent class to give it an opportunity to
+ * detect a difference.
+ *
+ * Returns: %TRUE if @a and @b are identical, %FALSE else.
+ */
+gboolean
+na_object_are_equal( const NAObject *a, const NAObject *b )
+{
+	g_assert( NA_IS_OBJECT( a ));
+	g_assert( NA_IS_OBJECT( b ));
+
+	return( v_are_equal( a, b ));
+}
+
+/**
+ * na_object_get_is_valid:
+ * @object: the #NAObject object whose validity is to be checked.
+ *
+ * Checks for the validity of @object.
+ *
+ * Returns: %TRUE is @object is valid, %FALSE else.
+ */
+gboolean
+na_object_is_valid( const NAObject *object )
 {
 	g_assert( NA_IS_OBJECT( object ));
 
-	NA_OBJECT_GET_CLASS( object )->dump( object );
+	return( v_is_valid( object ));
 }
 
-static gchar *
-do_get_id( const NAObject *object )
+/**
+ * na_object_get_origin:
+ * @object: the #NAObject object whose status is requested.
+ *
+ * Returns the original object which was at the origin of @object.
+ *
+ * Returns: a #NAObject, or NULL.
+ */
+NAObject *
+na_object_get_origin( const NAObject *object )
 {
 	g_assert( NA_IS_OBJECT( object ));
-	return(( gchar * ) NULL );
+
+	return( na_iduplicable_get_origin( object ));
 }
 
 /**
- * Returns the id of the object as new string.
+ * na_object_get_modified_status:
+ * @object: the #NAObject object whose status is requested.
+ *
+ * Returns the current modification status of @object.
  *
- * This is a virtual function which should be implemented by the
- * derived class ; if not, this parent object returns NULL.
+ * This suppose that @object has been previously duplicated in order
+ * to get benefits provided by the IDuplicable interface.
  *
- * @object: targeted NAObject object.
+ * This suppose also that the edition status of @object has previously
+ * been checked via na_object_check_edited_status().
  *
- * The returned string should be g_freed by the caller.
+ * Returns: %TRUE is the provided object has been modified regarding to
+ * the original one, %FALSE else.
  */
-gchar *
-na_object_get_id( const NAObject *object )
+gboolean
+na_object_get_modified_status( const NAObject *object )
+{
+	g_assert( NA_IS_OBJECT( object ));
+
+	return( na_iduplicable_is_modified( object ));
+}
+
+/**
+ * na_object_get_valid_status:
+ * @object: the #NAObject object whose status is requested.
+ *
+ * Returns the current validity status of @object.
+ *
+ * This suppose that @object has been previously duplicated in order
+ * to get benefits provided by the IDuplicable interface.
+ *
+ * This suppose also that the edition status of @object has previously
+ * been checked via na_object_check_edited_status().
+ *
+ * Returns: %TRUE is the provided object is valid, %FALSE else.
+ */
+gboolean
+na_object_get_valid_status( const NAObject *object )
 {
 	g_assert( NA_IS_OBJECT( object ));
-	return( NA_OBJECT_GET_CLASS( object )->get_id( object ));
+
+	return( na_iduplicable_is_valid( object ));
 }
 
-static gchar *
-do_get_label( const NAObject *object )
+/**
+ * na_object_set_origin:
+ * @object: the #NAObject object whose status is requested.
+ * @origin: a #NAObject which will be set as the new origin of @object.
+ *
+ * Sets the new origin of @object.
+ */
+void
+na_object_set_origin( NAObject *object, const NAObject *origin )
 {
 	g_assert( NA_IS_OBJECT( object ));
-	return(( gchar * ) NULL );
+
+	na_iduplicable_set_origin( object, origin );
 }
 
 /**
- * Returns the label of the object as new string.
+ * na_object_get_id:
+ * @object: the #NAObject object whose internal identifiant is
+ * requested.
  *
- * This is a virtual function which should be implemented by the
- * derived class ; if not, this parent object returns NULL.
+ * Returns the internal identifiant of @object.
+ *
+ * Returns: the internal identifiant of @object as a new string. The
+ * returned string is an ASCII, case insensitive, string. It should be
+ * g_free() by the caller.
+ */
+gchar *
+na_object_get_id( const NAObject *object )
+{
+	g_assert( NA_IS_OBJECT( object ));
+	gchar *id;
+	g_object_get( G_OBJECT( object ), PROP_NAOBJECT_ID_STR, &id, NULL );
+	return( id );
+}
+
+/**
+ * na_object_get_label:
+ * @object: the #NAObject object whose label is requested.
  *
- * @object: targeted NAObject object.
+ * Returns the label of @object.
  *
- * The returned string should be g_freed by the caller.
+ * Returns: the label of @object as a new string. The returned string
+ * is an UTF_8 string. It should be g_free() by the caller.
  */
 gchar *
 na_object_get_label( const NAObject *object )
 {
 	g_assert( NA_IS_OBJECT( object ));
-	return( NA_OBJECT_GET_CLASS( object )->get_label( object ));
+	gchar *label;
+	g_object_get( G_OBJECT( object ), PROP_NAOBJECT_LABEL_STR, &label, NULL );
+	return( label );
+}
+
+/**
+ * na_object_set_id:
+ * @object: the #NAObject object whose internal identifiant is to be
+ * set.
+ * @id: internal identifiant to be set.
+ *
+ * Sets the internal identifiant of @object by taking a copy of the
+ * provided one.
+ */
+void
+na_object_set_id( NAObject *object, const gchar *id )
+{
+	g_assert( NA_IS_OBJECT( object ));
+	g_object_set( G_OBJECT( object ), PROP_NAOBJECT_ID_STR, id, NULL );
+}
+
+/**
+ * na_object_set_label:
+ * @object: the #NAObject object whose label is to be set.
+ * @label: label to be set.
+ *
+ * Sets the label of @object by taking a copy of the provided one.
+ */
+void
+na_object_set_label( NAObject *object, const gchar *label )
+{
+	g_assert( NA_IS_OBJECT( object ));
+	g_object_set( G_OBJECT( object ), PROP_NAOBJECT_LABEL_STR, label, NULL );
+}
+
+static NAObject *
+v_duplicate( const NAObject *object )
+{
+	if( NA_OBJECT_GET_CLASS( object )->duplicate ){
+		return( NA_OBJECT_GET_CLASS( object )->duplicate( object ));
+	}
+
+	return( NULL );
+}
+
+static void
+v_copy( NAObject *target, const NAObject *source )
+{
+	if( NA_OBJECT_GET_CLASS( target )->copy ){
+		NA_OBJECT_GET_CLASS( target )->copy( target, source );
+	}
+}
+
+static gboolean
+v_are_equal( const NAObject *a, const NAObject *b )
+{
+	if( NA_OBJECT_GET_CLASS( a )->are_equal ){
+		return( NA_OBJECT_GET_CLASS( a )->are_equal( a, b ));
+	}
+
+	return( FALSE );
+}
+
+static gboolean
+v_is_valid( const NAObject *object )
+{
+	if( NA_OBJECT_GET_CLASS( object )->is_valid ){
+		return( NA_OBJECT_GET_CLASS( object )->is_valid( object ));
+	}
+
+	return( TRUE );
+}
+
+static void
+do_dump( const NAObject *object )
+{
+	static const char *thisfn = "na_object_do_dump";
+
+	g_assert( NA_IS_OBJECT( object ));
+
+	g_debug( "%s: object=%p", thisfn, object );
+	g_debug( "%s:     id=%s", thisfn, object->private->id );
+	g_debug( "%s:  label=%s", thisfn, object->private->label );
+
+	na_iduplicable_dump( object );
+}
+
+static void
+do_copy( NAObject *target, const NAObject *source )
+{
+	gchar *id = na_object_get_id( source );
+	na_object_set_id( target, id );
+	g_free( id );
+
+	gchar *label = na_object_get_label( source );
+	na_object_set_label( target, label );
+	g_free( label );
+}
+
+static gboolean
+do_are_equal( const NAObject *a, const NAObject *b )
+{
+	if( g_ascii_strcasecmp( a->private->id, b->private->id )){
+		return( FALSE );
+	}
+	if( g_utf8_collate( a->private->label, b->private->label )){
+		return( FALSE );
+	}
+	return( TRUE );
+}
+
+static gboolean
+do_is_valid( const NAObject *object )
+{
+	return( object->private->id && strlen( object->private->id ));
+}
+
+static NAObject *
+iduplicable_duplicate( const NAObject *object )
+{
+	return( v_duplicate( object ));
+}
+
+static gboolean
+iduplicable_are_equal( const NAObject *a, const NAObject *b )
+{
+	return( v_are_equal( a, b ));
+}
+
+static gboolean
+iduplicable_is_valid( const NAObject *object )
+{
+	return( v_is_valid( object ));
 }
diff --git a/src/common/na-object.h b/src/common/na-object.h
index 9d11de9..a863123 100644
--- a/src/common/na-object.h
+++ b/src/common/na-object.h
@@ -32,13 +32,20 @@
 #define __NA_OBJECT_H__
 
 /*
- * NAObject class definition.
+ * SECTION: na_object
+ * @short_description: #NAObject class definition.
+ * @include: common/na-object.h
  *
- * This is the base class for NactAction and NactActionProfile.
+ * This is the base class for NAAction and NActionProfile.
  *
- * It takes care of common things such as ids, i/o, etc.
- * It uses the NactIIOProviderInterface for all storage subsystems
- * management.
+ * It implements the NAIDuplicable interface in order to have easily
+ * duplicable derived objects.
+ *
+ * A #NAObject object is characterized by :
+ * - an internal identifiant (ASCII, case insensitive)
+ * - a libelle (UTF8, localizable).
+ *
+ * The #NAObject class is a pure virtual class.
  */
 
 #include <glib-object.h>
@@ -66,18 +73,109 @@ typedef struct {
 	GObjectClass          parent;
 	NAObjectClassPrivate *private;
 
-	/* virtual public functions */
-	void    ( *dump )     ( const NAObject *object );
-	gchar * ( *get_id )   ( const NAObject *object );
-	gchar * ( *get_label )( const NAObject *object );
+	/**
+	 * dump:
+	 * @object: the #NAObject-derived object to be dumped.
+	 *
+	 * Dumps via g_debug the content of the object.
+	 *
+	 * In order to get a down-to-top display, the derived class
+	 * implementation should call its parent class before actually
+	 * dumping its own data and properties.
+	 */
+	void       ( *dump )     ( const NAObject *object );
+
+	/**
+	 * duplicate:
+	 * @object: the #NAObject-derived object to be dumped.
+	 *
+	 * Duplicates a #NAObject-derived object.
+	 *
+	 * As the most-derived class will actually allocate the new object
+	 * with the right class, it shouldn't call its parent class.
+	 *
+	 * Copying data and properties should then be done via the
+	 * na_object_copy() function.
+	 *
+	 * Returns: a newly allocated object, which is an exact copy of
+	 * @object.
+	 */
+	NAObject * ( *duplicate )( const NAObject *object );
+
+	/**
+	 * copy:
+	 * @target: the #NAObject-derived object which will receive data.
+	 * @source: the #NAObject-derived object which will provide data.
+	 *
+	 * Copies data and properties from @source to @target.
+	 *
+	 * Each derived class should take care of calling its parent class
+	 * to complete the copy.
+	 */
+	void       ( *copy )     ( NAObject *target, const NAObject *source );
+
+	/**
+	 * are_equal:
+	 * @a: a first #NAObject object.
+	 * @b: a second #NAObject object to be compared to the first one.
+	 *
+	 * Compares the two objects.
+	 *
+	 * At least when it finds that @a and @b are equal, each derived
+	 * class should call its parent class to give it an opportunity to
+	 * detect a difference.
+	 *
+	 * Returns: %TRUE if @a and @b are identical, %FALSE else.
+	 */
+	gboolean   ( *are_equal )( const NAObject *a, const NAObject *b );
+
+	/**
+	 * is_valid:
+	 * @object: the #NAObject object to be checked.
+	 *
+	 * Checks @object for validity.
+	 *
+	 * At least when it finds that @object is valid, each derived class
+	 * should call its parent class to give it an opportunity to detect
+	 * an error.
+	 *
+	 * A #NAObject is valid if its internal identifiant is set.
+	 *
+	 * Returns: %TRUE if @object is valid, %FALSE else.
+	 */
+	gboolean   ( *is_valid ) ( const NAObject *object );
 }
 	NAObjectClass;
 
-GType    na_object_get_type( void );
+/* object properties
+ * used in derived classes to access to the properties
+ */
+enum {
+	PROP_NAOBJECT_ID = 1,
+	PROP_NAOBJECT_LABEL
+};
+
+GType     na_object_get_type( void );
+
+void      na_object_dump( const NAObject *object );
+NAObject *na_object_duplicate( const NAObject *object );
+void      na_object_copy( NAObject *target, const NAObject *source );
+
+void      na_object_check_edited_status( const NAObject *object );
+gboolean  na_object_are_equal( const NAObject *a, const NAObject *b );
+gboolean  na_object_is_valid( const NAObject *object );
+
+NAObject *na_object_get_origin( const NAObject *object );
+gboolean  na_object_get_modified_status( const NAObject *object );
+gboolean  na_object_get_valid_status( const NAObject *object );
+
+void      na_object_set_origin( NAObject *object, const NAObject *origin );
+
+gchar    *na_object_get_id( const NAObject *object );
+gchar    *na_object_get_label( const NAObject *object );
 
-void     na_object_dump( const NAObject *object );
-gchar   *na_object_get_id( const NAObject *object );
-gchar   *na_object_get_label( const NAObject *object );
+void      na_object_set_id( NAObject *object, const gchar *id );
+void      na_object_set_label( NAObject *object, const gchar *label );
 
 G_END_DECLS
 
diff --git a/src/common/na-pivot.c b/src/common/na-pivot.c
index fbc5c57..593d1e7 100644
--- a/src/common/na-pivot.c
+++ b/src/common/na-pivot.c
@@ -39,7 +39,7 @@
 #include "na-gconf.h"
 #include "na-pivot.h"
 #include "na-iio-provider.h"
-#include "na-ipivot-container.h"
+#include "na-ipivot-consumer.h"
 #include "na-utils.h"
 
 /* private class data
@@ -53,6 +53,7 @@ struct NAPivotPrivate {
 	gboolean dispose_has_run;
 
 	/* list of instances to be notified of an action modification
+	 * these are called 'consumers' of NAPivot
 	 */
 	GSList  *notified;
 
@@ -66,19 +67,9 @@ struct NAPivotPrivate {
 	/* list of actions
 	 */
 	GSList  *actions;
+	gboolean reload;
 };
 
-/* We have a double stage notification system :
- *
- * 1. When the storage subsystems detects a change on an action, it
- *    must emit the "notify_pivot_of_action_changed" signal to notify
- *    NAPivot of this change ; when this signal is received, NAPivot
- *    then updates accordingly the list of actions it maintains.
- *
- * 2. When NAPivot has successfully updated its list of actions, it has
- *    to notify its consumers (its 'containers') in order they update
- *    themselves.
- */
 enum {
 	ACTION_CHANGED,
 	LAST_SIGNAL
@@ -96,9 +87,9 @@ static void     class_init( NAPivotClass *klass );
 static void     instance_init( GTypeInstance *instance, gpointer klass );
 static GSList  *register_interface_providers( const NAPivot *pivot );
 static void     instance_dispose( GObject *object );
-static void     free_containers( GSList *list );
 static void     instance_finalize( GObject *object );
 
+static void     free_consumers( GSList *list );
 static void     action_changed_handler( NAPivot *pivot, gpointer user_data );
 static gboolean on_actions_changed_timeout( gpointer user_data );
 static gulong   time_val_diff( const GTimeVal *recent, const GTimeVal *old );
@@ -148,7 +139,7 @@ class_init( NAPivotClass *klass )
 	klass->private = g_new0( NAPivotClassPrivate, 1 );
 
 	/* register the signal and its default handler
-	 * this signal should be sent by the IIOProviders when an actions
+	 * this signal should be sent by the IIOProvider when an actions
 	 * has changed in the underlying storage subsystem
 	 */
 	st_signals[ ACTION_CHANGED ] = g_signal_new_class_handler(
@@ -175,9 +166,12 @@ instance_init( GTypeInstance *instance, gpointer klass )
 	NAPivot* self = NA_PIVOT( instance );
 
 	self->private = g_new0( NAPivotPrivate, 1 );
+
 	self->private->dispose_has_run = FALSE;
+	self->private->notified = NULL;
 	self->private->providers = register_interface_providers( self );
-	self->private->actions = na_iio_provider_read_actions( G_OBJECT( self ));
+	self->private->actions = na_iio_provider_read_actions( self );
+	self->private->reload = TRUE;
 }
 
 static GSList *
@@ -207,7 +201,7 @@ instance_dispose( GObject *object )
 		self->private->dispose_has_run = TRUE;
 
 		/* release list of containers to be notified */
-		free_containers( self->private->notified );
+		free_consumers( self->private->notified );
 
 		/* release list of actions */
 		na_pivot_free_actions( self->private->actions );
@@ -219,15 +213,6 @@ instance_dispose( GObject *object )
 }
 
 static void
-free_containers( GSList *containers )
-{
-	GSList *ic;
-	for( ic = containers ; ic ; ic = ic->next )
-		;
-	g_slist_free( containers );
-}
-
-static void
 instance_finalize( GObject *object )
 {
 	static const gchar *thisfn = "na_pivot_instance_finalize";
@@ -253,11 +238,11 @@ instance_finalize( GObject *object )
 }
 
 /**
- * Allocates a new NAPivot object.
+ * na_pivot_new:
+ * @target: a GObject which wishes be notified of any modification of
+ * an action in any of the underlying I/O storage subsystems.
  *
- * @target: the GObject which will handled Nautilus notification, and
- * should be notified when an actions is added, modified or removed in
- * one of the underlying storage subsystems.
+ * Allocates a new #NAPivot object.
  *
  * The target object will receive a "notify_nautilus_of_action_changed"
  * message, without any parameter.
@@ -268,27 +253,52 @@ na_pivot_new( const GObject *target )
 	NAPivot *pivot = g_object_new( NA_PIVOT_TYPE, NULL );
 
 	if( target ){
-		pivot->private->notified = g_slist_prepend( pivot->private->notified, ( gpointer ) target );
+		na_pivot_add_consumer( pivot, target );
 	}
 
 	return( pivot );
 }
 
 /**
+ * na_pivot_dump:
+ * @pivot: the #NAPivot object do be dumped.
+ *
+ * Dumps the content of a #NAPivot object.
+ */
+void
+na_pivot_dump( const NAPivot *pivot )
+{
+	static const gchar *thisfn = "na_pivot_dump";
+
+	GSList *it;
+	int i;
+	g_debug( "%s:  notified=%p (%d elts)", thisfn, pivot->private->notified, g_slist_length( pivot->private->notified ));
+	g_debug( "%s: providers=%p (%d elts)", thisfn, pivot->private->providers, g_slist_length( pivot->private->providers ));
+	g_debug( "%s:   actions=%p (%d elts)", thisfn, pivot->private->actions, g_slist_length( pivot->private->actions ));
+	for( it = pivot->private->actions, i = 0 ; it ; it = it->next ){
+		g_debug( "%s:   [%d]: %p", thisfn, i++, it->data );
+	}
+}
+
+/**
+ * na_pivot_get_providers:
+ * @pivot: this #NAPivot instance.
+ * @type: the type of searched interface.
+ * For now, we only have NA_IIO_PROVIDER_TYPE interfaces.
+ *
  * Returns the list of providers of the required interface.
  *
  * This function is called by interfaces API in order to find the
  * list of providers registered for this given interface.
  *
- * @pivot: this instance.
- *
- * @type: the type of searched interface.
+ * Returns: the list of providers of the required interface.
+ * This list should be na_pivot_free_providers().
  */
 GSList *
 na_pivot_get_providers( const NAPivot *pivot, GType type )
 {
 	static const gchar *thisfn = "na_pivot_get_providers";
-	g_debug( "%s", thisfn );
+	g_debug( "%s: pivot=%p", thisfn, pivot );
 
 	g_assert( NA_IS_PIVOT( pivot ));
 
@@ -304,24 +314,82 @@ na_pivot_get_providers( const NAPivot *pivot, GType type )
 }
 
 /**
- * Return the list of actions.
+ * na_pivot_free_providers:
+ * @providers: a list of providers.
+ *
+ * Frees a list of providers as returned from na_pivot_get_providers().
+ */
+void
+na_pivot_free_providers( GSList *providers )
+{
+	g_slist_free( providers );
+}
+
+/**
+ * na_pivot_get_actions:
+ * @pivot: this #NAPivot instance.
  *
- * @pivot: this NAPivot object.
+ * Returns the list of actions.
  *
- * The returned list is owned by this NAPivot object, and should not
- * be freed, nor unref by the caller.
+ * Returns: the list of #NAAction actions.
+ * The returned list is owned by this #NAPivot object, and should not
+ * be g_free(), nor g_object_unref() by the caller.
  */
 GSList *
 na_pivot_get_actions( const NAPivot *pivot )
 {
 	g_assert( NA_IS_PIVOT( pivot ));
+
 	return( pivot->private->actions );
 }
 
 /**
- * Free a list of actions.
+ * na_pivot_reload_actions:
+ * @pivot: this #NAPivot instance.
+ *
+ * Reloads the list of actions from I/O providers.
+ */
+void
+na_pivot_reload_actions( NAPivot *pivot )
+{
+	g_assert( NA_IS_PIVOT( pivot ));
+
+	if( pivot->private->actions ){
+		na_pivot_free_actions( pivot->private->actions );
+	}
+
+	pivot->private->actions = na_iio_provider_read_actions( pivot );
+}
+
+/**
+ * na_pivot_get_duplicate_actions:
+ * @pivot: this #NAPivot instance.
  *
- * @list: the GSList of NAActions to be freed.
+ * Returns an exact copy of the current list of actions.
+ *
+ * Returns: a #GSList of #NAAction actions.
+ * The caller should na_pivot_free_actions() after usage.
+ */
+GSList *
+na_pivot_get_duplicate_actions( const NAPivot *pivot )
+{
+	g_assert( NA_IS_PIVOT( pivot ));
+
+	GSList *list = NULL;
+	GSList *ia;
+
+	for( ia = pivot->private->actions ; ia ; ia = ia->next ){
+		list = g_slist_prepend( list, na_object_duplicate( NA_OBJECT( ia->data )));
+	}
+
+	return( list );
+}
+
+/**
+ * na_pivot_free_actions:
+ * @list: a #GSList of #NAActions to be freed.
+ *
+ * Frees a list of actions.
  */
 void
 na_pivot_free_actions( GSList *actions )
@@ -334,83 +402,183 @@ na_pivot_free_actions( GSList *actions )
 }
 
 /**
- * Return the specified action.
+ * na_pivot_add_action:
+ * @pivot: this #NAPivot instance.
+ * @action: the #NAAction to be added to the list.
+ *
+ * Adds a new #NAAction to the list of actions.
+ *
+ * We take the provided pointer. The provided #NAAction should so not
+ * be g_object_unref() by the caller.
+ */
+void
+na_pivot_add_action( NAPivot *pivot, const NAAction *action )
+{
+	g_assert( NA_IS_PIVOT( pivot ));
+
+	pivot->private->actions = g_slist_prepend( pivot->private->actions, ( gpointer ) action );
+}
+
+/**
+ * na_pivot_remove_action:
+ * @pivot: this #NAPivot instance.
+ * @action: the #NAAction to be removed to the list.
  *
- * @pivot: this NAPivot object.
+ * Removes a #NAAction from the list of actions.
  *
- * @uuid: required globally unique identifier (uuid).
+ * Note that #NAPivot also g_object_unref() the removed #NAAction.
+ */
+void
+na_pivot_remove_action( NAPivot *pivot, NAAction *action )
+{
+	g_assert( NA_IS_PIVOT( pivot ));
+
+	pivot->private->actions = g_slist_remove( pivot->private->actions, ( gconstpointer ) action );
+	g_object_unref( action );
+}
+
+/**
+ * na_pivot_get_action:
+ * @pivot: this #NAPivot instance.
+ * @uuid: the required globally unique identifier (uuid).
  *
- * Returns the specified NAAction object, or NULL if not found.
+ * Returns the specified action.
  *
- * The returned pointer is owned by NAPivot, and should not be freed
- * nor unref by the caller.
+ * Returns: the required #NAAction object, or NULL if not found.
+ * The returned pointer is owned by #NAPivot, and should not be
+ * g_free() nor g_object_unref() by the caller.
  */
-GObject *
-na_pivot_get_action( NAPivot *pivot, const gchar *uuid )
+NAAction *
+na_pivot_get_action( const NAPivot *pivot, const gchar *uuid )
 {
-	GSList *ia;
-	NAAction *act;
-	GObject *found = NULL;
-	uuid_t uua, uub;
-	gchar *uuid_act;
+	uuid_t uua, i_uub;
 
 	g_assert( NA_IS_PIVOT( pivot ));
+	if( !uuid || !strlen( uuid )){
+		return( NULL );
+	}
 
 	uuid_parse( uuid, uua );
+
+	GSList *ia;
 	for( ia = pivot->private->actions ; ia ; ia = ia->next ){
-		act = NA_ACTION( ia->data );
-		uuid_act = na_action_get_uuid( act );
-		uuid_parse( uuid_act, uub );
-		g_free( uuid_act );
-		if( !uuid_compare( uua, uub )){
-			found = G_OBJECT( act );
-			break;
+
+		gchar *i_uuid = na_action_get_uuid( NA_ACTION( ia->data ));
+		uuid_parse( i_uuid, i_uub );
+		g_free( i_uuid );
+
+		if( !uuid_compare( uua, i_uub )){
+			return( NA_ACTION( ia->data ));
 		}
 	}
 
-	return( found );
+	return( NULL );
 }
 
 /**
- * Write an action.
- *
- * @pivot: this NAPivot object.
- *
- * @action: action to be written by the storage subsystem.
- *
+ * na_pivot_write_action:
+ * @pivot: this #NAPivot instance.
+ * @action: a #NAAction action to be written by the storage subsystem.
  * @message: the I/O provider can allocate and store here an error
  * message.
  *
- * Returns the IIOProvider return code.
+ * Writes an action.
+ *
+ * Returns: the #NAIIOProvider return code.
  */
 guint
-na_pivot_write_action( NAPivot *pivot, const GObject *action, gchar **message )
+na_pivot_write_action( const NAPivot *pivot, NAAction *action, gchar **message )
 {
 	g_assert( NA_IS_PIVOT( pivot ));
 	g_assert( NA_IS_ACTION( action ));
 	g_assert( message );
-	return( na_iio_provider_write_action( G_OBJECT( pivot ), action, message ));
+	return( na_iio_provider_write_action( pivot, action, message ));
 }
 
 /**
- * Delete an action.
- *
- * @pivot: this NAPivot object.
- *
- * @action: action to be deleted from the storage subsystem.
- *
+ * na_pivot_delete_action:
+ * @pivot: this #NAPivot instance.
+ * @action: a #NAAction action to be deleted from the storage
+ * subsystem.
  * @message: the I/O provider can allocate and store here an error
  * message.
  *
- * Returns the IIOProvider return code.
+ * Deletes an action from the I/O storage subsystem.
+ *
+ * Returns: the #NAIIOProvider return code.
  */
 guint
-na_pivot_delete_action( NAPivot *pivot, const GObject *action, gchar **message )
+na_pivot_delete_action( const NAPivot *pivot, const NAAction *action, gchar **message )
 {
 	g_assert( NA_IS_PIVOT( pivot ));
 	g_assert( NA_IS_ACTION( action ));
 	g_assert( message );
-	return( na_iio_provider_delete_action( G_OBJECT( pivot ), action, message ));
+	return( na_iio_provider_delete_action( pivot, action, message ));
+}
+
+/**
+ * na_pivot_add_consumer:
+ * @pivot: this #NAPivot instance.
+ * @consumer: a #GObject which wishes be notified of any modification
+ * of an action in any of the underlying I/O storage subsystems.
+ *
+ * Registers a new consumer to be notified of an action modification.
+ */
+void
+na_pivot_add_consumer( NAPivot *pivot, const GObject *consumer )
+{
+	static const gchar *thisfn = "na_pivot_add_consumer";
+	g_debug( "%s: pivot=%p, consumer=%p", thisfn, pivot, consumer );
+
+	g_assert( NA_IS_PIVOT( pivot ));
+	g_assert( G_IS_OBJECT( consumer ));
+
+	pivot->private->notified = g_slist_prepend( pivot->private->notified, ( gpointer ) consumer );
+}
+
+/**
+ * na_pivot_get_automatic_reload:
+ * @pivot: this #NAPivot instance.
+ *
+ * Returns: the automatic reload flag.
+ */
+gboolean
+na_pivot_get_automatic_reload( const NAPivot *pivot )
+{
+	g_assert( NA_IS_PIVOT( pivot ));
+
+	return( pivot->private->reload );
+}
+
+/**
+ * na_pivot_set_automatic_reload:
+ * @pivot: this #NAPivot instance.
+ * @reload: whether this #NAPivot instance should automatically reload
+ * its list of actions when I/O providers advertize it of a
+ * modification.
+ *
+ * Sets the automatic reload flag.
+ *
+ * Note that even if the #NAPivot instance is not authorized to
+ * automatically reload its list of actions when it is advertized of
+ * a modification by one of the I/O providers, it always sends an
+ * ad-hoc notification to its consumers.
+ */
+void
+na_pivot_set_automatic_reload( NAPivot *pivot, gboolean reload )
+{
+	g_assert( NA_IS_PIVOT( pivot ));
+
+	pivot->private->reload = reload;
+}
+
+static void
+free_consumers( GSList *consumers )
+{
+	GSList *ic;
+	for( ic = consumers ; ic ; ic = ic->next )
+		;
+	g_slist_free( consumers );
 }
 
 /*
@@ -457,7 +625,7 @@ on_actions_changed_timeout( gpointer user_data )
 	GTimeVal now;
 
 	g_assert( NA_IS_PIVOT( user_data ));
-	NAPivot *pivot = NA_PIVOT( user_data );
+	const NAPivot *pivot = NA_PIVOT( user_data );
 
 	g_get_current_time( &now );
 	gulong diff = time_val_diff( &now, &st_last_event );
@@ -465,12 +633,14 @@ on_actions_changed_timeout( gpointer user_data )
 		return( TRUE );
 	}
 
-	na_pivot_free_actions( pivot->private->actions );
-	pivot->private->actions = na_iio_provider_read_actions( G_OBJECT( pivot ));
+	if( pivot->private->reload ){
+		na_pivot_free_actions( pivot->private->actions );
+		pivot->private->actions = na_iio_provider_read_actions( pivot );
+	}
 
 	GSList *ic;
 	for( ic = pivot->private->notified ; ic ; ic = ic->next ){
-		na_ipivot_container_notify( NA_IPIVOT_CONTAINER( ic->data ));
+		na_ipivot_consumer_notify( NA_IPIVOT_CONSUMER( ic->data ));
 	}
 
 	st_event_source_id = 0;
@@ -522,13 +692,3 @@ na_pivot_free_notify( NAPivotNotify *npn )
 		g_free( npn );
 	}
 }
-
-/**
- * Records a container which has to be notified of a modification of
- * the list of actions.
- */
-void
-na_pivot_add_notified( NAPivot *pivot, GObject *container )
-{
-	pivot->private->notified = g_slist_prepend( pivot->private->notified, container );
-}
diff --git a/src/common/na-pivot.h b/src/common/na-pivot.h
index db57e58..b4d07a9 100644
--- a/src/common/na-pivot.h
+++ b/src/common/na-pivot.h
@@ -31,17 +31,53 @@
 #ifndef __NA_PIVOT_H__
 #define __NA_PIVOT_H__
 
-/*
- * NAPivot class definition.
+/**
+ * SECTION: na_pivot
+ * @short_description: #NAPivot class definition.
+ * @include: common/na-pivot.h
  *
  * A consuming program should allocate one new NAPivot object in its
  * startup phase. The class takes care of declaring the I/O interface,
  * while registering the known providers. The object will then load
  * itself the existing list of actions.
+ *
+ * Notification system
+ *
+ * Each I/O storage provider should monitor modifications/deletions of
+ * actions, and advertize this #NAPivot, which itself will then
+ * advertize any registered consumers.
+ *
+ * This notification system is so a double-stage one :
+ *
+ * 1. When an I/O storage subsystem detects a change on an action, it
+ *    should emit the "notify_pivot_of_action_changed" signal to notify
+ *    #NAPivot of this change. The user data associated with the
+ *    message should be a #gpointer to a #NAPivotNotify structure.
+ *
+ *    When this signal is received, #NAPivot updates accordingly the
+ *    list of actions it maintains.
+ *
+ *    It is up to the I/O storage provider to decide if it sends a
+ *    message for each and every one detected modification, or if it
+ *    sends only one message for a whole, maybe coherent, set of
+ *    updates.
+ *
+ *    This first stage message is defined in na-iio-provider.h,
+ *    as NA_IIO_PROVIDER_SIGNAL_ACTION_CHANGED.
+ *
+ * 2. When #NAPivot has successfully updated its list of actions, it
+ *    notifies its consumers in order they update themselves.
+ *
+ *    Note that #NAPivot tries to factorize notification messages, and
+ *    to notify its consumers only once even if it has itself received
+ *    many elementary notifications from the underlying I/O storage
+ *    subsystem.
  */
 
 #include <glib-object.h>
 
+#include "na-action-class.h"
+
 G_BEGIN_DECLS
 
 #define NA_PIVOT_TYPE					( na_pivot_get_type())
@@ -67,18 +103,29 @@ typedef struct {
 }
 	NAPivotClass;
 
-GType    na_pivot_get_type( void );
+GType     na_pivot_get_type( void );
 
-NAPivot *na_pivot_new( const GObject *notified );
+NAPivot  *na_pivot_new( const GObject *notified );
+void      na_pivot_dump( const NAPivot *pivot );
 
-GSList  *na_pivot_get_providers( const NAPivot *pivot, GType type );
+GSList   *na_pivot_get_providers( const NAPivot *pivot, GType type );
+void      na_pivot_free_providers( GSList *providers );
 
-GSList  *na_pivot_get_actions( const NAPivot *pivot );
-void     na_pivot_free_actions( GSList *actions );
+GSList   *na_pivot_get_actions( const NAPivot *pivot );
+void      na_pivot_reload_actions( NAPivot *pivot );
+GSList   *na_pivot_get_duplicate_actions( const NAPivot *pivot );
+void      na_pivot_free_actions( GSList *actions );
+void      na_pivot_add_action( NAPivot *pivot, const NAAction *action );
+void      na_pivot_remove_action( NAPivot *pivot, NAAction *action );
 
-GObject *na_pivot_get_action( NAPivot *pivot, const gchar *uuid );
-guint    na_pivot_write_action( NAPivot *pivot, const GObject *action, gchar **message );
-guint    na_pivot_delete_action( NAPivot *pivot, const GObject *action, gchar **message );
+NAAction *na_pivot_get_action( const NAPivot *pivot, const gchar *uuid );
+guint     na_pivot_write_action( const NAPivot *pivot, NAAction *action, gchar **message );
+guint     na_pivot_delete_action( const NAPivot *pivot, const NAAction *action, gchar **message );
+
+void      na_pivot_add_consumer( NAPivot *pivot, const GObject *consumer );
+
+gboolean  na_pivot_get_automatic_reload( const NAPivot *pivot );
+void      na_pivot_set_automatic_reload( NAPivot *pivot, gboolean reload );
 
 /* data passed from the storage subsystem when an action is changed
  */
@@ -99,8 +146,6 @@ typedef struct {
 
 void       na_pivot_free_notify( NAPivotNotify *data );
 
-void       na_pivot_add_notified( NAPivot *pivot, GObject *container );
-
 G_END_DECLS
 
 #endif /* __NA_PIVOT_H__ */
diff --git a/src/common/na-utils.c b/src/common/na-utils.c
index 131f7f0..5dee803 100644
--- a/src/common/na-utils.c
+++ b/src/common/na-utils.c
@@ -218,7 +218,7 @@ na_utils_dump_string_list( GSList *list )
 
 /**
  * Converts a list of strings to a comma-separated list of strings,
- * enclosed by brackets (GConf export format).
+ * enclosed by brackets (dump format, GConf export format).
  */
 gchar *
 na_utils_gslist_to_schema( GSList *list )
diff --git a/src/nact/Makefile.am b/src/nact/Makefile.am
index ae442d6..cb3da93 100644
--- a/src/nact/Makefile.am
+++ b/src/nact/Makefile.am
@@ -67,6 +67,8 @@ nautilus_actions_config_SOURCES = \
 	nact-icommand-tab.h									\
 	nact-iconditions-tab.c								\
 	nact-iconditions-tab.h								\
+	nact-imenubar.c										\
+	nact-imenubar.h										\
 	nact-iprefs.c										\
 	nact-iprefs.h										\
 	nact-main.c											\
diff --git a/src/nact/nact-application.c b/src/nact/nact-application.c
index b7e8dd7..b99d269 100644
--- a/src/nact/nact-application.c
+++ b/src/nact/nact-application.c
@@ -35,8 +35,6 @@
 #include <glib/gi18n.h>
 #include <gtk/gtk.h>
 
-#include <common/na-pivot.h>
-
 #include "nact-application.h"
 #include "nact-main-window.h"
 
@@ -60,7 +58,7 @@ enum {
 	PROP_PIVOT = 1
 };
 
-#define PROP_PIVOT_STR					"pivot"
+#define PROP_PIVOT_STR					"nact-application-pivot"
 
 static GObjectClass *st_parent_class = NULL;
 
@@ -306,7 +304,7 @@ get_main_window( BaseApplication *application )
 
 	GObject *window = G_OBJECT( nact_main_window_new( G_OBJECT( application )));
 
-	na_pivot_add_notified( NA_PIVOT( nact_application_get_pivot( NACT_APPLICATION( application ))), window );
+	na_pivot_add_consumer( NA_PIVOT( nact_application_get_pivot( NACT_APPLICATION( application ))), window );
 
 	return( window );
 }
@@ -319,9 +317,9 @@ get_main_window( BaseApplication *application )
  * The returned pointer is owned by the NactApplication object.
  * It should not be freed not unref by the caller.
  */
-GObject *
+NAPivot *
 nact_application_get_pivot( NactApplication *application )
 {
 	g_assert( NACT_IS_APPLICATION( application ));
-	return( G_OBJECT( application->private->pivot ));
+	return( NA_PIVOT( application->private->pivot ));
 }
diff --git a/src/nact/nact-application.h b/src/nact/nact-application.h
index 0f26421..3232965 100644
--- a/src/nact/nact-application.h
+++ b/src/nact/nact-application.h
@@ -37,6 +37,8 @@
  * This is the main class for UI programs.
  */
 
+#include <common/na-pivot.h>
+
 #include "base-application.h"
 
 G_BEGIN_DECLS
@@ -68,7 +70,7 @@ GType            nact_application_get_type( void );
 
 NactApplication *nact_application_new_with_args( int argc, char **argv );
 
-GObject         *nact_application_get_pivot( NactApplication *application );
+NAPivot         *nact_application_get_pivot( NactApplication *application );
 
 G_END_DECLS
 
diff --git a/src/nact/nact-assist-import.c b/src/nact/nact-assist-import.c
index 13e7f73..d90a2d3 100644
--- a/src/nact/nact-assist-import.c
+++ b/src/nact/nact-assist-import.c
@@ -499,7 +499,7 @@ do_import( NactAssistImport *window, GtkAssistant *assistant )
 		msg = NULL;
 		NAAction *action = nact_gconf_reader_import( G_OBJECT( window ), ( const gchar * ) is->data, &msg );
 
-		if( action && na_pivot_write_action( pivot, G_OBJECT( action ), &error ) != NA_IIO_PROVIDER_WRITE_OK ){
+		if( action && na_pivot_write_action( pivot, action, &error ) != NA_IIO_PROVIDER_WRITE_OK ){
 			g_object_unref( action );
 			action = NULL;
 			msg = g_slist_append( msg, error );
diff --git a/src/nact/nact-gconf-reader.c b/src/nact/nact-gconf-reader.c
index 2eab015..42d8b3b 100644
--- a/src/nact/nact-gconf-reader.c
+++ b/src/nact/nact-gconf-reader.c
@@ -334,7 +334,7 @@ gconf_reader_parse_schemalist( NactGConfReader *reader, xmlNode *schema )
 
 	xmlNode *iter;
 
-	reader->private->action = na_action_new( NULL );
+	reader->private->action = na_action_new();
 	reader->private->uuid_set = FALSE;
 
 	for( iter = schema->children ; iter ; iter = iter->next ){
@@ -554,7 +554,7 @@ gconf_reader_parse_applyto( NactGConfReader *reader, xmlNode *node )
 	if( ret ){
 		if( !reader->private->uuid_set ){
 
-			GObject *object = na_pivot_get_action( reader->private->pivot, uuid );
+			NAAction *object = na_pivot_get_action( reader->private->pivot, uuid );
 			if( object ){
 				add_message( reader, ERR_UUID_ALREADY_EXISTS, uuid );
 				ret = FALSE;
@@ -581,8 +581,8 @@ gconf_reader_parse_applyto( NactGConfReader *reader, xmlNode *node )
 			reader->private->profile = NA_ACTION_PROFILE( na_action_get_profile( reader->private->action, profile ));
 
 			if( !reader->private->profile ){
-				reader->private->profile = na_action_profile_new( NA_OBJECT( reader->private->action ), profile );
-				na_action_add_profile( reader->private->action, NA_OBJECT( reader->private->profile ));
+				reader->private->profile = na_action_profile_new();
+				na_action_attach_profile( reader->private->action, reader->private->profile );
 			}
 		}
 
diff --git a/src/nact/nact-iaction-tab.c b/src/nact/nact-iaction-tab.c
index 336b6c2..034ce9a 100644
--- a/src/nact/nact-iaction-tab.c
+++ b/src/nact/nact-iaction-tab.c
@@ -51,14 +51,21 @@ enum {
 	ICON_N_COLUMN
 };
 
+/* IActionTab properties, set on the main window
+ */
+#define PROP_IACTION_TAB_STATUS_CONTEXT	"nact-iaction-tab-status-context"
+
 static GType         register_type( void );
 static void          interface_base_init( NactIActionTabInterface *klass );
 static void          interface_base_finalize( NactIActionTabInterface *klass );
 
+static GtkWidget    *v_get_status_bar( NactWindow *window );
+static NAObject     *v_get_selected( NactWindow *window );
 static NAAction     *v_get_edited_action( NactWindow *window );
 static void          v_field_modified( NactWindow *window );
 
 static void          on_label_changed( GtkEntry *entry, gpointer user_data );
+static void          check_for_label( NactWindow *window, GtkEntry *entry, const gchar *label );
 static void          on_tooltip_changed( GtkEntry *entry, gpointer user_data );
 static void          on_icon_changed( GtkEntry *entry, gpointer user_data );
 static void          on_icon_browse( GtkButton *button, gpointer user_data );
@@ -68,6 +75,11 @@ static gint          sort_stock_ids( gconstpointer a, gconstpointer b );
 static gchar        *strip_underscore( const gchar *text );
 static void          display_icon( NactWindow *window, GtkWidget *image, gboolean display );
 
+static void          display_status( NactWindow *window, const gchar *status );
+static void          hide_status( NactWindow *window );
+static guint         get_status_context( NactWindow *window );
+static void          set_status_context( NactWindow *window, guint context );
+
 GType
 nact_iaction_tab_get_type( void )
 {
@@ -147,6 +159,13 @@ nact_iaction_tab_initial_load( NactWindow *dialog )
 	GtkWidget *icon_widget = base_window_get_widget( BASE_WINDOW( dialog ), "ActionIconComboBoxEntry" );
 	gtk_combo_box_set_model( GTK_COMBO_BOX( icon_widget ), create_stock_icon_model());
 	icon_combo_list_fill( GTK_COMBO_BOX_ENTRY( icon_widget ));
+
+	GtkWidget *status_bar = v_get_status_bar( dialog );
+	if( status_bar ){
+		g_assert( GTK_IS_STATUSBAR( status_bar ));
+		guint context = gtk_statusbar_get_context_id( GTK_STATUSBAR( status_bar ), "nact-iaction-tab" );
+		set_status_context( dialog, context );
+	}
 }
 
 void
@@ -185,26 +204,45 @@ nact_iaction_tab_dispose( NactWindow *dialog )
 	g_debug( "%s: dialog=%p", thisfn, dialog );
 }
 
+/*
+ * disable the tab if current row is a profile and the action has more
+ * than one profile
+ */
 void
 nact_iaction_tab_set_action( NactWindow *dialog, const NAAction *action )
 {
 	/*static const gchar *thisfn = "nact_iaction_tab_set_action";
 	g_debug( "%s: dialog=%p, action=%p", thisfn, dialog, action );*/
 
+	NAObject *current = v_get_selected( dialog );
+	gboolean enabled = TRUE;
+	if( NA_IS_ACTION_PROFILE( current)){
+		if( na_action_get_profiles_count( action ) > 1 ){
+			enabled = FALSE;
+		}
+	}
+
 	GtkWidget *label_widget = base_window_get_widget( BASE_WINDOW( dialog ), "ActionLabelEntry" );
 	gchar *label = na_action_get_label( action );
 	gtk_entry_set_text( GTK_ENTRY( label_widget ), label );
+	gtk_widget_set_sensitive( label_widget, enabled );
+	check_for_label( dialog, GTK_ENTRY( label_widget ), label );
 	g_free( label );
 
 	GtkWidget *tooltip_widget = base_window_get_widget( BASE_WINDOW( dialog ), "ActionTooltipEntry" );
 	gchar *tooltip = na_action_get_tooltip( action );
 	gtk_entry_set_text( GTK_ENTRY( tooltip_widget ), tooltip );
+	gtk_widget_set_sensitive( tooltip_widget, enabled );
 	g_free( tooltip );
 
 	GtkWidget *icon_widget = base_window_get_widget( BASE_WINDOW( dialog ), "ActionIconComboBoxEntry" );
 	gchar *icon = na_action_get_icon( action );
 	gtk_entry_set_text( GTK_ENTRY( GTK_BIN( icon_widget )->child ), icon );
+	gtk_widget_set_sensitive( icon_widget, enabled );
 	g_free( icon );
+
+	GtkWidget *button = base_window_get_widget( BASE_WINDOW( dialog ), "ActionIconBrowseButton" );
+	gtk_widget_set_sensitive( button, enabled );
 }
 
 /**
@@ -219,6 +257,28 @@ nact_iaction_tab_has_label( NactWindow *window )
 	return( g_utf8_strlen( label, -1 ) > 0 );
 }
 
+static GtkWidget *
+v_get_status_bar( NactWindow *window )
+{
+	if( NACT_IACTION_TAB_GET_INTERFACE( window )->get_status_bar ){
+		return( NACT_IACTION_TAB_GET_INTERFACE( window )->get_status_bar( window ));
+	}
+
+	return( NULL );
+}
+
+static NAObject *
+v_get_selected( NactWindow *window )
+{
+	g_assert( NACT_IS_IACTION_TAB( window ));
+
+	if( NACT_IACTION_TAB_GET_INTERFACE( window )->get_selected ){
+		return( NACT_IACTION_TAB_GET_INTERFACE( window )->get_selected( window ));
+	}
+
+	return( NULL );
+}
+
 static NAAction *
 v_get_edited_action( NactWindow *window )
 {
@@ -248,9 +308,34 @@ on_label_changed( GtkEntry *entry, gpointer user_data )
 	NactWindow *dialog = NACT_WINDOW( user_data );
 
 	NAAction *edited = v_get_edited_action( dialog );
-	na_action_set_label( edited, gtk_entry_get_text( entry ));
+	const gchar *label = gtk_entry_get_text( entry );
+	na_action_set_label( edited, label );
+
+	/* 2009-07-20: about 900-1200 usec for ten loops */
+	/*int i;
+	GTimeVal begin, end;
+	g_get_current_time( &begin );
+	for( i=0 ; i<10 ; ++i ){
+		v_field_modified( dialog );
+	}
+	g_get_current_time( &end );
+	g_debug( "on_label_changed: %ld usec", ( 1000000 * ( end.tv_sec - begin.tv_sec )) + end.tv_usec - begin.tv_usec );*/
 
 	v_field_modified( dialog );
+	check_for_label( dialog, entry, label );
+}
+
+static void
+check_for_label( NactWindow *window, GtkEntry *entry, const gchar *label )
+{
+	hide_status( window );
+
+	NAAction *edited = v_get_edited_action( window );
+
+	if( edited && g_utf8_strlen( label, -1 ) == 0 ){
+		/* i18n: status bar message when the action label is empty */
+		display_status( window, _( "Caution: a label is mandatory for the action." ));
+	}
 }
 
 static void
@@ -467,3 +552,31 @@ display_icon( NactWindow *window, GtkWidget *image, gboolean show )
 		gtk_frame_set_shadow_type( frame, GTK_SHADOW_IN );
 	}
 }
+
+static void
+display_status( NactWindow *window, const gchar *status )
+{
+	GtkWidget *bar = v_get_status_bar( window );
+	guint context = get_status_context( window );
+	gtk_statusbar_push( GTK_STATUSBAR( bar ), context, status );
+}
+
+static void
+hide_status( NactWindow *window )
+{
+	GtkWidget *bar = v_get_status_bar( window );
+	guint context = get_status_context( window );
+	gtk_statusbar_pop( GTK_STATUSBAR( bar ), context );
+}
+
+static guint
+get_status_context( NactWindow *window )
+{
+	return( GPOINTER_TO_UINT( g_object_get_data( G_OBJECT( window ), PROP_IACTION_TAB_STATUS_CONTEXT )));
+}
+
+static void
+set_status_context( NactWindow *window, guint context )
+{
+	g_object_set_data( G_OBJECT( window ), PROP_IACTION_TAB_STATUS_CONTEXT, GUINT_TO_POINTER( context ));
+}
diff --git a/src/nact/nact-iaction-tab.h b/src/nact/nact-iaction-tab.h
index a304a31..4939879 100644
--- a/src/nact/nact-iaction-tab.h
+++ b/src/nact/nact-iaction-tab.h
@@ -51,12 +51,14 @@ typedef struct NactIActionTab NactIActionTab;
 typedef struct NactIActionTabInterfacePrivate NactIActionTabInterfacePrivate;
 
 typedef struct {
-	GTypeInterface                 parent;
+	GTypeInterface                  parent;
 	NactIActionTabInterfacePrivate *private;
 
 	/* api */
-	NAAction * ( *get_edited_action )( NactWindow *window );
-	void       ( *field_modified )   ( NactWindow *window );
+	GtkWidget * ( *get_status_bar )   ( NactWindow *window );
+	NAObject *  ( *get_selected )     ( NactWindow *window );
+	NAAction *  ( *get_edited_action )( NactWindow *window );
+	void        ( *field_modified )   ( NactWindow *window );
 }
 	NactIActionTabInterface;
 
diff --git a/src/nact/nact-iactions-list.c b/src/nact/nact-iactions-list.c
index 73e251b..4ffbbf3 100644
--- a/src/nact/nact-iactions-list.c
+++ b/src/nact/nact-iactions-list.c
@@ -33,6 +33,7 @@
 #endif
 
 #include <gdk/gdkkeysyms.h>
+#include <string.h>
 
 #include <common/na-action.h>
 
@@ -67,12 +68,20 @@ static GSList    *v_get_actions( NactWindow *window );
 static void       v_on_selection_changed( GtkTreeSelection *selection, gpointer user_data );
 static gboolean   v_on_button_press_event( GtkWidget *widget, GdkEventButton *event, gpointer data );
 static gboolean   v_on_key_pressed_event( GtkWidget *widget, GdkEventKey *event, gpointer data );
+static gboolean   v_is_modified_action( NactWindow *window, const NAAction *action );
+static gboolean   v_is_valid_action( NactWindow *window, const NAAction *action );
+static gboolean   v_is_modified_profile( NactWindow *window, const NAActionProfile *profile );
+static gboolean   v_is_valid_profile( NactWindow *window, const NAActionProfile *profile );
 
+static void       display_label( GtkTreeViewColumn *column, GtkCellRenderer *cell, GtkTreeModel *model, GtkTreeIter *iter, NactWindow *window );
 static void       setup_action( GtkWidget *treeview, GtkTreeStore *model, GtkTreeIter *iter, NAAction *action );
 static void       setup_profile( GtkWidget *treeview, GtkTreeStore *model, GtkTreeIter *iter, NAActionProfile *profile );
 static gint       sort_actions_list( GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b, NactWindow *window );
 static gboolean   filter_visible( GtkTreeModel *model, GtkTreeIter *iter, gpointer data );
 static GtkWidget *get_actions_list_widget( NactWindow *window );
+static GSList    *get_expanded_rows( NactWindow *window );
+static void       expand_rows( NactWindow *window, GSList *expanded );
+static void       free_expanded_list( GSList *expanded );
 
 GType
 nact_iactions_list_get_type( void )
@@ -186,8 +195,15 @@ nact_iactions_list_initial_load( NactWindow *window )
 			"icon", gtk_cell_renderer_pixbuf_new(), "pixbuf", IACTIONS_LIST_ICON_COLUMN, NULL );
 	gtk_tree_view_append_column( GTK_TREE_VIEW( widget ), column );
 
-	column = gtk_tree_view_column_new_with_attributes(
-			"label", gtk_cell_renderer_text_new(), "text", IACTIONS_LIST_LABEL_COLUMN, NULL );
+	/*column = gtk_tree_view_column_new_with_attributes(
+			"label", gtk_cell_renderer_text_new(), "text", IACTIONS_LIST_LABEL_COLUMN, NULL );*/
+	column = gtk_tree_view_column_new();
+	gtk_tree_view_column_set_title( column, "label" );
+	gtk_tree_view_column_set_sort_column_id( column, IACTIONS_LIST_LABEL_COLUMN );
+	GtkCellRenderer *renderer = gtk_cell_renderer_text_new();
+	gtk_tree_view_column_pack_start( column, renderer, TRUE );
+	gtk_tree_view_column_set_cell_data_func(
+			column, renderer, ( GtkTreeCellDataFunc ) display_label, window, NULL );
 	gtk_tree_view_append_column( GTK_TREE_VIEW( widget ), column );
 }
 
@@ -206,7 +222,7 @@ nact_iactions_list_runtime_init( NactWindow *window )
 	GtkWidget *widget = get_actions_list_widget( window );
 	g_assert( GTK_IS_WIDGET( widget ));
 
-	nact_iactions_list_fill( window );
+	nact_iactions_list_fill( window, TRUE );
 
 	/* set up selection */
 	nact_window_signal_connect(
@@ -238,7 +254,7 @@ nact_iactions_list_runtime_init( NactWindow *window )
  * Fill the listbox with current actions.
  */
 void
-nact_iactions_list_fill( NactWindow *window )
+nact_iactions_list_fill( NactWindow *window, gboolean keep_expanded )
 {
 	static const gchar *thisfn = "nact_iactions_list_fill";
 	g_debug( "%s: window=%p", thisfn, window );
@@ -247,6 +263,11 @@ nact_iactions_list_fill( NactWindow *window )
 
 	nact_iactions_list_set_is_filling_list( window, TRUE );
 
+	GSList *expanded = NULL;
+	if( keep_expanded ){
+		expanded = get_expanded_rows( window );
+	}
+
 	GtkWidget *widget = get_actions_list_widget( window );
 	GtkTreeModelFilter *tmf_model = GTK_TREE_MODEL_FILTER( gtk_tree_view_get_model( GTK_TREE_VIEW( widget )));
 	GtkTreeStore *ts_model = GTK_TREE_STORE( gtk_tree_model_filter_get_model( tmf_model ));
@@ -254,7 +275,7 @@ nact_iactions_list_fill( NactWindow *window )
 
 	GSList *actions = v_get_actions( window );
 	GSList *ia;
-	/*g_debug( "%s: actions has %d elements", thisfn, g_slist_length( actions ));*/
+	g_debug( "%s: actions has %d elements", thisfn, g_slist_length( actions ));
 
 	for( ia = actions ; ia != NULL ; ia = ia->next ){
 		GtkTreeIter iter;
@@ -276,60 +297,164 @@ nact_iactions_list_fill( NactWindow *window )
 	}
 	/*g_debug( "%s: at end, actions has %d elements", thisfn, g_slist_length( actions ));*/
 
+	if( keep_expanded ){
+		expand_rows( window, expanded );
+		free_expanded_list( expanded );
+	}
+
 	nact_iactions_list_set_is_filling_list( window, FALSE );
 }
 
 /**
- * Set the selection to the named action.
- * If not found, we select the first following, else the previous one.
+ * Set the selection to the specified object.
+ *
+ * @type: select a profile or an action
+ * @uuid: uuid of the relevant action
+ * @label: label of the action, or of the profile
+ *
+ * if we want select an action:
+ * - set type = NA_ACTION_TYPE
+ * - set uuid = uuid of the action
+ * - set label = label of the action
+ *
+ * we are going to select:
+ * - an action
+ * - whose uuid is the requested uuid
+ * - or whose label is the most close of the required label (if uuid is not found)
+ *
+ * if we want select a profile
+ * - set type = NA_ACTION_PROFILE_TYPE
+ * - set uuid = uuid of the parent action
+ * - set label = label of the profile
+ *
+ * we are going to select:
+ * a) if the action is found
+ *    a.1) if the action has more than one profile
+ *         - a profile of the action
+ *         - whose label is the most close of the required one
+ *    a.2) if the action has only one profile
+ *         - the action
+ * b) if the action is not found
+ *    the last action of the list (this case should not appear)
  */
-/*void
-nact_iactions_list_set_selection( NactWindow *window, const gchar *uuid, const gchar *label )
+void
+nact_iactions_list_set_selection( NactWindow *window, GType type, const gchar *uuid, const gchar *label )
 {
 	static const gchar *thisfn = "nact_iactions_list_set_selection";
-	g_debug( "%s: window=%p, uuid=%s, label=%s", thisfn, window, uuid, label );
+	g_debug( "%s: window=%p, type=%s, uuid=%s, label=%s", thisfn, window, type == NA_ACTION_TYPE ? "action":"profile", uuid, label );
 
 	GtkWidget *list = get_actions_list_widget( window );
 	GtkTreeSelection *selection = gtk_tree_view_get_selection( GTK_TREE_VIEW( list ));
+	/*GtkTreeModelFilter *tmf_model = GTK_TREE_MODEL_FILTER( gtk_tree_view_get_model( GTK_TREE_VIEW( list )));
+	GtkTreeStore *ts_model = GTK_TREE_STORE( gtk_tree_model_filter_get_model( tmf_model ));*/
 	GtkTreeModel *model = gtk_tree_view_get_model( GTK_TREE_VIEW( list ));
-	GtkTreeIter iter, previous;
 
-	gtk_tree_selection_unselect_all( selection );
+	if( uuid && strlen( uuid )){
+		gboolean found = FALSE;
+		GtkTreeIter iter, previous;
+		/*gboolean iterok = gtk_tree_model_get_iter_first( GTK_TREE_MODEL( ts_model ), &iter );*/
+		gboolean iterok = gtk_tree_model_get_iter_first( model, &iter );
+		NAObject *iter_object;
+		gchar *iter_uuid, *iter_label;
+
+		while( iterok && !found ){
+			/*gtk_tree_model_get( GTK_TREE_MODEL( ts_model ), &iter, IACTIONS_LIST_NAOBJECT_COLUMN, &iter_object, -1 );*/
+			gtk_tree_model_get( model, &iter, IACTIONS_LIST_NAOBJECT_COLUMN, &iter_object, IACTIONS_LIST_LABEL_COLUMN, &iter_label, -1 );
+			g_debug( "%s: iter_object=%p", thisfn, iter_object );
+			g_assert( NA_IS_ACTION( iter_object ));
+
+			iter_uuid = na_action_get_uuid( NA_ACTION( iter_object ));
+			gint ret_uuid = g_ascii_strcasecmp( iter_uuid, uuid );
+			guint nb_profiles = na_action_get_profiles_count( NA_ACTION( iter_object ));
+
+			if( type == NA_ACTION_TYPE || ( ret_uuid == 0 && nb_profiles == 1 )){
+				gint ret_label = g_utf8_collate( iter_label, label );
+
+				if( ret_uuid == 0 || ret_label > 0 ){
+					gtk_tree_selection_select_iter( selection, &iter );
+					found = TRUE;
+					break;
+				}
 
-	gboolean iterok = gtk_tree_model_get_iter_first( model, &iter );
-	gboolean found = FALSE;
-	NAAction *action;
-	gchar *iter_uuid, *iter_label;
-	gint count = 0;
-
-	while( iterok && !found ){
-		count += 1;
-		gtk_tree_model_get(
-				model,
-				&iter,
-				IACTIONS_LIST_NAOBJECT_COLUMN, &action, IACTIONS_LIST_LABEL_COLUMN, &iter_label,
-				-1 );
-
-		iter_uuid = na_action_get_uuid( action );
-		gint ret_uuid = g_ascii_strcasecmp( iter_uuid, uuid );
-		gint ret_label = g_utf8_collate( iter_label, label );
-		if(( ret_uuid == 0 && ret_label == 0 ) || ret_label > 0 ){
-			gtk_tree_selection_select_iter( selection, &iter );
-			found = TRUE;
+			} else if( ret_uuid == 0 && gtk_tree_model_iter_has_child( model, &iter )){
+				GtkTreeIter iter_child, previous_child;
+				gboolean iter_child_ok = gtk_tree_model_iter_children( model, &iter_child, &iter );
+
+				while( iter_child_ok ){
+					gtk_tree_model_get( model, &iter_child, IACTIONS_LIST_NAOBJECT_COLUMN, &iter_object, IACTIONS_LIST_LABEL_COLUMN, &iter_label, -1 );
+					gint ret_label = g_utf8_collate( iter_label, label );
+
+					if( ret_label >= 0 ){
+						gtk_tree_selection_select_iter( selection, &iter_child );
+						found = TRUE;
+						break;
+					}
+					previous_child = iter_child;
+					iter_child_ok = gtk_tree_model_iter_next( model, &iter_child );
+				}
+				if( !found ){
+					gtk_tree_selection_select_iter( selection, &previous_child );
+					found = TRUE;
+				}
+			}
 
-		} else {
 			previous = iter;
+			/*iterok = gtk_tree_model_iter_next( GTK_TREE_MODEL( ts_model ), &iter );*/
+			iterok = gtk_tree_model_iter_next( model, &iter );
+		}
+		if( !found ){
+			gtk_tree_selection_select_iter( selection, &previous );
 		}
 
-		g_free( iter_uuid );
-		g_free( iter_label );
-		iterok = gtk_tree_model_iter_next( model, &iter );
+	} else {
+		gtk_tree_selection_unselect_all( selection );
 	}
+	/*
+		static const gchar *thisfn = "nact_iactions_list_set_selection";
+		g_debug( "%s: window=%p, uuid=%s, label=%s", thisfn, window, uuid, label );
+
+		GtkWidget *list = get_actions_list_widget( window );
+		GtkTreeSelection *selection = gtk_tree_view_get_selection( GTK_TREE_VIEW( list ));
+		GtkTreeModel *model = gtk_tree_view_get_model( GTK_TREE_VIEW( list ));
+		GtkTreeIter iter, previous;
+
+		gtk_tree_selection_unselect_all( selection );
+
+		gboolean iterok = gtk_tree_model_get_iter_first( model, &iter );
+		gboolean found = FALSE;
+		NAAction *action;
+		gchar *iter_uuid, *iter_label;
+		gint count = 0;
+
+		while( iterok && !found ){
+			count += 1;
+			gtk_tree_model_get(
+					model,
+					&iter,
+					IACTIONS_LIST_NAOBJECT_COLUMN, &action, IACTIONS_LIST_LABEL_COLUMN, &iter_label,
+					-1 );
+
+			iter_uuid = na_action_get_uuid( action );
+			gint ret_uuid = g_ascii_strcasecmp( iter_uuid, uuid );
+			gint ret_label = g_utf8_collate( iter_label, label );
+			if(( ret_uuid == 0 && ret_label == 0 ) || ret_label > 0 ){
+				gtk_tree_selection_select_iter( selection, &iter );
+				found = TRUE;
+
+			} else {
+				previous = iter;
+			}
 
-	if( !found && count ){
-		gtk_tree_selection_select_iter( selection, &previous );
-	}
-}*/
+			g_free( iter_uuid );
+			g_free( iter_label );
+			iterok = gtk_tree_model_iter_next( model, &iter );
+		}
+
+		if( !found && count ){
+			gtk_tree_selection_select_iter( selection, &previous );
+		}
+	 */
+}
 
 /**
  * Reset the focus on the ActionsList listbox.
@@ -345,16 +470,22 @@ nact_iactions_list_set_focus( NactWindow *window )
  * Returns the currently selected action or profile.
  */
 NAObject *
-nact_iactions_list_get_selected_action( NactWindow *window )
+nact_iactions_list_get_selected_object( NactWindow *window )
 {
-	GSList *list = nact_iactions_list_get_selected_actions( window );
+	NAObject *object = NULL;
 
-	NAObject *object = NA_OBJECT( list->data );
+	GtkWidget *treeview = get_actions_list_widget( window );
+	GtkTreeSelection *selection = gtk_tree_view_get_selection( GTK_TREE_VIEW( treeview ));
 
-	g_assert( object );
-	g_assert( NA_IS_OBJECT( object ));
+	GtkTreeModel *tm_model;
+	GtkTreeIter iter;
+	if( gtk_tree_selection_get_selected( selection, &tm_model, &iter )){
+
+		gtk_tree_model_get( tm_model, &iter, IACTIONS_LIST_NAOBJECT_COLUMN, &object, -1 );
 
-	g_slist_free( list );
+		g_assert( object );
+		g_assert( NA_IS_OBJECT( object ));
+	}
 
 	return( object );
 }
@@ -393,36 +524,76 @@ nact_iactions_list_get_selected_actions( NactWindow *window )
 	return( actions );
 }
 
-
-void
+/*void
 nact_iactions_list_set_modified( NactWindow *window, gboolean is_modified, gboolean can_save )
 {
+}*/
+
+gboolean
+nact_iactions_list_is_expanded( NactWindow *window, const NAAction *action )
+{
+	GtkWidget *treeview = get_actions_list_widget( window );
+	GtkTreeModel *model = gtk_tree_view_get_model( GTK_TREE_VIEW( treeview ));
+
+	gboolean is_expanded = FALSE;
+	GtkTreeIter iter;
+	gboolean iterok = gtk_tree_model_get_iter_first( model, &iter );
+	NAObject *iter_object;
+
+	while( iterok ){
+		gtk_tree_model_get( model, &iter, IACTIONS_LIST_NAOBJECT_COLUMN, &iter_object, -1 );
+
+		if( iter_object == NA_OBJECT( action )){
+			GtkTreePath *path = gtk_tree_model_get_path( model, &iter );
+			is_expanded = gtk_tree_view_row_expanded( GTK_TREE_VIEW( treeview ), path );
+			gtk_tree_path_free( path );
+			break;
+		}
+
+		iterok = gtk_tree_model_iter_next( model, &iter );
+	}
+
+	return( is_expanded );
 }
 
 /*
  * Collapse / expand if actions has more than one profile
  */
 void
-nact_iactions_list_toggle_collapse( NactWindow *window )
-{
-	NAObject *object = nact_iactions_list_get_selected_action( window );
-	if( NA_IS_ACTION( object )){
-		NAAction *action = NA_ACTION( object );
-		if( na_action_get_profiles_count( action ) > 1 ){
-			GtkWidget *treeview = get_actions_list_widget( window );
-			GtkTreeSelection *selection = gtk_tree_view_get_selection( GTK_TREE_VIEW( treeview ));
-			GtkTreeModel *model;
-			GtkTreeIter iter;
-			if( gtk_tree_selection_get_selected( selection, &model, &iter )){
+nact_iactions_list_toggle_collapse( NactWindow *window, const NAAction *action )
+{
+	static const gchar *thisfn = "nact_iactions_list_toggle_collapse";
+
+	GtkWidget *treeview = get_actions_list_widget( window );
+	GtkTreeModel *model = gtk_tree_view_get_model( GTK_TREE_VIEW( treeview ));
+
+	GtkTreeIter iter;
+	gboolean iterok = gtk_tree_model_get_iter_first( model, &iter );
+
+	while( iterok ){
+
+		NAObject *iter_object;
+		gtk_tree_model_get( model, &iter, IACTIONS_LIST_NAOBJECT_COLUMN, &iter_object, -1 );
+		if( iter_object == NA_OBJECT( action )){
+
+			if( na_action_get_profiles_count( action ) > 1 ){
+
 				GtkTreePath *path = gtk_tree_model_get_path( model, &iter );
+
 				if( gtk_tree_view_row_expanded( GTK_TREE_VIEW( treeview ), path )){
 					gtk_tree_view_collapse_row( GTK_TREE_VIEW( treeview ), path );
+					g_debug( "%s: action=%p collapsed", thisfn, action );
+
 				} else {
 					gtk_tree_view_expand_row( GTK_TREE_VIEW( treeview ), path, TRUE );
+					g_debug( "%s: action=%p expanded", thisfn, action );
 				}
+
 				gtk_tree_path_free( path );
 			}
+			break;
 		}
+		iterok = gtk_tree_model_iter_next( model, &iter );
 	}
 }
 
@@ -610,10 +781,98 @@ v_on_key_pressed_event( GtkWidget *widget, GdkEventKey *event, gpointer user_dat
 				stop = NACT_IACTIONS_LIST_GET_INTERFACE( instance )->on_enter_key_pressed( widget, event, user_data );
 			}
 		}
+		if( event->keyval == GDK_Delete || event->keyval == GDK_KP_Delete ){
+			if( NACT_IACTIONS_LIST_GET_INTERFACE( instance )->on_delete_key_pressed ){
+				stop = NACT_IACTIONS_LIST_GET_INTERFACE( instance )->on_delete_key_pressed( widget, event, user_data );
+			}
+		}
 	}
 	return( stop );
 }
 
+static gboolean
+v_is_modified_action( NactWindow *window, const NAAction *action )
+{
+	if( NACT_IACTIONS_LIST_GET_INTERFACE( window )->is_modified_action ){
+		return( NACT_IACTIONS_LIST_GET_INTERFACE( window )->is_modified_action( window, action ));
+	}
+
+	return( FALSE );
+}
+
+static gboolean
+v_is_valid_action( NactWindow *window, const NAAction *action )
+{
+	if( NACT_IACTIONS_LIST_GET_INTERFACE( window )->is_valid_action ){
+		return( NACT_IACTIONS_LIST_GET_INTERFACE( window )->is_valid_action( window, action ));
+	}
+
+	return( FALSE );
+}
+
+static gboolean
+v_is_modified_profile( NactWindow *window, const NAActionProfile *profile )
+{
+	if( NACT_IACTIONS_LIST_GET_INTERFACE( window )->is_modified_profile ){
+		return( NACT_IACTIONS_LIST_GET_INTERFACE( window )->is_modified_profile( window, profile ));
+	}
+
+	return( FALSE );
+}
+
+static gboolean
+v_is_valid_profile( NactWindow *window, const NAActionProfile *profile )
+{
+	if( NACT_IACTIONS_LIST_GET_INTERFACE( window )->is_valid_profile ){
+		return( NACT_IACTIONS_LIST_GET_INTERFACE( window )->is_valid_profile( window, profile ));
+	}
+
+	return( FALSE );
+}
+
+/*
+ * action modified: italic
+ * action not saveable: red
+ */
+static void
+display_label( GtkTreeViewColumn *column, GtkCellRenderer *cell, GtkTreeModel *model, GtkTreeIter *iter, NactWindow *window )
+{
+	NAObject *object;
+	gtk_tree_model_get( model, iter, IACTIONS_LIST_NAOBJECT_COLUMN, &object, -1 );
+
+	if( object ){
+		g_assert( NA_IS_OBJECT( object ));
+		gchar *label = na_object_get_label( object );
+		gboolean modified = FALSE;
+		gboolean valid = TRUE;
+
+		if( NA_IS_ACTION( object )){
+			modified = v_is_modified_action( window, NA_ACTION( object ));
+			valid = v_is_valid_action( window, NA_ACTION( object ));
+
+		} else {
+			g_assert( NA_IS_ACTION_PROFILE( object ));
+			modified = v_is_modified_profile( window, NA_ACTION_PROFILE( object ));
+			valid = v_is_valid_profile( window, NA_ACTION_PROFILE( object ));
+		}
+
+		if( modified ){
+			g_object_set( cell, "style", PANGO_STYLE_ITALIC, "style-set", TRUE, NULL );
+		} else {
+			g_object_set( cell, "style-set", FALSE, NULL );
+		}
+		if( valid ){
+			g_object_set( cell, "foreground-set", FALSE, NULL );
+		} else {
+			g_object_set( cell, "foreground", "Red", "foreground-set", TRUE, NULL );
+		}
+
+		g_object_set( cell, "text", label, NULL );
+
+		g_free( label );
+	}
+}
+
 static void
 setup_action( GtkWidget *treeview, GtkTreeStore *model, GtkTreeIter *iter, NAAction *action )
 {
@@ -685,6 +944,7 @@ filter_visible( GtkTreeModel *model, GtkTreeIter *iter, gpointer data )
 {
 	NAObject *object;
 	gtk_tree_model_get( model, iter, IACTIONS_LIST_NAOBJECT_COLUMN, &object, -1 );
+	/*g_debug( "nact_main_window_filer_visible: model=%p, iter=%p, data=%p, object=%p", model, iter, data, object );*/
 
 	if( object ){
 		if( NA_IS_ACTION( object )){
@@ -692,7 +952,7 @@ filter_visible( GtkTreeModel *model, GtkTreeIter *iter, gpointer data )
 		}
 
 		g_assert( NA_IS_ACTION_PROFILE( object ));
-		NAAction *action = NA_ACTION( na_action_profile_get_action( NA_ACTION_PROFILE( object )));
+		NAAction *action = na_action_profile_get_action( NA_ACTION_PROFILE( object ));
 		return( na_action_get_profiles_count( action ) > 1 );
 	}
 
@@ -704,3 +964,66 @@ get_actions_list_widget( NactWindow *window )
 {
 	return( base_window_get_widget( BASE_WINDOW( window ), "ActionsList" ));
 }
+
+static GSList *
+get_expanded_rows( NactWindow *window )
+{
+	GSList *expanded = NULL;
+	GtkWidget *treeview = get_actions_list_widget( window );
+	GtkTreeModel *model = gtk_tree_view_get_model( GTK_TREE_VIEW( treeview ));
+
+	GtkTreeIter iter;
+	gboolean iterok = gtk_tree_model_get_iter_first( model, &iter );
+	NAObject *object;
+
+	while( iterok ){
+		gtk_tree_model_get( model, &iter, IACTIONS_LIST_NAOBJECT_COLUMN, &object, -1 );
+
+		GtkTreePath *path = gtk_tree_model_get_path( model, &iter );
+
+		if( gtk_tree_view_row_expanded( GTK_TREE_VIEW( treeview ), path )){
+			expanded = g_slist_prepend( expanded, object );
+		}
+
+		gtk_tree_path_free( path );
+
+		iterok = gtk_tree_model_iter_next( model, &iter );
+	}
+
+	return( expanded );
+}
+
+static void
+expand_rows( NactWindow *window, GSList *expanded )
+{
+	GtkWidget *treeview = get_actions_list_widget( window );
+	GtkTreeModel *model = gtk_tree_view_get_model( GTK_TREE_VIEW( treeview ));
+
+	GtkTreeIter iter;
+	gboolean iterok = gtk_tree_model_get_iter_first( model, &iter );
+	NAObject *object;
+
+	while( iterok ){
+		gtk_tree_model_get( model, &iter, IACTIONS_LIST_NAOBJECT_COLUMN, &object, -1 );
+
+		GSList *is;
+		for( is = expanded ; is ; is = is->next ){
+			if( object == NA_OBJECT( is->data )){
+
+				GtkTreePath *path = gtk_tree_model_get_path( model, &iter );
+				gtk_tree_view_expand_row( GTK_TREE_VIEW( treeview ), path, TRUE );
+				gtk_tree_path_free( path );
+
+				break;
+			}
+		}
+
+		iterok = gtk_tree_model_iter_next( model, &iter );
+	}
+}
+
+static void
+free_expanded_list( GSList *expanded )
+{
+	g_slist_free( expanded );
+}
diff --git a/src/nact/nact-iactions-list.h b/src/nact/nact-iactions-list.h
index 37e9bd6..f0d2f31 100644
--- a/src/nact/nact-iactions-list.h
+++ b/src/nact/nact-iactions-list.h
@@ -64,7 +64,12 @@ typedef struct {
 	gboolean ( *on_button_press_event )( GtkWidget *widget, GdkEventButton *event, gpointer data );
 	gboolean ( *on_key_pressed_event ) ( GtkWidget *widget, GdkEventKey *event, gpointer data );
 	gboolean ( *on_double_click )      ( GtkWidget *widget, GdkEventButton *event, gpointer data );
+	gboolean ( *on_delete_key_pressed )( GtkWidget *widget, GdkEventKey *event, gpointer data );
 	gboolean ( *on_enter_key_pressed ) ( GtkWidget *widget, GdkEventKey *event, gpointer data );
+	gboolean ( *is_modified_action )   ( NactWindow *window, const NAAction *action );
+	gboolean ( *is_valid_action )      ( NactWindow *window, const NAAction *action );
+	gboolean ( *is_modified_profile )  ( NactWindow *window, const NAActionProfile *profile );
+	gboolean ( *is_valid_profile )     ( NactWindow *window, const NAActionProfile *profile );
 }
 	NactIActionsListInterface;
 
@@ -72,13 +77,14 @@ GType     nact_iactions_list_get_type( void );
 
 void      nact_iactions_list_initial_load( NactWindow *window );
 void      nact_iactions_list_runtime_init( NactWindow *window );
-void      nact_iactions_list_fill( NactWindow *window );
-NAObject *nact_iactions_list_get_selected_action( NactWindow *window );
+void      nact_iactions_list_fill( NactWindow *window, gboolean keep_expanded );
+NAObject *nact_iactions_list_get_selected_object( NactWindow *window );
 GSList  * nact_iactions_list_get_selected_actions( NactWindow *window );
-/*void      nact_iactions_list_set_selection( NactWindow *window, const gchar *uuid, const gchar *label );*/
+void      nact_iactions_list_set_selection( NactWindow *window, GType type, const gchar *uuid, const gchar *label );
 /*void      nact_iactions_list_set_focus( NactWindow *window );*/
-void      nact_iactions_list_set_modified( NactWindow *window, gboolean is_modified, gboolean can_save );
-void      nact_iactions_list_toggle_collapse( NactWindow *window );
+/*void      nact_iactions_list_set_modified( NactWindow *window, gboolean is_modified, gboolean can_save );*/
+gboolean  nact_iactions_list_is_expanded( NactWindow *window, const NAAction *action );
+void      nact_iactions_list_toggle_collapse( NactWindow *window, const NAAction *action );
 void      nact_iactions_list_update_selected( NactWindow *window, NAAction *action );
 
 void      nact_iactions_list_set_multiple_selection( NactWindow *window, gboolean multiple );
diff --git a/src/nact/nact-icommand-tab.c b/src/nact/nact-icommand-tab.c
index c62317c..fde1b58 100644
--- a/src/nact/nact-icommand-tab.c
+++ b/src/nact/nact-icommand-tab.c
@@ -48,17 +48,22 @@ struct NactICommandTabInterfacePrivate {
 
 /* the GConf key used to read/write size and position of auxiliary dialogs
  */
-#define IPREFS_LEGEND_DIALOG		"iconditions-legend-dialog"
-#define IPREFS_COMMAND_CHOOSER		"iconditions-command-chooser"
+#define IPREFS_LEGEND_DIALOG				"iconditions-legend-dialog"
+#define IPREFS_COMMAND_CHOOSER				"iconditions-command-chooser"
 
 /* a data set in the LegendDialog GObject
  */
-#define LEGEND_DIALOG_IS_VISIBLE	"iconditions-legend-dialog-visible"
+#define LEGEND_DIALOG_IS_VISIBLE			"iconditions-legend-dialog-visible"
+
+/* ICommandTab properties, set on the main window
+ */
+#define PROP_ICOMMAND_TAB_STATUS_CONTEXT	"iconditions-status-context"
 
 static GType            register_type( void );
 static void             interface_base_init( NactICommandTabInterface *klass );
 static void             interface_base_finalize( NactICommandTabInterface *klass );
 
+static GtkWidget       *v_get_status_bar( NactWindow *window );
 static NAActionProfile *v_get_edited_profile( NactWindow *window );
 static void             v_field_modified( NactWindow *window );
 static void             v_get_isfiledir( NactWindow *window, gboolean *isfile, gboolean *isdir );
@@ -66,6 +71,7 @@ static gboolean         v_get_multiple( NactWindow *window );
 static GSList          *v_get_schemes( NactWindow *window );
 
 static void             on_label_changed( GtkEntry *entry, gpointer user_data );
+static void             check_for_label( NactWindow *window, GtkEntry *entry, const gchar *label );
 static GtkWidget       *get_label_entry( NactWindow *window );
 static void             on_path_changed( GtkEntry *entry, gpointer user_data );
 static void             on_path_browse( GtkButton *button, gpointer user_data );
@@ -81,6 +87,11 @@ static void             hide_legend_dialog( NactWindow *window );
 static GtkButton       *get_legend_button( NactWindow *window );
 static GtkWindow       *get_legend_dialog( NactWindow *window );
 
+static void             display_status( NactWindow *window, const gchar *status );
+static void             hide_status( NactWindow *window );
+static guint            get_status_context( NactWindow *window );
+static void             set_status_context( NactWindow *window, guint context );
+
 GType
 nact_icommand_tab_get_type( void )
 {
@@ -156,6 +167,13 @@ nact_icommand_tab_initial_load( NactWindow *dialog )
 {
 	static const gchar *thisfn = "nact_icommand_tab_initial_load";
 	g_debug( "%s: dialog=%p", thisfn, dialog );
+
+	GtkWidget *status_bar = v_get_status_bar( dialog );
+	if( status_bar ){
+		g_assert( GTK_IS_STATUSBAR( status_bar ));
+		guint context = gtk_statusbar_get_context_id( GTK_STATUSBAR( status_bar ), "nact-iaction-tab" );
+		set_status_context( dialog, context );
+	}
 }
 
 void
@@ -209,6 +227,7 @@ nact_icommand_tab_set_profile( NactWindow *dialog, const NAActionProfile *profil
 	gchar *label = profile ? na_action_profile_get_label( profile ) : g_strdup( "" );
 	gtk_entry_set_text( GTK_ENTRY( label_entry ), label );
 	gtk_widget_set_sensitive( label_entry, profile != NULL );
+	check_for_label( dialog, GTK_ENTRY( label_entry ), label );
 	g_free( label );
 
 	GtkWidget *path_entry = get_path_entry( dialog );
@@ -242,6 +261,16 @@ nact_icommand_tab_has_label( NactWindow *window )
 	return( g_utf8_strlen( label, -1 ) > 0 );
 }
 
+static GtkWidget *
+v_get_status_bar( NactWindow *window )
+{
+	if( NACT_ICOMMAND_TAB_GET_INTERFACE( window )->get_status_bar ){
+		return( NACT_ICOMMAND_TAB_GET_INTERFACE( window )->get_status_bar( window ));
+	}
+
+	return( NULL );
+}
+
 static NAActionProfile *
 v_get_edited_profile( NactWindow *window )
 {
@@ -308,10 +337,26 @@ on_label_changed( GtkEntry *entry, gpointer user_data )
 	g_assert( NACT_IS_WINDOW( user_data ));
 	NactWindow *dialog = NACT_WINDOW( user_data );
 
-	NAActionProfile *edited = NA_ACTION_PROFILE( v_get_edited_profile( dialog ));
+	NAActionProfile *edited = v_get_edited_profile( dialog );
+
 	if( edited ){
-		na_action_profile_set_label( edited, gtk_entry_get_text( entry ));
+		const gchar *label = gtk_entry_get_text( entry );
+		na_action_profile_set_label( edited, label );
 		v_field_modified( dialog );
+		check_for_label( dialog, entry, label );
+	}
+}
+
+static void
+check_for_label( NactWindow *window, GtkEntry *entry, const gchar *label )
+{
+	hide_status( window );
+
+	NAActionProfile *edited = v_get_edited_profile( window );
+
+	if( edited && g_utf8_strlen( label, -1 ) == 0 ){
+		/* i18n: status bar message when the profile label is empty */
+		display_status( window, _( "Caution: a label is mandatory for the profile." ));
 	}
 }
 
@@ -660,3 +705,31 @@ get_legend_dialog( NactWindow *window )
 {
 	return( base_window_get_dialog( BASE_WINDOW( window ), "LegendDialog" ));
 }
+
+static void
+display_status( NactWindow *window, const gchar *status )
+{
+	GtkWidget *bar = v_get_status_bar( window );
+	guint context = get_status_context( window );
+	gtk_statusbar_push( GTK_STATUSBAR( bar ), context, status );
+}
+
+static void
+hide_status( NactWindow *window )
+{
+	GtkWidget *bar = v_get_status_bar( window );
+	guint context = get_status_context( window );
+	gtk_statusbar_pop( GTK_STATUSBAR( bar ), context );
+}
+
+static guint
+get_status_context( NactWindow *window )
+{
+	return( GPOINTER_TO_UINT( g_object_get_data( G_OBJECT( window ), PROP_ICOMMAND_TAB_STATUS_CONTEXT )));
+}
+
+static void
+set_status_context( NactWindow *window, guint context )
+{
+	g_object_set_data( G_OBJECT( window ), PROP_ICOMMAND_TAB_STATUS_CONTEXT, GUINT_TO_POINTER( context ));
+}
diff --git a/src/nact/nact-icommand-tab.h b/src/nact/nact-icommand-tab.h
index 18895c3..4fa8ff1 100644
--- a/src/nact/nact-icommand-tab.h
+++ b/src/nact/nact-icommand-tab.h
@@ -55,6 +55,7 @@ typedef struct {
 	NactICommandTabInterfacePrivate *private;
 
 	/* api */
+	GtkWidget *       ( *get_status_bar )    ( NactWindow *window );
 	NAActionProfile * ( *get_edited_profile )( NactWindow *window );
 	void              ( *field_modified )    ( NactWindow *window );
 	void              ( *get_isfiledir )     ( NactWindow *window, gboolean *is_file, gboolean *is_dir );
diff --git a/src/nact/nact-iconditions-tab.h b/src/nact/nact-iconditions-tab.h
index 91136cb..664d245 100644
--- a/src/nact/nact-iconditions-tab.h
+++ b/src/nact/nact-iconditions-tab.h
@@ -43,7 +43,7 @@
 G_BEGIN_DECLS
 
 #define NACT_ICONDITIONS_TAB_TYPE						( nact_iconditions_tab_get_type())
-#define NACT_ICONDITIONS_TAB( object )					( G_TYPE_CHECK_INSTANCE_CAST( object, NACT_ICONDITIONS_TAB_TYPE, NactIConditions_Tab ))
+#define NACT_ICONDITIONS_TAB( object )					( G_TYPE_CHECK_INSTANCE_CAST( object, NACT_ICONDITIONS_TAB_TYPE, NactIConditionsTab ))
 #define NACT_IS_ICONDITIONS_TAB( object )				( G_TYPE_CHECK_INSTANCE_TYPE( object, NACT_ICONDITIONS_TAB_TYPE ))
 #define NACT_ICONDITIONS_TAB_GET_INTERFACE( instance )	( G_TYPE_INSTANCE_GET_INTERFACE(( instance ), NACT_ICONDITIONS_TAB_TYPE, NactIConditionsTabInterface ))
 
diff --git a/src/nact/nact-imenubar.c b/src/nact/nact-imenubar.c
new file mode 100644
index 0000000..7ec4623
--- /dev/null
+++ b/src/nact/nact-imenubar.c
@@ -0,0 +1,936 @@
+/*
+ * Nautilus Actions
+ * A Nautilus extension which offers configurable context menu actions.
+ *
+ * Copyright (C) 2005 The GNOME Foundation
+ * Copyright (C) 2006, 2007, 2008 Frederic Ruaudel and others (see AUTHORS)
+ * Copyright (C) 2009 Pierre Wieser and others (see AUTHORS)
+ *
+ * This Program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this Library; see the file COPYING.  If not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place,
+ * Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Authors:
+ *   Frederic Ruaudel <grumz grumz net>
+ *   Rodrigo Moya <rodrigo gnome-db org>
+ *   Pierre Wieser <pwieser trychlos org>
+ *   ... and many others (see AUTHORS)
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <glib/gi18n.h>
+
+#include "nact-application.h"
+#include "nact-assist-export.h"
+#include "nact-assist-import.h"
+#include "nact-imenubar.h"
+
+/* private interface data
+ */
+struct NactIMenubarInterfacePrivate {
+};
+
+/* menubar properties, set on the main window
+ */
+#define PROP_IMENUBAR_STATUS_CONTEXT	"nact-imenubar-status-context"
+#define PROP_IMENUBAR_DELETED_ACTIONS	"nact-imenubar-deleted-actions"
+#define PROP_IMENUBAR_NEW_PROFILE_ITEM	"nact-imenubar-new-profile-item"
+#define PROP_IMENUBAR_SAVE_ITEM			"nact-imenubar-save-item"
+#define PROP_IMENUBAR_DELETE_ITEM		"nact-imenubar-delete-item"
+#define PROP_IMENUBAR_EXPORT_ITEM		"nact-imenubar-export-item"
+
+static GType      register_type( void );
+static void       interface_base_init( NactIMenubarInterface *klass );
+static void       interface_base_finalize( NactIMenubarInterface *klass );
+
+static void       create_file_menu( NactMainWindow *window, GtkMenuBar *bar );
+static void       create_edit_menu( NactMainWindow *window, GtkMenuBar *bar );
+static void       create_tools_menu( NactMainWindow *window, GtkMenuBar *bar );
+static void       create_help_menu( NactMainWindow *window, GtkMenuBar *bar );
+static void       signal_connect( NactMainWindow *window, GtkWidget *item, GCallback on_activated, GCallback on_selected );
+
+static void       on_file_selected( GtkMenuItem *item, NactWindow *window );
+static void       on_new_action_activated( GtkMenuItem *item, NactWindow *window );
+static void       on_new_action_selected( GtkItem *item, NactWindow *window );
+static void       on_new_profile_activated( GtkMenuItem *item, NactWindow *window );
+static void       on_new_profile_selected( GtkItem *item, NactWindow *window );
+static void       on_save_activated( GtkMenuItem *item, NactWindow *window );
+static void       on_save_selected( GtkMenuItem *item, NactWindow *window );
+static void       on_quit_activated( GtkMenuItem *item, NactWindow *window );
+static void       on_quit_selected( GtkMenuItem *item, NactWindow *window );
+
+static void       on_edit_selected( GtkMenuItem *item, NactWindow *window );
+static void       on_delete_activated( GtkMenuItem *item, NactWindow *window );
+static void       on_delete_selected( GtkItem *item, NactWindow *window );
+
+static void       on_tools_selected( GtkMenuItem *item, NactWindow *window );
+static void       on_import_activated( GtkMenuItem *item, NactWindow *window );
+static void       on_import_selected( GtkItem *item, NactWindow *window );
+static void       on_export_activated( GtkMenuItem *item, NactWindow *window );
+static void       on_export_selected( GtkItem *item, NactWindow *window );
+
+static void       on_about_activated( GtkMenuItem *item, NactWindow *window );
+static void       on_about_selected( GtkItem *item, NactWindow *window );
+
+static void       on_menu_item_deselected( GtkItem *item, NactWindow *window );
+static void       display_status( NactWindow *window, const gchar *status );
+static void       hide_status( NactWindow *window );
+
+static void       v_add_action( NactWindow *window, NAAction *action );
+static void       v_add_profile( NactWindow *window, NAActionProfile *profile );
+static void       v_remove_action( NactWindow *window, NAAction *action );
+static GSList    *v_get_deleted_actions( NactWindow *window );
+static void       v_free_deleted_actions( NactWindow *window );
+static void       v_push_removed_action( NactWindow *window, NAAction *action );
+static GSList    *v_get_actions( NactWindow *window );
+static NAObject  *v_get_selected( NactWindow *window );
+static GtkWidget *v_get_status_bar( NactWindow *window );
+static void       v_setup_dialog_title( NactWindow *window );
+static void       v_update_actions_list( NactWindow *window );
+static void       v_select_actions_list( NactWindow *window, GType type, const gchar *uuid, const gchar *label );
+static gint       v_count_actions( NactWindow *window );
+static gint       v_count_modified_actions( NactWindow *window );
+static void       v_on_save( NactWindow *window );
+
+static guint      get_status_context( NactMainWindow *window );
+static void       set_status_context( NactMainWindow *window, guint context );
+static GtkWidget *get_new_profile_item( NactWindow *window );
+static void       set_new_profile_item( NactWindow *window, GtkWidget *item );
+static GtkWidget *get_save_item( NactWindow *window );
+static void       set_save_item( NactWindow *window, GtkWidget *item );
+static GtkWidget *get_delete_item( NactWindow *window );
+static void       set_delete_item( NactWindow *window, GtkWidget *item );
+static GtkWidget *get_export_item( NactWindow *window );
+static void       set_export_item( NactWindow *window, GtkWidget *item );
+
+GType
+nact_imenubar_get_type( void )
+{
+	static GType iface_type = 0;
+
+	if( !iface_type ){
+		iface_type = register_type();
+	}
+
+	return( iface_type );
+}
+
+static GType
+register_type( void )
+{
+	static const gchar *thisfn = "nact_imenubar_register_type";
+	g_debug( "%s", thisfn );
+
+	static const GTypeInfo info = {
+		sizeof( NactIMenubarInterface ),
+		( GBaseInitFunc ) interface_base_init,
+		( GBaseFinalizeFunc ) interface_base_finalize,
+		NULL,
+		NULL,
+		NULL,
+		0,
+		0,
+		NULL
+	};
+
+	GType type = g_type_register_static( G_TYPE_INTERFACE, "NactIMenubar", &info, 0 );
+
+	g_type_interface_add_prerequisite( type, NACT_WINDOW_TYPE );
+
+	return( type );
+}
+
+static void
+interface_base_init( NactIMenubarInterface *klass )
+{
+	static const gchar *thisfn = "nact_imenubar_interface_base_init";
+	static gboolean initialized = FALSE;
+
+	if( !initialized ){
+		g_debug( "%s: klass=%p", thisfn, klass );
+
+		klass->private = g_new0( NactIMenubarInterfacePrivate, 1 );
+
+		initialized = TRUE;
+	}
+}
+
+static void
+interface_base_finalize( NactIMenubarInterface *klass )
+{
+	static const gchar *thisfn = "nact_imenubar_interface_base_finalize";
+	static gboolean finalized = FALSE ;
+
+	if( !finalized ){
+		g_debug( "%s: klass=%p", thisfn, klass );
+
+		g_free( klass->private );
+
+		finalized = TRUE;
+	}
+}
+
+/**
+ * nact_imenubar_init:
+ * @window: the #NactMainWindow to which the menubar is attached.
+ *
+ * Creates the menubar.
+ */
+void
+nact_imenubar_init( NactMainWindow *window )
+{
+	g_assert( NACT_IS_MAIN_WINDOW( window ));
+	g_assert( NACT_IS_IMENUBAR( window ));
+
+	GtkWidget *vbox = base_window_get_widget( BASE_WINDOW( window ), "MenuBarVBox" );
+	GtkWidget *menubar= gtk_menu_bar_new();
+	gtk_container_add( GTK_CONTAINER( vbox ), menubar );
+
+	create_file_menu( window, GTK_MENU_BAR( menubar ));
+	create_edit_menu( window, GTK_MENU_BAR( menubar ));
+	create_tools_menu( window, GTK_MENU_BAR( menubar ));
+	create_help_menu( window, GTK_MENU_BAR( menubar ));
+
+	GtkWidget *status_bar = v_get_status_bar( NACT_WINDOW( window ));
+	if( status_bar ){
+		g_assert( GTK_IS_STATUSBAR( status_bar ));
+		guint context = gtk_statusbar_get_context_id( GTK_STATUSBAR( status_bar ), "nact-imenubar" );
+		set_status_context( window, context );
+	}
+}
+
+/**
+ * nact_imenubar_on_delete_key_pressed:
+ * @window: the #NactMainWindow to which the menubar is attached.
+ *
+ * Deletes the currently selected item.
+ */
+void
+nact_imenubar_on_delete_key_pressed( NactWindow *window )
+{
+	static const gchar *thisfn = "nact_imenubar_on_delete_key_pressed";
+	g_debug( "%s: window=%p", thisfn, window );
+
+	g_assert( NACT_IS_MAIN_WINDOW( window ));
+	g_assert( NACT_IS_IMENUBAR( window ));
+
+	on_delete_activated( NULL, window );
+}
+
+/**
+ * nact_imenubar_on_delete_event:
+ * @window: the #NactMainWindow to which the menubar is attached.
+ *
+ * Closes the main window via the standard 'Quit' item of the menubar.
+ *
+ * This functions is triggered by the main window when it receives the
+ * 'delete-event' event.
+ */
+void
+nact_imenubar_on_delete_event( NactWindow *window )
+{
+	static const gchar *thisfn = "nact_imenubar_on_delete_event";
+	g_debug( "%s: window=%p", thisfn, window );
+
+	g_assert( NACT_IS_MAIN_WINDOW( window ));
+	g_assert( NACT_IS_IMENUBAR( window ));
+
+	on_quit_activated( NULL, window );
+}
+
+static void
+create_file_menu( NactMainWindow *window, GtkMenuBar *menubar )
+{
+	/* i18n: File menu */
+	GtkWidget *file = gtk_menu_item_new_with_label( _( "_File" ));
+	gtk_menu_item_set_use_underline( GTK_MENU_ITEM( file ), TRUE );
+	gtk_menu_shell_append( GTK_MENU_SHELL( menubar ), file );
+	GtkWidget *menu = gtk_menu_new();
+	gtk_menu_item_set_submenu( GTK_MENU_ITEM( file ), menu );
+	nact_window_signal_connect( NACT_WINDOW( window ), G_OBJECT( file ), "select", G_CALLBACK( on_file_selected ));
+
+	GtkWidget *item = gtk_image_menu_item_new_from_stock( GTK_STOCK_NEW, NULL );
+	/* i18n: 'New action' item in 'File' menu - use same accelerator than GTK_STOCK_NEW item */
+	gtk_menu_item_set_label( GTK_MENU_ITEM( item ), _( "_New action" ));
+	gtk_menu_shell_append( GTK_MENU_SHELL( menu ), item );
+	signal_connect( window, item, G_CALLBACK( on_new_action_activated ), G_CALLBACK( on_new_action_selected ));
+
+	/* i18n: 'New profile' item in 'File' menu */
+	item = gtk_image_menu_item_new_with_label( _( "New _profile" ));
+	gtk_menu_shell_append( GTK_MENU_SHELL( menu ), item );
+	gtk_menu_item_set_use_underline( GTK_MENU_ITEM( item ), TRUE );
+	set_new_profile_item( NACT_WINDOW( window ), item );
+	signal_connect( window, item, G_CALLBACK( on_new_profile_activated ), G_CALLBACK( on_new_profile_selected ));
+
+	item = gtk_image_menu_item_new_from_stock( GTK_STOCK_SAVE, NULL );
+	gtk_menu_shell_append( GTK_MENU_SHELL( menu ), item );
+	set_save_item( NACT_WINDOW( window ), item );
+	signal_connect( window, item, G_CALLBACK( on_save_activated ), G_CALLBACK( on_save_selected ));
+
+	item = gtk_separator_menu_item_new();
+	gtk_menu_shell_append( GTK_MENU_SHELL( menu ), item );
+
+	item = gtk_image_menu_item_new_from_stock( GTK_STOCK_QUIT, NULL );
+	gtk_menu_shell_append( GTK_MENU_SHELL( menu ), item );
+	signal_connect( window, item, G_CALLBACK( on_quit_activated ), G_CALLBACK( on_quit_selected ));
+}
+
+static void
+create_edit_menu( NactMainWindow *window, GtkMenuBar *menubar )
+{
+	/* i18n: Edit menu */
+	GtkWidget *edit = gtk_menu_item_new_with_label( _( "_Edit" ));
+	gtk_menu_item_set_use_underline( GTK_MENU_ITEM( edit ), TRUE );
+	gtk_menu_shell_append( GTK_MENU_SHELL( menubar ), edit );
+	GtkWidget *menu = gtk_menu_new();
+	gtk_menu_item_set_submenu( GTK_MENU_ITEM( edit ), menu );
+	nact_window_signal_connect( NACT_WINDOW( window ), G_OBJECT( edit ), "select", G_CALLBACK( on_edit_selected ));
+
+	/* i18n: Delete item in Edit menu */
+	GtkWidget *item = gtk_image_menu_item_new_from_stock( GTK_STOCK_DELETE, NULL );
+	gtk_menu_shell_append( GTK_MENU_SHELL( menu ), item );
+	set_delete_item( NACT_WINDOW( window ), item );
+	signal_connect( window, item, G_CALLBACK( on_delete_activated ), G_CALLBACK( on_delete_selected ));
+}
+
+static void
+create_tools_menu( NactMainWindow *window, GtkMenuBar *menubar )
+{
+	/* i18n: Tools menu */
+	GtkWidget *tools = gtk_menu_item_new_with_label( _( "_Tools" ));
+	gtk_menu_item_set_use_underline( GTK_MENU_ITEM( tools ), TRUE );
+	gtk_menu_shell_append( GTK_MENU_SHELL( menubar ), tools );
+	GtkWidget *menu = gtk_menu_new();
+	gtk_menu_item_set_submenu( GTK_MENU_ITEM( tools ), menu );
+	nact_window_signal_connect( NACT_WINDOW( window ), G_OBJECT( tools ), "select", G_CALLBACK( on_tools_selected ));
+
+	/* i18n: Import item in Tools menu */
+	GtkWidget *item = gtk_image_menu_item_new_with_label( _( "_Import" ));
+	gtk_menu_item_set_use_underline( GTK_MENU_ITEM( item ), TRUE );
+	gtk_menu_shell_append( GTK_MENU_SHELL( menu ), item );
+	signal_connect( window, item, G_CALLBACK( on_import_activated ), G_CALLBACK( on_import_selected ));
+
+	/* i18n: Export item in Tools menu */
+	item = gtk_image_menu_item_new_with_label( _( "_Export" ));
+	gtk_menu_item_set_use_underline( GTK_MENU_ITEM( item ), TRUE );
+	gtk_menu_shell_append( GTK_MENU_SHELL( menu ), item );
+	set_export_item( NACT_WINDOW( window ), item );
+	signal_connect( window, item, G_CALLBACK( on_export_activated ), G_CALLBACK( on_export_selected ));
+}
+
+static void
+create_help_menu( NactMainWindow *window, GtkMenuBar *menubar )
+{
+	/* i18n: Help menu */
+	GtkWidget *help = gtk_menu_item_new_with_label( _( "_Help" ));
+	gtk_menu_item_set_use_underline( GTK_MENU_ITEM( help ), TRUE );
+	gtk_menu_shell_append( GTK_MENU_SHELL( menubar ), help );
+	GtkWidget *menu = gtk_menu_new();
+	gtk_menu_item_set_submenu( GTK_MENU_ITEM( help ), menu );
+
+	GtkWidget *item = gtk_image_menu_item_new_from_stock( GTK_STOCK_ABOUT, NULL );
+	gtk_menu_shell_append( GTK_MENU_SHELL( menu ), item );
+	signal_connect( window, item, G_CALLBACK( on_about_activated ), G_CALLBACK( on_about_selected ));
+}
+
+static void
+signal_connect( NactMainWindow *window, GtkWidget *item, GCallback on_activated, GCallback on_selected )
+{
+	if( on_activated ){
+		nact_window_signal_connect( NACT_WINDOW( window ), G_OBJECT( item ), "activate", on_activated );
+	}
+
+	if( on_selected ){
+		nact_window_signal_connect( NACT_WINDOW( window ), G_OBJECT( item ), "select", on_selected );
+		nact_window_signal_connect( NACT_WINDOW( window ), G_OBJECT( item ), "deselect", G_CALLBACK( on_menu_item_deselected ));
+	}
+}
+
+static void
+on_file_selected( GtkMenuItem *item, NactWindow *window )
+{
+	NAObject *object = v_get_selected( window );
+	gboolean new_profile_enabled = NA_IS_ACTION( object ) || NA_IS_ACTION_PROFILE( object );
+	GtkWidget *new_profile_item = get_new_profile_item( window );
+	gtk_widget_set_sensitive( new_profile_item, new_profile_enabled );
+
+	gint modified = v_count_modified_actions( window );
+	gboolean save_enabled = ( modified > 0 );
+	GtkWidget *save_item = get_save_item( window );
+	gtk_widget_set_sensitive( save_item, save_enabled );
+}
+
+static void
+on_new_action_activated( GtkMenuItem *item, NactWindow *window )
+{
+	NAAction *action = na_action_new_with_profile();
+	na_object_check_edited_status( NA_OBJECT( action ));
+	v_add_action( window, action );
+
+	v_update_actions_list( window );
+	v_setup_dialog_title( window );
+
+	gchar *uuid = na_action_get_uuid( action );
+	gchar *label = na_action_get_label( action );
+	v_select_actions_list( window, NA_ACTION_TYPE, uuid, label );
+	g_free( label );
+	g_free( uuid );
+}
+
+static void
+on_new_action_selected( GtkItem *item, NactWindow *window )
+{
+	/* i18n: tooltip displayed in the status bar when selecting the 'New action' item */
+	display_status( window, _( "Define a new action." ));
+}
+
+static void
+on_new_profile_activated( GtkMenuItem *item, NactWindow *window )
+{
+	NAObject *object = v_get_selected( window );
+	g_assert( NA_IS_OBJECT( object ));
+
+	NAAction *action = NA_IS_ACTION( object ) ?
+			NA_ACTION( object ) : na_action_profile_get_action( NA_ACTION_PROFILE( object ));
+
+	NAActionProfile *new_profile = na_action_profile_new();
+	g_debug( "nact_imenubar_on_new_profile_activated: action=%p, profile=%p", action, new_profile );
+
+	na_action_attach_profile( action, new_profile );
+	na_object_check_edited_status( NA_OBJECT( new_profile ));
+
+	v_add_profile( window, new_profile );
+
+	v_setup_dialog_title( window );
+	v_update_actions_list( window );
+
+	gchar *uuid = na_action_get_uuid( action );
+	gchar *label = na_action_profile_get_label( new_profile );
+	v_select_actions_list( window, NA_ACTION_PROFILE_TYPE, uuid, label );
+	g_free( label );
+	g_free( uuid );
+}
+
+static void
+on_new_profile_selected( GtkItem *item, NactWindow *window )
+{
+	/* i18n: tooltip displayed in the status bar when selecting the 'New profile' item */
+	display_status( window, _( "Define a new profile attached to the current action." ));
+}
+
+static void
+on_save_activated( GtkMenuItem *item, NactWindow *window )
+{
+	NactApplication *application = NACT_APPLICATION( base_window_get_application( BASE_WINDOW( window )));
+	NAPivot *pivot = nact_application_get_pivot( application );
+	GSList *actions = v_get_actions( window );
+	GSList *ia;
+
+	/* keep the current selection
+	 * to be able to restore it at the end of the operation
+	 */
+	NAObject *current = v_get_selected( window );
+	GType type;
+	gchar *uuid, *label;
+	if( NA_IS_ACTION( current )){
+		uuid = na_action_get_uuid( NA_ACTION( current ));
+		label = na_action_get_label( NA_ACTION( current ));
+		type = NA_ACTION_TYPE;
+
+	} else {
+		g_assert( NA_IS_ACTION_PROFILE( current ));
+		NAAction *action = na_action_profile_get_action( NA_ACTION_PROFILE( current ));
+		uuid = na_action_get_uuid( action );
+		label = na_action_profile_get_label( NA_ACTION_PROFILE( current ));
+		type = NA_ACTION_PROFILE_TYPE;
+	}
+
+	/* save the modified actions
+	 * - remove the origin of pivot if any
+	 * - add a duplicate of this action to pivot
+	 * - set the duplicate as the origin of this action
+	 * - reset the status
+	 */
+	for( ia = actions ; ia ; ia = ia->next ){
+		NAAction *current = NA_ACTION( ia->data );
+		if( na_object_get_modified_status( NA_OBJECT( current ))){
+			if( nact_window_save_action( window, current )){
+
+				NAAction *origin = NA_ACTION( na_object_get_origin( NA_OBJECT( current )));
+				if( origin ){
+					na_pivot_remove_action( pivot, origin );
+				}
+
+				NAAction *dup_pivot = NA_ACTION( na_object_duplicate( NA_OBJECT( current )));
+				na_pivot_add_action( pivot, dup_pivot );
+
+				v_remove_action( window, current );
+				g_object_unref( current );
+
+				NAAction *dup_window = NA_ACTION( na_object_duplicate( NA_OBJECT( dup_pivot )));
+				v_add_action( window, dup_window );
+				na_object_check_edited_status( NA_OBJECT( dup_window ));
+			}
+		}
+	}
+
+	/* delete the removed actions
+	 * - remove the origin of pivot if any
+	 */
+	GSList *deleted = v_get_deleted_actions( window );
+	for( ia = deleted ; ia ; ia = ia->next ){
+		NAAction *current = NA_ACTION( ia->data );
+		if( nact_window_delete_action( window, current )){
+
+			NAAction *origin = NA_ACTION( na_object_get_origin( NA_OBJECT( current )));
+			if( origin ){
+				na_pivot_remove_action( pivot, origin );
+			}
+		}
+	}
+	v_free_deleted_actions( window );
+	v_on_save( window );
+
+	v_setup_dialog_title( window );
+	v_update_actions_list( window );
+	v_select_actions_list( window, type, uuid, label );
+	g_free( label );
+	g_free( uuid );
+}
+
+static void
+on_save_selected( GtkMenuItem *item, NactWindow *window )
+{
+	/* i18n: tooltip displayed in the status bar when selecting 'Save' item */
+	display_status( window, _( "Record all the modified actions." ));
+}
+
+static void
+on_quit_activated( GtkMenuItem *item, NactWindow *window )
+{
+	static const gchar *thisfn = "nact_imenubar_on_quit_activated";
+	g_debug( "%s: item=%p, window=%p", thisfn, item, window );
+
+	gint count = v_count_modified_actions( NACT_WINDOW( window ));
+	if( !count || nact_window_warn_count_modified( NACT_WINDOW( window ), count )){
+		g_object_unref( window );
+	}
+}
+
+static void
+on_quit_selected( GtkMenuItem *item, NactWindow *window )
+{
+	/* i18n: tooltip displayed in the status bar when selecting 'Quit' item */
+	display_status( window, _( "Quit the application." ));
+}
+
+static void
+on_edit_selected( GtkMenuItem *item, NactWindow *window )
+{
+	NAObject *object = v_get_selected( window );
+	gboolean delete_enabled = FALSE;
+	if( object ){
+		if( NA_IS_ACTION( object )){
+			delete_enabled = TRUE;
+		} else {
+			g_assert( NA_IS_ACTION_PROFILE( object ));
+			NAAction *action = na_action_profile_get_action( NA_ACTION_PROFILE( object ));
+			delete_enabled = ( na_action_get_profiles_count( action ) > 1 );
+		}
+	}
+	GtkWidget *delete_item = get_delete_item( window );
+	gtk_widget_set_sensitive( delete_item, delete_enabled );
+}
+
+static void
+on_delete_activated( GtkMenuItem *item, NactWindow *window )
+{
+	static const gchar *thisfn = "nact_imenubar_on_delete_activated";
+	g_debug( "%s: item=%p, window=%p", thisfn, item, window );
+
+	NAObject *object = v_get_selected( window );
+	gchar *uuid, *label;
+	GType type;
+
+	if( NA_IS_ACTION( object )){
+		uuid = na_action_get_uuid( NA_ACTION( object ));
+		label = na_action_get_label( NA_ACTION( object ));
+		type = NA_ACTION_TYPE;
+		v_remove_action( window, NA_ACTION( object ));
+		v_push_removed_action( window, NA_ACTION( object ));
+
+	} else {
+		g_assert( NA_IS_ACTION_PROFILE( object ));
+		NAAction *action = na_action_profile_get_action( NA_ACTION_PROFILE( object ));
+		uuid = na_action_get_uuid( action );
+		label = na_action_profile_get_label( NA_ACTION_PROFILE( object ));
+		type = NA_ACTION_PROFILE_TYPE;
+		g_assert( na_action_get_profiles_count( action ) > 1 );
+		na_action_remove_profile( action, NA_ACTION_PROFILE( object ));
+		na_object_check_edited_status( NA_OBJECT( action ));
+	}
+
+	v_setup_dialog_title( window );
+	v_update_actions_list( window );
+
+	v_select_actions_list( window, type, uuid, label );
+	g_free( label );
+	g_free( uuid );
+}
+
+static void
+on_delete_selected( GtkItem *item, NactWindow *window )
+{
+	/* i18n: tooltip displayed in the status bar when selecting the Delete item */
+	display_status( window, _( "Remove the selected action or profile from your configuration." ));
+}
+
+static void
+on_tools_selected( GtkMenuItem *item, NactWindow *window )
+{
+	gboolean export_enabled = v_count_actions( window );
+	GtkWidget *export_item = get_export_item( window );
+	gtk_widget_set_sensitive( export_item, export_enabled );
+}
+
+static void
+on_import_activated( GtkMenuItem *item, NactWindow *window )
+{
+	static const gchar *thisfn = "nact_imenubar_on_import_activated";
+	g_debug( "%s: item=%p, window=%p", thisfn, item, window );
+
+	nact_assist_import_run( NACT_WINDOW( window ));
+
+	/*g_assert( NACT_IS_MAIN_WINDOW( user_data ));
+	NactWindow *wndmain = NACT_WINDOW( user_data );
+	nact_iactions_list_set_focus( wndmain );*/
+}
+
+static void
+on_import_selected( GtkItem *item, NactWindow *window )
+{
+	/* i18n: tooltip displayed in the status bar when selecting the Import item */
+	display_status( window, _( "Import one or more actions from external (XML) files into your configuration." ));
+}
+
+static void
+on_export_activated( GtkMenuItem *item, NactWindow *window )
+{
+	static const gchar *thisfn = "nact_imenubar_on_export_activated";
+	g_debug( "%s: item=%p, window=%p", thisfn, item, window );
+
+	nact_assist_export_run( NACT_WINDOW( window ));
+
+	/*g_assert( NACT_IS_MAIN_WINDOW( user_data ));
+	NactWindow *wndmain = NACT_WINDOW( user_data );
+	nact_iactions_list_set_focus( wndmain );*/
+}
+
+static void
+on_export_selected( GtkItem *item, NactWindow *window )
+{
+	/* i18n: tooltip displayed in the status bar when selecting the Export item */
+	display_status( window, _( "Export one or more actions from your configuration to external XML files." ));
+}
+
+/* TODO: make the website url and the mail addresses clickables
+ */
+static void
+on_about_activated( GtkMenuItem *item, NactWindow *window )
+{
+	static const gchar *thisfn = "nact_imenubar_on_about_activated";
+	g_debug( "%s: item=%p, window=%p", thisfn, item, window );
+
+	BaseApplication *appli;
+	g_object_get( G_OBJECT( window ), PROP_WINDOW_APPLICATION_STR, &appli, NULL );
+	gchar *icon_name = base_application_get_icon_name( appli );
+
+	static const gchar *artists[] = {
+		N_( "Ulisse Perusin <uli peru gmail com>" ),
+		NULL
+	};
+
+	static const gchar *authors[] = {
+		N_( "Frederic Ruaudel <grumz grumz net>" ),
+		N_( "Rodrigo Moya <rodrigo gnome-db org>" ),
+		N_( "Pierre Wieser <pwieser trychlos org>" ),
+		NULL
+	};
+
+	static const gchar *documenters[] = {
+		NULL
+	};
+
+	static gchar *license[] = {
+		N_( "Nautilus Actions Configuration Tool is free software; you can "
+			"redistribute it and/or modify it under the terms of the GNU General "
+			"Public License as published by the Free Software Foundation; either "
+			"version 2 of the License, or (at your option) any later version." ),
+		N_( "Nautilus Actions Configuration Tool is distributed in the hope that it "
+			"will be useful, but WITHOUT ANY WARRANTY; without even the implied "
+			"warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See "
+			"the GNU General Public License for more details." ),
+		N_( "You should have received a copy of the GNU General Public License along "
+			"with Nautilus Actions Configuration Tool ; if not, write to the Free "
+			"Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, "
+			"MA 02110-1301, USA." ),
+		NULL
+	};
+	gchar *license_i18n = g_strjoinv( "\n\n", license );
+
+	GtkWindow *toplevel = base_window_get_toplevel_dialog( BASE_WINDOW( window ));
+
+	gtk_show_about_dialog( toplevel,
+			"artists", artists,
+			"authors", authors,
+			"comments", _( "A graphical interface to create and edit your Nautilus actions." ),
+			"copyright", _( "Copyright \xc2\xa9 2005-2007 Frederic Ruaudel <grumz grumz net>\nCopyright \xc2\xa9 2009 Pierre Wieser <pwieser trychlos org>" ),
+			"documenters", documenters,
+			"translator-credits", _( "The GNOME Translation Project <gnome-i18n gnome org>" ),
+			"license", license_i18n,
+			"wrap-license", TRUE,
+			"logo-icon-name", icon_name,
+			"version", PACKAGE_VERSION,
+			"website", "http://www.nautilus-actions.org";,
+			NULL );
+
+	g_free( license_i18n );
+	g_free( icon_name );
+
+	/*nact_iactions_list_set_focus( NACT_WINDOW( wndmain ));*/
+}
+
+static void
+on_about_selected( GtkItem *item, NactWindow *window )
+{
+	/* i18n: tooltip displayed in the status bar when selecting the About item */
+	display_status( window, _( "Display informations about this program." ));
+}
+
+static void
+on_menu_item_deselected( GtkItem *item, NactWindow *window )
+{
+	hide_status( window );
+}
+
+static void
+display_status( NactWindow *window, const gchar *status )
+{
+	GtkWidget *bar = v_get_status_bar( window );
+	guint context = get_status_context( NACT_MAIN_WINDOW( window ));
+	gtk_statusbar_push( GTK_STATUSBAR( bar ), context, status );
+}
+
+static void
+hide_status( NactWindow *window )
+{
+	GtkWidget *bar = v_get_status_bar( window );
+	guint context = get_status_context( NACT_MAIN_WINDOW( window ));
+	gtk_statusbar_pop( GTK_STATUSBAR( bar ), context );
+}
+
+static void
+v_add_action( NactWindow *window, NAAction *action )
+{
+	if( NACT_IMENUBAR_GET_INTERFACE( window )->add_action ){
+		return( NACT_IMENUBAR_GET_INTERFACE( window )->add_action( window, action ));
+	}
+}
+
+static void
+v_add_profile( NactWindow *window, NAActionProfile *profile )
+{
+	if( NACT_IMENUBAR_GET_INTERFACE( window )->add_profile ){
+		return( NACT_IMENUBAR_GET_INTERFACE( window )->add_profile( window, profile ));
+	}
+}
+
+static void
+v_remove_action( NactWindow *window, NAAction *action )
+{
+	if( NACT_IMENUBAR_GET_INTERFACE( window )->remove_action ){
+		return( NACT_IMENUBAR_GET_INTERFACE( window )->remove_action( window, action ));
+	}
+}
+
+static GSList *
+v_get_deleted_actions( NactWindow *window )
+{
+	if( NACT_IMENUBAR_GET_INTERFACE( window )->get_deleted_actions ){
+		return( NACT_IMENUBAR_GET_INTERFACE( window )->get_deleted_actions( window ));
+	}
+
+	return( NULL );
+}
+
+static void
+v_free_deleted_actions( NactWindow *window )
+{
+	if( NACT_IMENUBAR_GET_INTERFACE( window )->free_deleted_actions ){
+		NACT_IMENUBAR_GET_INTERFACE( window )->free_deleted_actions( window );
+	}
+}
+
+static void
+v_push_removed_action( NactWindow *window, NAAction *action )
+{
+	if( NACT_IMENUBAR_GET_INTERFACE( window )->push_removed_action ){
+		return( NACT_IMENUBAR_GET_INTERFACE( window )->push_removed_action( window, action ));
+	}
+}
+
+static GSList *
+v_get_actions( NactWindow *window )
+{
+	if( NACT_IMENUBAR_GET_INTERFACE( window )->get_actions ){
+		return( NACT_IMENUBAR_GET_INTERFACE( window )->get_actions( window ));
+	}
+
+	return( NULL );
+}
+
+static NAObject *
+v_get_selected( NactWindow *window )
+{
+	if( NACT_IMENUBAR_GET_INTERFACE( window )->get_selected ){
+		return( NACT_IMENUBAR_GET_INTERFACE( window )->get_selected( window ));
+	}
+
+	return( NULL );
+}
+
+static GtkWidget *
+v_get_status_bar( NactWindow *window )
+{
+	if( NACT_IMENUBAR_GET_INTERFACE( window )->get_status_bar ){
+		return( NACT_IMENUBAR_GET_INTERFACE( window )->get_status_bar( window ));
+	}
+
+	return( NULL );
+}
+
+static void
+v_setup_dialog_title( NactWindow *window )
+{
+	if( NACT_IMENUBAR_GET_INTERFACE( window )->setup_dialog_title ){
+		return( NACT_IMENUBAR_GET_INTERFACE( window )->setup_dialog_title( window ));
+	}
+}
+
+static void
+v_update_actions_list( NactWindow *window )
+{
+	if( NACT_IMENUBAR_GET_INTERFACE( window )->update_actions_list ){
+		return( NACT_IMENUBAR_GET_INTERFACE( window )->update_actions_list( window ));
+	}
+}
+
+static void
+v_select_actions_list( NactWindow *window, GType type, const gchar *uuid, const gchar *label )
+{
+	if( NACT_IMENUBAR_GET_INTERFACE( window )->select_actions_list ){
+		return( NACT_IMENUBAR_GET_INTERFACE( window )->select_actions_list( window, type, uuid, label ));
+	}
+}
+
+static gint
+v_count_actions( NactWindow *window )
+{
+	if( NACT_IMENUBAR_GET_INTERFACE( window )->count_actions ){
+		return( NACT_IMENUBAR_GET_INTERFACE( window )->count_actions( window ));
+	}
+
+	return( 0 );
+}
+
+static gint
+v_count_modified_actions( NactWindow *window )
+{
+	if( NACT_IMENUBAR_GET_INTERFACE( window )->count_modified_actions ){
+		return( NACT_IMENUBAR_GET_INTERFACE( window )->count_modified_actions( window ));
+	}
+
+	return( 0 );
+}
+
+static void
+v_on_save( NactWindow *window )
+{
+	if( NACT_IMENUBAR_GET_INTERFACE( window )->on_save ){
+		NACT_IMENUBAR_GET_INTERFACE( window )->on_save( window );
+	}
+}
+
+static guint
+get_status_context( NactMainWindow *window )
+{
+	return( GPOINTER_TO_UINT( g_object_get_data( G_OBJECT( window ), PROP_IMENUBAR_STATUS_CONTEXT )));
+}
+
+static void
+set_status_context( NactMainWindow *window, guint context )
+{
+	g_object_set_data( G_OBJECT( window ), PROP_IMENUBAR_STATUS_CONTEXT, GUINT_TO_POINTER( context ));
+}
+
+static GtkWidget *
+get_new_profile_item( NactWindow *window )
+{
+	return( GTK_WIDGET( g_object_get_data( G_OBJECT( window ), PROP_IMENUBAR_NEW_PROFILE_ITEM )));
+}
+
+static void
+set_new_profile_item( NactWindow *window, GtkWidget *item )
+{
+	g_object_set_data( G_OBJECT( window ), PROP_IMENUBAR_NEW_PROFILE_ITEM, item );
+}
+
+static GtkWidget *
+get_save_item( NactWindow *window )
+{
+	return( GTK_WIDGET( g_object_get_data( G_OBJECT( window ), PROP_IMENUBAR_SAVE_ITEM )));
+}
+
+static void
+set_save_item( NactWindow *window, GtkWidget *item )
+{
+	g_object_set_data( G_OBJECT( window ), PROP_IMENUBAR_SAVE_ITEM, item );
+}
+
+static GtkWidget *
+get_delete_item( NactWindow *window )
+{
+	return( GTK_WIDGET( g_object_get_data( G_OBJECT( window ), PROP_IMENUBAR_DELETE_ITEM )));
+}
+
+static void
+set_delete_item( NactWindow *window, GtkWidget *item )
+{
+	g_object_set_data( G_OBJECT( window ), PROP_IMENUBAR_DELETE_ITEM, item );
+}
+
+static GtkWidget *
+get_export_item( NactWindow *window )
+{
+	return( GTK_WIDGET( g_object_get_data( G_OBJECT( window ), PROP_IMENUBAR_EXPORT_ITEM )));
+}
+
+static void
+set_export_item( NactWindow *window, GtkWidget *item )
+{
+	g_object_set_data( G_OBJECT( window ), PROP_IMENUBAR_EXPORT_ITEM, item );
+}
diff --git a/src/nact/nact-imenubar.h b/src/nact/nact-imenubar.h
new file mode 100644
index 0000000..9bcbc31
--- /dev/null
+++ b/src/nact/nact-imenubar.h
@@ -0,0 +1,85 @@
+/*
+ * Nautilus Actions
+ * A Nautilus extension which offers configurable context menu actions.
+ *
+ * Copyright (C) 2005 The GNOME Foundation
+ * Copyright (C) 2006, 2007, 2008 Frederic Ruaudel and others (see AUTHORS)
+ * Copyright (C) 2009 Pierre Wieser and others (see AUTHORS)
+ *
+ * This Program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this Library; see the file COPYING.  If not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place,
+ * Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Authors:
+ *   Frederic Ruaudel <grumz grumz net>
+ *   Rodrigo Moya <rodrigo gnome-db org>
+ *   Pierre Wieser <pwieser trychlos org>
+ *   ... and many others (see AUTHORS)
+ */
+
+#ifndef __NACT_IMENUBAR_H__
+#define __NACT_IMENUBAR_H__
+
+/*
+ * NactIMenubar interface definition.
+ */
+
+#include <gtk/gtk.h>
+
+#include "nact-main-window.h"
+
+G_BEGIN_DECLS
+
+#define NACT_IMENUBAR_TYPE						( nact_imenubar_get_type())
+#define NACT_IMENUBAR( object )					( G_TYPE_CHECK_INSTANCE_CAST( object, NACT_IMENUBAR_TYPE, NactIMenubar ))
+#define NACT_IS_IMENUBAR( object )				( G_TYPE_CHECK_INSTANCE_TYPE( object, NACT_IMENUBAR_TYPE ))
+#define NACT_IMENUBAR_GET_INTERFACE( instance )	( G_TYPE_INSTANCE_GET_INTERFACE(( instance ), NACT_IMENUBAR_TYPE, NactIMenubarInterface ))
+
+typedef struct NactIMenubar NactIMenubar;
+
+typedef struct NactIMenubarInterfacePrivate NactIMenubarInterfacePrivate;
+
+typedef struct {
+	GTypeInterface                parent;
+	NactIMenubarInterfacePrivate *private;
+
+	/* api */
+	void        ( *add_action )            ( NactWindow *window, NAAction* action );
+	void        ( *add_profile )           ( NactWindow *window, NAActionProfile *profile );
+	void        ( *remove_action )         ( NactWindow *window, NAAction *action );
+	GSList *    ( *get_deleted_actions )   ( NactWindow *window );
+	void        ( *free_deleted_actions )  ( NactWindow *window );
+	void        ( *push_removed_action )   ( NactWindow *window, NAAction *action );
+	GSList *    ( *get_actions )           ( NactWindow *window );
+	NAObject *  ( *get_selected )          ( NactWindow *window );
+	GtkWidget * ( *get_status_bar )        ( NactWindow *window );
+	void        ( *setup_dialog_title )    ( NactWindow *window );
+	void        ( *update_actions_list )   ( NactWindow *window );
+	void        ( *select_actions_list )   ( NactWindow *window, GType type, const gchar *uuid, const gchar *label );
+	gint        ( *count_actions )         ( NactWindow *window );
+	gint        ( *count_modified_actions )( NactWindow *window );
+	void        ( *on_save )               ( NactWindow *window );
+}
+	NactIMenubarInterface;
+
+GType nact_imenubar_get_type( void );
+
+void  nact_imenubar_init( NactMainWindow *window );
+
+void  nact_imenubar_on_delete_key_pressed( NactWindow *window );
+void  nact_imenubar_on_delete_event( NactWindow *window );
+
+G_END_DECLS
+
+#endif /* __NACT_IMENUBAR_H__ */
diff --git a/src/nact/nact-main-window.c b/src/nact/nact-main-window.c
index 565b9f1..9140571 100644
--- a/src/nact/nact-main-window.c
+++ b/src/nact/nact-main-window.c
@@ -39,16 +39,15 @@
 
 #include <common/na-pivot.h>
 #include <common/na-iio-provider.h>
-#include <common/na-ipivot-container.h>
+#include <common/na-ipivot-consumer.h>
 
 #include "nact-application.h"
-#include "nact-assist-export.h"
-#include "nact-assist-import.h"
 #include "nact-iactions-list.h"
 #include "nact-iaction-tab.h"
 #include "nact-icommand-tab.h"
 #include "nact-iconditions-tab.h"
 #include "nact-iadvanced-tab.h"
+#include "nact-imenubar.h"
 #include "nact-iprefs.h"
 #include "nact-main-window.h"
 
@@ -63,11 +62,11 @@ struct NactMainWindowPrivate {
 	gboolean         dispose_has_run;
 	GtkStatusbar    *status_bar;
 	guint            status_context;
-	GtkWidget       *new_profile_item;
-	GtkWidget       *save_item;
 	GSList          *actions;
 	NAAction        *edited_action;
 	NAActionProfile *edited_profile;
+	GSList          *deleted;
+	GTimeVal         last_saved;
 };
 
 /* the GConf key used to read/write size and position of auxiliary dialogs
@@ -83,7 +82,8 @@ static void             iaction_tab_iface_init( NactIActionTabInterface *iface )
 static void             icommand_tab_iface_init( NactICommandTabInterface *iface );
 static void             iconditions_tab_iface_init( NactIConditionsTabInterface *iface );
 static void             iadvanced_tab_iface_init( NactIAdvancedTabInterface *iface );
-static void             ipivot_container_iface_init( NAIPivotContainerInterface *iface );
+static void             imenubar_iface_init( NactIMenubarInterface *iface );
+static void             ipivot_consumer_iface_init( NAIPivotConsumerInterface *iface );
 static void             instance_init( GTypeInstance *instance, gpointer klass );
 static void             instance_dispose( GObject *application );
 static void             instance_finalize( GObject *application );
@@ -91,17 +91,16 @@ static void             instance_finalize( GObject *application );
 static gchar           *get_iprefs_window_id( NactWindow *window );
 static gchar           *get_toplevel_name( BaseWindow *window );
 static GSList          *get_actions( NactWindow *window );
+static GtkWidget       *get_status_bar( NactWindow *window );
 
 static void             on_initial_load_toplevel( BaseWindow *window );
-static void             create_file_menu( BaseWindow *window, GtkMenuBar *menubar );
-static void             create_tools_menu( BaseWindow *window, GtkMenuBar *menubar );
-static void             create_help_menu( BaseWindow *window, GtkMenuBar *menubar );
 static void             on_runtime_init_toplevel( BaseWindow *window );
-static void             setup_dialog_title( NactMainWindow *window );
-static void             setup_dialog_menu( NactMainWindow *window );
+static void             setup_dialog_title( NactWindow *window );
+/*static void             setup_dialog_menu( NactMainWindow *window );*/
 
 static void             on_actions_list_selection_changed( GtkTreeSelection *selection, gpointer user_data );
 static gboolean         on_actions_list_double_click( GtkWidget *widget, GdkEventButton *event, gpointer data );
+static gboolean         on_actions_list_delete_key_pressed( GtkWidget *widget, GdkEventKey *event, gpointer data );
 static gboolean         on_actions_list_enter_key_pressed( GtkWidget *widget, GdkEventKey *event, gpointer data );
 static void             set_current_action( NactMainWindow *window );
 static void             set_current_profile( NactMainWindow *window );
@@ -109,35 +108,34 @@ static NAAction        *get_edited_action( NactWindow *window );
 static NAActionProfile *get_edited_profile( NactWindow *window );
 static void             on_modified_field( NactWindow *window );
 static void             check_edited_status( NactWindow *window, const NAAction *action );
-static gboolean         is_action_modified( const NAAction *action );
-static gboolean         is_action_to_save( const NAAction *action );
+static gboolean         is_modified_action( NactWindow *window, const NAAction *action );
+static gboolean         is_valid_action( NactWindow *window, const NAAction *action );
+static gboolean         is_modified_profile( NactWindow *window, const NAActionProfile *profile );
+static gboolean         is_valid_profile( NactWindow *window, const NAActionProfile *profile );
 
 static void             get_isfiledir( NactWindow *window, gboolean *isfile, gboolean *isdir );
 static gboolean         get_multiple( NactWindow *window );
 static GSList          *get_schemes( NactWindow *window );
 
-static void             on_new_action_activated( GtkMenuItem *item, gpointer user_data );
-static void             on_new_action_selected( GtkItem *item, gpointer user_data );
-static void             on_new_profile_activated( GtkMenuItem *item, gpointer user_data );
-static void             on_new_profile_selected( GtkItem *item, gpointer user_data );
-
-static void             on_import_activated( GtkMenuItem *item, gpointer user_data );
-static void             on_import_selected( GtkItem *item, gpointer user_data );
-static void             on_export_activated( GtkMenuItem *item, gpointer user_data );
-static void             on_export_selected( GtkItem *item, gpointer user_data );
-static void             on_about_activated( GtkMenuItem *item, gpointer user_data );
-static void             on_about_selected( GtkItem *item, gpointer user_data );
-static void             on_menu_item_deselected( GtkItem *item, gpointer user_data );
+static void             add_action( NactWindow *window, NAAction *action );
+static void             add_profile( NactWindow *window, NAActionProfile *profile );
+static void             remove_action( NactWindow *window, NAAction *action );
+static GSList          *get_deleted_actions( NactWindow *window );
+static void             free_deleted_actions( NactWindow *window );
+static void             push_removed_action( NactWindow *window, NAAction *action );
+
 /*static void     on_new_button_clicked( GtkButton *button, gpointer user_data );
 static void     on_edit_button_clicked( GtkButton *button, gpointer user_data );
 static void     on_duplicate_button_clicked( GtkButton *button, gpointer user_data );
 static void     on_delete_button_clicked( GtkButton *button, gpointer user_data );
 static gboolean on_dialog_response( GtkDialog *dialog, gint response_id, BaseWindow *window );*/
-static void             on_close( GtkMenuItem *item, gpointer user_data );
-static gboolean         on_delete_event( BaseWindow *window, GtkWindow *toplevel, GdkEvent *event );
 
-static gint             count_modified_actions( NactMainWindow *window );
-static void             on_actions_changed( NAIPivotContainer *instance, gpointer user_data );
+static void             update_actions_list( NactWindow *window );
+static gboolean         on_delete_event( BaseWindow *window, GtkWindow *toplevel, GdkEvent *event );
+static gint             count_actions( NactWindow *window );
+static gint             count_modified_actions( NactWindow *window );
+static void             on_save( NactWindow *window );
+static void             on_actions_changed( NAIPivotConsumer *instance, gpointer user_data );
 
 GType
 nact_main_window_get_type( void )
@@ -215,14 +213,23 @@ register_type( void )
 	};
 	g_type_add_interface_static( type, NACT_IADVANCED_TAB_TYPE, &iadvanced_tab_iface_info );
 
-	/* implement IPivotContainer interface
+	/* implement IMenubar interface
 	 */
-	static const GInterfaceInfo pivot_container_iface_info = {
-		( GInterfaceInitFunc ) ipivot_container_iface_init,
+	static const GInterfaceInfo imenubar_iface_info = {
+		( GInterfaceInitFunc ) imenubar_iface_init,
 		NULL,
 		NULL
 	};
-	g_type_add_interface_static( type, NA_IPIVOT_CONTAINER_TYPE, &pivot_container_iface_info );
+	g_type_add_interface_static( type, NACT_IMENUBAR_TYPE, &imenubar_iface_info );
+
+	/* implement IPivotConsumer interface
+	 */
+	static const GInterfaceInfo pivot_consumer_iface_info = {
+		( GInterfaceInitFunc ) ipivot_consumer_iface_init,
+		NULL,
+		NULL
+	};
+	g_type_add_interface_static( type, NA_IPIVOT_CONSUMER_TYPE, &pivot_consumer_iface_info );
 
 	return( type );
 }
@@ -260,7 +267,12 @@ iactions_list_iface_init( NactIActionsListInterface *iface )
 	iface->get_actions = get_actions;
 	iface->on_selection_changed = on_actions_list_selection_changed;
 	iface->on_double_click = on_actions_list_double_click;
+	iface->on_delete_key_pressed = on_actions_list_delete_key_pressed;
 	iface->on_enter_key_pressed = on_actions_list_enter_key_pressed;
+	iface->is_modified_action = is_modified_action;
+	iface->is_valid_action = is_valid_action;
+	iface->is_modified_profile = is_modified_profile;
+	iface->is_valid_profile = is_valid_profile;
 }
 
 static void
@@ -269,6 +281,8 @@ iaction_tab_iface_init( NactIActionTabInterface *iface )
 	static const gchar *thisfn = "nact_main_window_iaction_tab_iface_init";
 	g_debug( "%s: iface=%p", thisfn, iface );
 
+	iface->get_status_bar = get_status_bar;
+	iface->get_selected = nact_iactions_list_get_selected_object;
 	iface->get_edited_action = get_edited_action;
 	iface->field_modified = on_modified_field;
 }
@@ -279,6 +293,7 @@ icommand_tab_iface_init( NactICommandTabInterface *iface )
 	static const gchar *thisfn = "nact_main_window_icommand_tab_iface_init";
 	g_debug( "%s: iface=%p", thisfn, iface );
 
+	iface->get_status_bar = get_status_bar;
 	iface->get_edited_profile = get_edited_profile;
 	iface->field_modified = on_modified_field;
 	iface->get_isfiledir = get_isfiledir;
@@ -307,9 +322,32 @@ iadvanced_tab_iface_init( NactIAdvancedTabInterface *iface )
 }
 
 static void
-ipivot_container_iface_init( NAIPivotContainerInterface *iface )
+imenubar_iface_init( NactIMenubarInterface *iface )
+{
+	static const gchar *thisfn = "nact_main_window_imenubar_iface_init";
+	g_debug( "%s: iface=%p", thisfn, iface );
+
+	iface->add_action = add_action;
+	iface->add_profile = add_profile;
+	iface->remove_action = remove_action;
+	iface->get_deleted_actions = get_deleted_actions;
+	iface->free_deleted_actions = free_deleted_actions;
+	iface->push_removed_action = push_removed_action;
+	iface->get_actions = get_actions;
+	iface->get_selected = nact_iactions_list_get_selected_object;
+	iface->get_status_bar = get_status_bar;
+	iface->setup_dialog_title = setup_dialog_title;
+	iface->update_actions_list = update_actions_list;
+	iface->select_actions_list = nact_iactions_list_set_selection;
+	iface->count_actions = count_actions;
+	iface->count_modified_actions = count_modified_actions;
+	iface->on_save = on_save;
+}
+
+static void
+ipivot_consumer_iface_init( NAIPivotConsumerInterface *iface )
 {
-	static const gchar *thisfn = "nact_main_window_ipivot_container_iface_init";
+	static const gchar *thisfn = "nact_main_window_ipivot_consumer_iface_init";
 	g_debug( "%s: iface=%p", thisfn, iface );
 
 	iface->on_actions_changed = on_actions_changed;
@@ -352,6 +390,8 @@ instance_dispose( GObject *window )
 		}
 		g_slist_free( self->private->actions );
 
+		free_deleted_actions( NACT_WINDOW( self ));
+
 		nact_iaction_tab_dispose( NACT_WINDOW( window ));
 		nact_icommand_tab_dispose( NACT_WINDOW( window ));
 		nact_iconditions_tab_dispose( NACT_WINDOW( window ));
@@ -412,6 +452,13 @@ get_actions( NactWindow *window )
 	return( NACT_MAIN_WINDOW( window )->private->actions );
 }
 
+static GtkWidget *
+get_status_bar( NactWindow *window )
+{
+	g_assert( NACT_IS_MAIN_WINDOW( window ));
+	return( GTK_WIDGET( NACT_MAIN_WINDOW( window )->private->status_bar ));
+}
+
 /*
  * note that for this NactMainWindow, on_initial_load_toplevel and
  * on_runtime_init_toplevel are equivalent, as there is only one
@@ -433,23 +480,16 @@ on_initial_load_toplevel( BaseWindow *window )
 	NactMainWindow *wnd = NACT_MAIN_WINDOW( window );
 
 	NactApplication *application = NACT_APPLICATION( base_window_get_application( BASE_WINDOW( wnd )));
-	NAPivot *pivot = NA_PIVOT( nact_application_get_pivot( application ));
-	GSList *origin = na_pivot_get_actions( pivot );
-	GSList *ia;
-	for( ia = origin ; ia ; ia = ia->next ){
-		wnd->private->actions = g_slist_prepend( wnd->private->actions, na_action_duplicate( NA_ACTION( ia->data )));
-	}
-
-	GtkWidget *vbox = base_window_get_widget( window, "MenuBarVBox" );
-	GtkWidget *menubar = gtk_menu_bar_new();
-	gtk_container_add( GTK_CONTAINER( vbox ), menubar );
+	NAPivot *pivot = nact_application_get_pivot( application );
+	na_pivot_set_automatic_reload( pivot, FALSE );
+	wnd->private->actions = na_pivot_get_duplicate_actions( pivot );
 
-	create_file_menu( window, GTK_MENU_BAR( menubar ));
-	create_tools_menu( window, GTK_MENU_BAR( menubar ));
-	create_help_menu( window, GTK_MENU_BAR( menubar ));
+	g_get_current_time( &wnd->private->last_saved );
 
 	wnd->private->status_bar = GTK_STATUSBAR( base_window_get_widget( window, "StatusBar" ));
-	wnd->private->status_context = gtk_statusbar_get_context_id( wnd->private->status_bar, "NautilusActionsConfigurationTool" );
+	wnd->private->status_context = gtk_statusbar_get_context_id( wnd->private->status_bar, "nact-main-window" );
+
+	nact_imenubar_init( wnd );
 
 	g_assert( NACT_IS_IACTIONS_LIST( window ));
 	nact_iactions_list_initial_load( NACT_WINDOW( window ));
@@ -476,89 +516,6 @@ on_initial_load_toplevel( BaseWindow *window )
 }
 
 static void
-create_file_menu( BaseWindow *window, GtkMenuBar *menubar )
-{
-	/* i18n: File menu */
-	GtkWidget *file = gtk_menu_item_new_with_label( _( "_File" ));
-	gtk_menu_item_set_use_underline( GTK_MENU_ITEM( file ), TRUE );
-	gtk_menu_shell_append( GTK_MENU_SHELL( menubar ), file );
-	GtkWidget *menu = gtk_menu_new();
-	gtk_menu_item_set_submenu( GTK_MENU_ITEM( file ), menu );
-
-	GtkWidget *item = gtk_image_menu_item_new_from_stock( GTK_STOCK_NEW, NULL );
-	/* i18n: 'New action' item in 'File' menu - use same accelerator than GTK_STOCK_NEW item */
-	gtk_menu_item_set_label( GTK_MENU_ITEM( item ), _( "_New action" ));
-	gtk_menu_shell_append( GTK_MENU_SHELL( menu ), item );
-	nact_window_signal_connect( NACT_WINDOW( window ), G_OBJECT( item ), "activate", G_CALLBACK( on_new_action_activated ));
-	nact_window_signal_connect( NACT_WINDOW( window ), G_OBJECT( item ), "select", G_CALLBACK( on_new_action_selected ));
-	nact_window_signal_connect( NACT_WINDOW( window ), G_OBJECT( item ), "deselect", G_CALLBACK( on_menu_item_deselected ));
-
-	/* i18n: 'New profile' item in 'File' menu */
-	item = gtk_image_menu_item_new_with_label( _( "New _profile" ));
-	gtk_menu_shell_append( GTK_MENU_SHELL( menu ), item );
-	gtk_menu_item_set_use_underline( GTK_MENU_ITEM( item ), TRUE );
-	NACT_MAIN_WINDOW( window )->private->new_profile_item = item;
-	nact_window_signal_connect( NACT_WINDOW( window ), G_OBJECT( item ), "activate", G_CALLBACK( on_new_profile_activated ));
-	nact_window_signal_connect( NACT_WINDOW( window ), G_OBJECT( item ), "select", G_CALLBACK( on_new_profile_selected ));
-	nact_window_signal_connect( NACT_WINDOW( window ), G_OBJECT( item ), "deselect", G_CALLBACK( on_menu_item_deselected ));
-
-	item = gtk_image_menu_item_new_from_stock( GTK_STOCK_SAVE, NULL );
-	gtk_menu_shell_append( GTK_MENU_SHELL( menu ), item );
-	NACT_MAIN_WINDOW( window )->private->save_item = item;
-
-	item = gtk_separator_menu_item_new();
-	gtk_menu_shell_append( GTK_MENU_SHELL( menu ), item );
-
-	item = gtk_image_menu_item_new_from_stock( GTK_STOCK_CLOSE, NULL );
-	gtk_menu_shell_append( GTK_MENU_SHELL( menu ), item );
-	nact_window_signal_connect( NACT_WINDOW( window ), G_OBJECT( item ), "activate", G_CALLBACK( on_close ));
-}
-
-static void
-create_tools_menu( BaseWindow *window, GtkMenuBar *menubar )
-{
-	/* i18n: Tools menu */
-	GtkWidget *tools = gtk_menu_item_new_with_label( _( "_Tools" ));
-	gtk_menu_item_set_use_underline( GTK_MENU_ITEM( tools ), TRUE );
-	gtk_menu_shell_append( GTK_MENU_SHELL( menubar ), tools );
-	GtkWidget *menu = gtk_menu_new();
-	gtk_menu_item_set_submenu( GTK_MENU_ITEM( tools ), menu );
-
-	/* i18n: Import item in Tools menu */
-	GtkWidget *item = gtk_image_menu_item_new_with_label( _( "_Import" ));
-	gtk_menu_item_set_use_underline( GTK_MENU_ITEM( item ), TRUE );
-	gtk_menu_shell_append( GTK_MENU_SHELL( menu ), item );
-	nact_window_signal_connect( NACT_WINDOW( window ), G_OBJECT( item ), "activate", G_CALLBACK( on_import_activated ));
-	nact_window_signal_connect( NACT_WINDOW( window ), G_OBJECT( item ), "select", G_CALLBACK( on_import_selected ));
-	nact_window_signal_connect( NACT_WINDOW( window ), G_OBJECT( item ), "deselect", G_CALLBACK( on_menu_item_deselected ));
-
-	/* i18n: Export item in Tools menu */
-	item = gtk_image_menu_item_new_with_label( _( "_Export" ));
-	gtk_menu_item_set_use_underline( GTK_MENU_ITEM( item ), TRUE );
-	gtk_menu_shell_append( GTK_MENU_SHELL( menu ), item );
-	nact_window_signal_connect( NACT_WINDOW( window ), G_OBJECT( item ), "activate", G_CALLBACK( on_export_activated ));
-	nact_window_signal_connect( NACT_WINDOW( window ), G_OBJECT( item ), "select", G_CALLBACK( on_export_selected ));
-	nact_window_signal_connect( NACT_WINDOW( window ), G_OBJECT( item ), "deselect", G_CALLBACK( on_menu_item_deselected ));
-}
-
-static void
-create_help_menu( BaseWindow *window, GtkMenuBar *menubar )
-{
-	/* i18n: Help menu */
-	GtkWidget *help = gtk_menu_item_new_with_label( _( "_Help" ));
-	gtk_menu_item_set_use_underline( GTK_MENU_ITEM( help ), TRUE );
-	gtk_menu_shell_append( GTK_MENU_SHELL( menubar ), help );
-	GtkWidget *menu = gtk_menu_new();
-	gtk_menu_item_set_submenu( GTK_MENU_ITEM( help ), menu );
-
-	GtkWidget *item = gtk_image_menu_item_new_from_stock( GTK_STOCK_ABOUT, NULL );
-	gtk_menu_shell_append( GTK_MENU_SHELL( menu ), item );
-	nact_window_signal_connect( NACT_WINDOW( window ), G_OBJECT( item ), "activate", G_CALLBACK( on_about_activated ));
-	nact_window_signal_connect( NACT_WINDOW( window ), G_OBJECT( item ), "select", G_CALLBACK( on_about_selected ));
-	nact_window_signal_connect( NACT_WINDOW( window ), G_OBJECT( item ), "deselect", G_CALLBACK( on_menu_item_deselected ));
-}
-
-static void
 on_runtime_init_toplevel( BaseWindow *window )
 {
 	static const gchar *thisfn = "nact_main_window_on_runtime_init_toplevel";
@@ -589,23 +546,23 @@ on_runtime_init_toplevel( BaseWindow *window )
 }
 
 static void
-setup_dialog_title( NactMainWindow *window )
+setup_dialog_title( NactWindow *window )
 {
 	BaseApplication *appli = BASE_APPLICATION( base_window_get_application( BASE_WINDOW( window )));
 	gchar *title = base_application_get_name( appli );
 
-	if( window->private->edited_action ){
-		gchar *label = na_action_get_label( window->private->edited_action );
+	if( NACT_MAIN_WINDOW( window )->private->edited_action ){
+		gchar *label = na_action_get_label( NACT_MAIN_WINDOW( window )->private->edited_action );
 		gchar *tmp = g_strdup_printf( "%s - %s", title, label );
 		g_free( label );
 		g_free( title );
 		title = tmp;
-	}
 
-	if( count_modified_actions( window )){
-		gchar *tmp = g_strdup_printf( "*%s", title );
-		g_free( title );
-		title = tmp;
+		if( is_modified_action( NACT_WINDOW( window ), NACT_MAIN_WINDOW( window )->private->edited_action )){
+			gchar *tmp = g_strdup_printf( "*%s", title );
+			g_free( title );
+			title = tmp;
+		}
 	}
 
 	GtkWindow *toplevel = base_window_get_toplevel_dialog( BASE_WINDOW( window ));
@@ -614,20 +571,20 @@ setup_dialog_title( NactMainWindow *window )
 	g_free( title );
 }
 
-static void
+/*static void
 setup_dialog_menu( NactMainWindow *window )
 {
 	GSList *ia;
 	gboolean to_save = FALSE;
 	for( ia = window->private->actions ; ia && !to_save ; ia = ia->next ){
-		gboolean elt_to_save = is_action_to_save( NA_ACTION( ia->data ));
+		gboolean elt_to_save = is_valid_action( NACT_WINDOW( window ), NA_ACTION( ia->data ));
 		to_save |= elt_to_save;
 	}
 
 	gtk_widget_set_sensitive(  window->private->new_profile_item, window->private->edited_action != NULL );
 
 	gtk_widget_set_sensitive( window->private->save_item, to_save );
-}
+}*/
 
 /*
  * note that the IActionsList tree store may return an action or a profile
@@ -635,19 +592,25 @@ setup_dialog_menu( NactMainWindow *window )
 static void
 on_actions_list_selection_changed( GtkTreeSelection *selection, gpointer user_data )
 {
+	static const gchar *thisfn = "nact_main_window_on_actions_list_selection_changed";
+	g_debug( "%s: selection=%p, user_data=%p", thisfn, selection, user_data );
+
 	g_assert( NACT_IS_MAIN_WINDOW( user_data ));
 	NactMainWindow *window = NACT_MAIN_WINDOW( user_data );
 
-	NAObject *object = nact_iactions_list_get_selected_action( NACT_WINDOW( window ));
+	NAObject *object = nact_iactions_list_get_selected_object( NACT_WINDOW( window ));
+	g_debug( "%s: object=%p", thisfn, object );
 
-	if( NA_IS_ACTION( object )){
-		window->private->edited_action = NA_ACTION( object );
-		set_current_action( window );
+	if( object ){
+		if( NA_IS_ACTION( object )){
+			window->private->edited_action = NA_ACTION( object );
+			set_current_action( window );
 
-	} else {
-		g_assert( NA_IS_ACTION_PROFILE( object ));
-		window->private->edited_profile = NA_ACTION_PROFILE( object );
-		set_current_profile( window );
+		} else {
+			g_assert( NA_IS_ACTION_PROFILE( object ));
+			window->private->edited_profile = NA_ACTION_PROFILE( object );
+			set_current_profile( window );
+		}
 	}
 }
 
@@ -656,15 +619,28 @@ on_actions_list_double_click( GtkWidget *widget, GdkEventButton *event, gpointer
 {
 	g_assert( event->type == GDK_2BUTTON_PRESS );
 
-	nact_iactions_list_toggle_collapse( NACT_WINDOW( user_data ));
+	nact_iactions_list_toggle_collapse(
+			NACT_WINDOW( user_data ), NACT_MAIN_WINDOW( user_data )->private->edited_action );
 
 	return( TRUE );
 }
 
 static gboolean
+on_actions_list_delete_key_pressed( GtkWidget *widget, GdkEventKey *event, gpointer user_data )
+{
+	if( NACT_MAIN_WINDOW( user_data )->private->edited_action ){
+		nact_imenubar_on_delete_key_pressed( NACT_WINDOW( user_data ));
+		return( TRUE );
+	}
+
+	return( FALSE );
+}
+
+static gboolean
 on_actions_list_enter_key_pressed( GtkWidget *widget, GdkEventKey *event, gpointer user_data )
 {
-	nact_iactions_list_toggle_collapse( NACT_WINDOW( user_data ));
+	nact_iactions_list_toggle_collapse(
+			NACT_WINDOW( user_data ), NACT_MAIN_WINDOW( user_data )->private->edited_action );
 
 	return( TRUE );
 }
@@ -681,6 +657,7 @@ set_current_action( NactMainWindow *window )
 	nact_iaction_tab_set_action( NACT_WINDOW( window ), window->private->edited_action );
 
 	window->private->edited_profile = NULL;
+
 	if( na_action_get_profiles_count( window->private->edited_action ) == 1 ){
 		window->private->edited_profile = NA_ACTION_PROFILE( na_action_get_profiles( window->private->edited_action )->data );
 	}
@@ -693,10 +670,8 @@ set_current_profile( NactMainWindow *window )
 {
 	if( window->private->edited_profile ){
 		NAAction *action = NA_ACTION( na_action_profile_get_action( window->private->edited_profile ));
-		if( action != window->private->edited_action ){
-			window->private->edited_action = action;
-			nact_iaction_tab_set_action( NACT_WINDOW( window ), window->private->edited_action );
-		}
+		window->private->edited_action = action;
+		nact_iaction_tab_set_action( NACT_WINDOW( window ), window->private->edited_action );
 	}
 
 	nact_icommand_tab_set_profile( NACT_WINDOW( window ), window->private->edited_profile );
@@ -724,8 +699,9 @@ get_edited_profile( NactWindow *window )
 
 /*
  * called as a virtual function by each interface tab when a field
- * has been modified : time to set the 'modified' flag in the
- * IActionsList box
+ * has been modified
+ * - if the label has been modified, the IActionsList must reflect this
+ * - setup dialog title
  */
 static void
 on_modified_field( NactWindow *window )
@@ -734,58 +710,76 @@ on_modified_field( NactWindow *window )
 
 	check_edited_status( window, NACT_MAIN_WINDOW( window )->private->edited_action );
 
-	setup_dialog_title( NACT_MAIN_WINDOW( window ));
-	setup_dialog_menu( NACT_MAIN_WINDOW( window ));
+	setup_dialog_title( window );
 
 	nact_iactions_list_update_selected( window, NACT_MAIN_WINDOW( window )->private->edited_action );
 }
 
+/*
+ * is it modified ?
+ * and, if it has been modified, is it valid ?
+ */
 static void
 check_edited_status( NactWindow *window, const NAAction *edited )
 {
 	g_assert( edited );
 
-	NactApplication *application = NACT_APPLICATION( base_window_get_application( BASE_WINDOW( window )));
+	na_object_check_edited_status( NA_OBJECT( edited ));
+	/*NactApplication *application = NACT_APPLICATION( base_window_get_application( BASE_WINDOW( window )));
 	NAPivot *pivot = NA_PIVOT( nact_application_get_pivot( application ));
 	gchar *uuid = na_action_get_uuid( edited );
 	NAAction *original = NA_ACTION( na_pivot_get_action( pivot, uuid ));
 	g_free( uuid );
-	gboolean is_modified = !na_action_are_equal( edited, original );
-	g_object_set_data( G_OBJECT( edited ), "nact-main-window-action-modified", GINT_TO_POINTER( is_modified ));
+	gboolean is_modified = !na_object_are_equal( NA_OBJECT( edited ), NA_OBJECT( original ));
+	g_object_set_data( G_OBJECT( edited ), "nact-main-window-action-modified", GINT_TO_POINTER( is_modified ));*/
 
 	/*gboolean check = is_action_modified( edited );
 	g_debug( "check_edited_status: edited=%p, is_modified=%s, check=%s", edited, is_modified ? "True":"False", check ? "True":"False" );*/
 
-	gboolean can_save = FALSE;
+	/*gboolean a_valid = TRUE;
 	if( is_modified ){
 		gchar *label = na_action_get_label( edited );
 		if( label && g_utf8_strlen( label, -1 )){
 			GSList *ip;
+			gboolean p_valid = FALSE;
 			GSList *profiles = na_action_get_profiles( edited );
 			for( ip = profiles ; ip ; ip = ip->next ){
 				NAActionProfile *prof = NA_ACTION_PROFILE( ip->data );
 				gchar *prof_label = na_action_profile_get_label( prof );
 				if( prof_label && g_utf8_strlen( prof_label, -1 )){
-					can_save = TRUE;
+					p_valid = TRUE;
 				}
+				g_object_set_data( G_OBJECT( prof ), "nact-main-window-profile-is-valid", GINT_TO_POINTER( p_valid ));
 				g_free( prof_label );
 			}
 			g_free( label );
 		}
 	}
-	g_object_set_data( G_OBJECT( edited ), "nact-main-window-action-can-save", GINT_TO_POINTER( can_save));
+	g_object_set_data( G_OBJECT( edited ), "nact-main-window-action-is-valid", GINT_TO_POINTER( a_valid ));*/
 }
 
 static gboolean
-is_action_modified( const NAAction *action )
+is_modified_action( NactWindow *window, const NAAction *action )
 {
-	return( GPOINTER_TO_INT( g_object_get_data( G_OBJECT( action ), "nact-main-window-action-modified" )));
+	return( na_object_get_modified_status( NA_OBJECT( action )));
 }
 
 static gboolean
-is_action_to_save( const NAAction *action )
+is_valid_action( NactWindow *window, const NAAction *action )
 {
-	return( GPOINTER_TO_INT( g_object_get_data( G_OBJECT( action ), "nact-main-window-action-can-save" )));
+	return( na_object_get_valid_status( NA_OBJECT( action )));
+}
+
+static gboolean
+is_modified_profile( NactWindow *window, const NAActionProfile *profile )
+{
+	return( na_object_get_modified_status( NA_OBJECT( profile )));
+}
+
+static gboolean
+is_valid_profile( NactWindow *window, const NAActionProfile *profile )
+{
+	return( na_object_get_valid_status( NA_OBJECT( profile )));
 }
 
 static void
@@ -807,183 +801,52 @@ get_schemes( NactWindow *window )
 }
 
 static void
-on_new_action_activated( GtkMenuItem *item, gpointer user_data )
+add_action( NactWindow *window, NAAction *action )
 {
-	g_assert( NACT_IS_MAIN_WINDOW( user_data ));
-	NactMainWindow *window = NACT_MAIN_WINDOW( user_data );
-
-	NAAction *action = na_action_new_with_profile();
-	window->private->actions = g_slist_prepend( window->private->actions, action );
-}
-
-static void
-on_new_action_selected( GtkItem *item, gpointer user_data )
-{
-	g_assert( NACT_IS_MAIN_WINDOW( user_data ));
-	NactMainWindow *window = NACT_MAIN_WINDOW( user_data );
-	gtk_statusbar_push(
-			window->private->status_bar,
-			window->private->status_context,
-			/* i18n: tooltip displayed in the status bar when selecting the 'New action' item */
-			_( "Define a new action." ));
-}
-
-static void
-on_new_profile_activated( GtkMenuItem *item, gpointer user_data )
-{
-
-}
-
-static void
-on_new_profile_selected( GtkItem *item, gpointer user_data )
-{
-	g_assert( NACT_IS_MAIN_WINDOW( user_data ));
-	NactMainWindow *window = NACT_MAIN_WINDOW( user_data );
-	gtk_statusbar_push(
-			window->private->status_bar,
-			window->private->status_context,
-			/* i18n: tooltip displayed in the status bar when selecting the 'New profile' item */
-			_( "Define a new profile attached to the current action." ));
-}
-
-static void
-on_import_activated( GtkMenuItem *item, gpointer user_data )
-{
-	static const gchar *thisfn = "nact_main_window_on_import_activated";
-	g_debug( "%s: item=%p, user_data=%p", thisfn, item, user_data );
-
-	nact_assist_import_run( NACT_WINDOW( user_data ));
-
-	/*g_assert( NACT_IS_MAIN_WINDOW( user_data ));
-	NactWindow *wndmain = NACT_WINDOW( user_data );
-	nact_iactions_list_set_focus( wndmain );*/
-}
-
-static void
-on_import_selected( GtkItem *item, gpointer user_data )
-{
-	g_assert( NACT_IS_MAIN_WINDOW( user_data ));
-	NactMainWindow *window = NACT_MAIN_WINDOW( user_data );
-	gtk_statusbar_push(
-			window->private->status_bar,
-			window->private->status_context,
-			/* i18n: tooltip displayed in the status bar when selecting the Import item */
-			_( "Import one or more actions from external (XML) files into your configuration." ));
+	NactMainWindow *wnd = NACT_MAIN_WINDOW( window );
+	wnd->private->actions = g_slist_prepend( wnd->private->actions, ( gpointer ) action );
 }
 
 static void
-on_export_activated( GtkMenuItem *item, gpointer user_data )
+add_profile( NactWindow *window, NAActionProfile *profile )
 {
-	static const gchar *thisfn = "nact_main_window_on_export_activated";
-	g_debug( "%s: item=%p, user_data=%p", thisfn, item, user_data );
-
-	nact_assist_export_run( NACT_WINDOW( user_data ));
+	NAAction *action = na_action_profile_get_action( profile );
 
-	/*g_assert( NACT_IS_MAIN_WINDOW( user_data ));
-	NactWindow *wndmain = NACT_WINDOW( user_data );
-	nact_iactions_list_set_focus( wndmain );*/
+	if( !nact_iactions_list_is_expanded( window, action )){
+		nact_iactions_list_toggle_collapse( window, action );
+	}
 }
 
 static void
-on_export_selected( GtkItem *item, gpointer user_data )
+remove_action( NactWindow *window, NAAction *action )
 {
-	g_assert( NACT_IS_MAIN_WINDOW( user_data ));
-	NactMainWindow *window = NACT_MAIN_WINDOW( user_data );
-	gtk_statusbar_push(
-			window->private->status_bar,
-			window->private->status_context,
-			/* i18n: tooltip displayed in the status bar when selecting the Export item */
-			_( "Export one or more actions from your configuration to external XML files." ));
+	NactMainWindow *wnd = NACT_MAIN_WINDOW( window );
+	wnd->private->actions = g_slist_remove( wnd->private->actions, ( gconstpointer ) action );
 }
 
-/* TODO: make the website url and the mail addresses clickables
- */
-static void
-on_about_activated( GtkMenuItem *item, gpointer user_data )
+static GSList *
+get_deleted_actions( NactWindow *window )
 {
-	static const gchar *thisfn = "nact_main_window_on_about_activated";
-	g_debug( "%s: item=%p, user_data=%p", thisfn, item, user_data );
-
-	g_assert( NACT_IS_MAIN_WINDOW( user_data ));
-	NactMainWindow *window = NACT_MAIN_WINDOW( user_data );
-
-	BaseApplication *appli;
-	g_object_get( G_OBJECT( window ), PROP_WINDOW_APPLICATION_STR, &appli, NULL );
-	gchar *icon_name = base_application_get_icon_name( appli );
-
-	static const gchar *artists[] = {
-		N_( "Ulisse Perusin <uli peru gmail com>" ),
-		NULL
-	};
-
-	static const gchar *authors[] = {
-		N_( "Frederic Ruaudel <grumz grumz net>" ),
-		N_( "Rodrigo Moya <rodrigo gnome-db org>" ),
-		N_( "Pierre Wieser <pwieser trychlos org>" ),
-		NULL
-	};
-
-	static const gchar *documenters[] = {
-		NULL
-	};
-
-	static gchar *license[] = {
-		N_( "Nautilus Actions Configuration Tool is free software; you can "
-			"redistribute it and/or modify it under the terms of the GNU General "
-			"Public License as published by the Free Software Foundation; either "
-			"version 2 of the License, or (at your option) any later version." ),
-		N_( "Nautilus Actions Configuration Tool is distributed in the hope that it "
-			"will be useful, but WITHOUT ANY WARRANTY; without even the implied "
-			"warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See "
-			"the GNU General Public License for more details." ),
-		N_( "You should have received a copy of the GNU General Public License along "
-			"with Nautilus Actions Configuration Tool ; if not, write to the Free "
-			"Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, "
-			"MA 02110-1301, USA." ),
-		NULL
-	};
-	gchar *license_i18n = g_strjoinv( "\n\n", license );
-
-	GtkWindow *toplevel = base_window_get_toplevel_dialog( BASE_WINDOW( window ));
-
-	gtk_show_about_dialog( toplevel,
-			"artists", artists,
-			"authors", authors,
-			"comments", _( "A graphical tool to create and edit your Nautilus actions." ),
-			"copyright", _( "Copyright \xc2\xa9 2005-2007 Frederic Ruaudel <grumz grumz net>\nCopyright \xc2\xa9 2009 Pierre Wieser <pwieser trychlos org>" ),
-			"documenters", documenters,
-			"translator-credits", _( "The GNOME Translation Project <gnome-i18n gnome org>" ),
-			"license", license_i18n,
-			"wrap-license", TRUE,
-			"logo-icon-name", icon_name,
-			"version", PACKAGE_VERSION,
-			"website", "http://www.nautilus-actions.org";,
-			NULL );
-
-	g_free( license_i18n );
-	g_free( icon_name );
-
-	/*nact_iactions_list_set_focus( NACT_WINDOW( wndmain ));*/
+	return( NACT_MAIN_WINDOW( window )->private->deleted );
 }
 
 static void
-on_about_selected( GtkItem *item, gpointer user_data )
+free_deleted_actions( NactWindow *window )
 {
-	g_assert( NACT_IS_MAIN_WINDOW( user_data ));
-	NactMainWindow *window = NACT_MAIN_WINDOW( user_data );
-	gtk_statusbar_push(
-			window->private->status_bar,
-			window->private->status_context,
-			/* i18n: tooltip displayed in the status bar when selecting the About item */
-			_( "Display informations about this program." ));
+	NactMainWindow *self = NACT_MAIN_WINDOW( window );
+	GSList *ia;
+	for( ia = self->private->deleted ; ia ; ia = ia->next ){
+		g_object_unref( NA_ACTION( ia->data ));
+	}
+	g_slist_free( self->private->deleted );
+	self->private->deleted = NULL;
 }
 
 static void
-on_menu_item_deselected( GtkItem *item, gpointer user_data )
+push_removed_action( NactWindow *window, NAAction *action )
 {
-	g_assert( NACT_IS_MAIN_WINDOW( user_data ));
-	NactMainWindow *window = NACT_MAIN_WINDOW( user_data );
-	gtk_statusbar_pop( window->private->status_bar, window->private->status_context );
+	NactMainWindow *wnd = NACT_MAIN_WINDOW( window );
+	wnd->private->deleted = g_slist_append( wnd->private->deleted, ( gpointer ) action );
 }
 
 /*
@@ -1143,18 +1006,9 @@ on_dialog_response( GtkDialog *dialog, gint response_id, BaseWindow *window )
 }*/
 
 static void
-on_close( GtkMenuItem *item, gpointer user_data )
+update_actions_list( NactWindow *window )
 {
-	static const gchar *thisfn = "nact_main_window_on_close";
-	g_debug( "%s: item=%p, user_data=%p", thisfn, item, user_data );
-
-	g_assert( NACT_IS_MAIN_WINDOW( user_data ));
-	NactMainWindow *window = NACT_MAIN_WINDOW( user_data );
-
-	gint count = count_modified_actions( window );
-	if( !count || nact_window_warn_count_modified( NACT_WINDOW( window ), count )){
-		g_object_unref( window );
-	}
+	nact_iactions_list_fill( window, TRUE );
 }
 
 static gboolean
@@ -1164,36 +1018,66 @@ on_delete_event( BaseWindow *window, GtkWindow *toplevel, GdkEvent *event )
 	g_debug( "%s: window=%p, toplevel=%p, event=%p", thisfn, window, toplevel, event );
 
 	g_assert( NACT_IS_MAIN_WINDOW( window ));
-
-	on_close( NULL, window );
+	nact_imenubar_on_delete_event( NACT_WINDOW( window ));
 
 	return( TRUE );
 }
 
 static gint
-count_modified_actions( NactMainWindow *window )
+count_actions( NactWindow *window )
 {
-	gint count = 0;
+	return( g_slist_length( NACT_MAIN_WINDOW( window )->private->actions ));
+}
+
+static gint
+count_modified_actions( NactWindow *window )
+{
+	gint count = g_slist_length( NACT_MAIN_WINDOW( window )->private->deleted );
+
 	GSList *ia;
-	for( ia = window->private->actions ; ia ; ia = ia->next ){
-		gboolean is_modified = is_action_modified( NA_ACTION( ia->data ));
-		if( is_modified ){
+	for( ia = NACT_MAIN_WINDOW( window )->private->actions ; ia ; ia = ia->next ){
+		if( is_modified_action( window, NA_ACTION( ia->data ))){
 			count += 1;
 		}
-		/*g_debug( "count_modified_actions: action=%p, is_modified=%s", ia->data, is_modified ? "True":"False" );*/
 	}
-	/*g_debug( "count_modified_actions: length=%d, count=%d", g_slist_length( window->private->actions ), count );*/
+
 	return( count );
 }
 
 /*
- * called by NAPivot because this window implements the IIOContainer
+ * in initial_load_toplevel(), we have forbidden the automatic reload
+ * of the list of actions in NAPivot, as we take care of updating it of
+ * the modifications entered in the UI
+ *
+ * this doesn't prevent NAPivot to advertise us when it detects some
+ * modifications in an I/O provider ; so that we are able to ask the
+ * user for a reload
+ *
+ * but we don't want be advertized when this is our own save which
+ * triggers the NAPivot advertising - so we forbids such advertisings
+ * during one seconde after each save
+ *
+ * note that last_saved is initialized in initial_load_toplevel()
+ * there is so a race condition if NAPivot detects a modification
+ * in the seconde after this initialization - just ignore this case
+ */
+static void
+on_save( NactWindow *window )
+{
+	g_get_current_time( &NACT_MAIN_WINDOW( window )->private->last_saved );
+}
+
+/*
+ * called by NAPivot because this window implements the IIOConsumer
  * interface, i.e. it wish to be advertised when the list of actions
  * changes in the underlying I/O storage subsystem (typically, when we
  * save the modifications)
+ *
+ * note that we only reload the full list of actions when asking for a
+ * reset - saving is handled on a per-action basis.
  */
 static void
-on_actions_changed( NAIPivotContainer *instance, gpointer user_data )
+on_actions_changed( NAIPivotConsumer *instance, gpointer user_data )
 {
 	static const gchar *thisfn = "nact_main_window_on_actions_changed";
 	g_debug( "%s: instance=%p, user_data=%p", thisfn, instance, user_data );
@@ -1201,10 +1085,44 @@ on_actions_changed( NAIPivotContainer *instance, gpointer user_data )
 	g_assert( NACT_IS_MAIN_WINDOW( instance ));
 	NactMainWindow *self = NACT_MAIN_WINDOW( instance );
 
-	if( !self->private->dispose_has_run ){
-		nact_iactions_list_fill( NACT_WINDOW( instance ));
+	GTimeVal now;
+	g_get_current_time( &now );
+	glong ecart = 1000000 * ( now.tv_sec - self->private->last_saved.tv_sec );
+	ecart += now.tv_usec - self->private->last_saved.tv_usec;
+	if( ecart < 1000000 ){
+		return;
 	}
 
-	/*nact_iactions_list_set_selection(
-			NACT_WINDOW( self ), self->private->current_uuid, self->private->current_label );*/
+	NactApplication *application = NACT_APPLICATION( base_window_get_application( BASE_WINDOW( instance )));
+	NAPivot *pivot = nact_application_get_pivot( application );
+
+	gchar *first = g_strdup(_( "One or more actions have been modified in the filesystem.\n"
+								"You could keep to work with your current list of actions, "
+								"or you may want to reload a fresh one." ));
+
+	if( count_modified_actions( NACT_WINDOW( instance )) > 0 ){
+		gchar *tmp = g_strdup_printf( "%s\n\n%s", first,
+				_( "Note that reloading a fresh list of actions requires "
+					"that you give up with your current modifications." ));
+		g_free( first );
+		first = tmp;
+	}
+
+	gchar *second = g_strdup( _( "Do you want to reload a fresh list of actions ?" ));
+
+	gboolean ok = base_window_yesno_dlg( BASE_WINDOW( instance ), GTK_MESSAGE_QUESTION, first, second );
+
+	g_free( second );
+	g_free( first );
+
+	if( ok ){
+
+		na_pivot_reload_actions( pivot );
+
+		na_pivot_free_actions( self->private->actions );
+
+		self->private->actions = na_pivot_get_duplicate_actions( pivot );
+
+		nact_iactions_list_fill( NACT_WINDOW( instance ), TRUE );
+	}
 }
diff --git a/src/nact/nact-window.c b/src/nact/nact-window.c
index 9854d85..ee86e0d 100644
--- a/src/nact/nact-window.c
+++ b/src/nact/nact-window.c
@@ -35,7 +35,6 @@
 #include <glib.h>
 #include <glib/gi18n.h>
 
-#include <common/na-pivot.h>
 #include <common/na-iio-provider.h>
 
 #include "nact-application.h"
@@ -220,14 +219,14 @@ instance_finalize( GObject *window )
 /**
  * Returns a pointer to the list of actions.
  */
-GObject *
+NAPivot *
 nact_window_get_pivot( NactWindow *window )
 {
 	NactApplication *application;
 	g_object_get( G_OBJECT( window ), PROP_WINDOW_APPLICATION_STR, &application, NULL );
 	g_return_val_if_fail( NACT_IS_APPLICATION( application ), NULL );
 
-	GObject *pivot = nact_application_get_pivot( application );
+	NAPivot *pivot = nact_application_get_pivot( application );
 	g_return_val_if_fail( NA_IS_PIVOT( pivot ), NULL );
 
 	return( pivot );
@@ -255,18 +254,18 @@ nact_window_set_current_action( NactWindow *window, const NAAction *action )
  * @action: the modified action.
  */
 gboolean
-nact_window_save_action( NactWindow *window, const NAAction *action )
+nact_window_save_action( NactWindow *window, NAAction *action )
 {
 	static const gchar *thisfn = "nact_window_save_action";
 	g_debug( "%s: window=%p, action=%p", thisfn, window, action );
 
-	NAPivot *pivot = NA_PIVOT( nact_window_get_pivot( window ));
+	NAPivot *pivot = nact_window_get_pivot( window );
 	g_assert( NA_IS_PIVOT( pivot ));
 
 	na_object_dump( NA_OBJECT( action ));
 
 	gchar *msg = NULL;
-	guint ret = na_pivot_write_action( pivot, G_OBJECT( action ), &msg );
+	guint ret = na_pivot_write_action( pivot, action, &msg );
 	if( msg ){
 		base_window_error_dlg(
 				BASE_WINDOW( window ),
@@ -278,6 +277,36 @@ nact_window_save_action( NactWindow *window, const NAAction *action )
 }
 
 /**
+ * Deleted an action from the I/O storage subsystem.
+ *
+ * @window: this NactWindow object.
+ *
+ * @action: the action to delete.
+ */
+gboolean
+nact_window_delete_action( NactWindow *window, NAAction *action )
+{
+	static const gchar *thisfn = "nact_window_delete_action";
+	g_debug( "%s: window=%p, action=%p", thisfn, window, action );
+
+	NAPivot *pivot = nact_window_get_pivot( window );
+	g_assert( NA_IS_PIVOT( pivot ));
+
+	na_object_dump( NA_OBJECT( action ));
+
+	gchar *msg = NULL;
+	guint ret = na_pivot_delete_action( pivot, action, &msg );
+	if( msg ){
+		base_window_error_dlg(
+				BASE_WINDOW( window ),
+				GTK_MESSAGE_WARNING, _( "An error has occured when trying to delete the action" ), msg );
+		g_free( msg );
+	}
+
+	return( ret == NA_IIO_PROVIDER_WRITE_OK );
+}
+
+/**
  * Emits a warning if the action has been modified.
  *
  * @window: this NactWindow object.
diff --git a/src/nact/nact-window.h b/src/nact/nact-window.h
index e75e0a5..aadca3f 100644
--- a/src/nact/nact-window.h
+++ b/src/nact/nact-window.h
@@ -40,6 +40,7 @@
 
 #include <common/na-action.h>
 #include <common/na-action-profile.h>
+#include <common/na-pivot.h>
 
 #include "base-window.h"
 
@@ -74,11 +75,12 @@ typedef struct {
 
 GType    nact_window_get_type( void );
 
-GObject *nact_window_get_pivot( NactWindow *window );
+NAPivot *nact_window_get_pivot( NactWindow *window );
 
 /* TODO: check these functions */
 void     nact_window_set_current_action( NactWindow *window, const NAAction *action );
-gboolean nact_window_save_action( NactWindow *window, const NAAction *action );
+gboolean nact_window_save_action( NactWindow *window, NAAction *action );
+gboolean nact_window_delete_action( NactWindow *window, NAAction *action );
 
 /* TODO: move the function to nact-main-window */
 gboolean nact_window_warn_count_modified( NactWindow *window, gint count );
diff --git a/src/plugin/nautilus-actions.c b/src/plugin/nautilus-actions.c
index fa4d2e0..18c6b54 100644
--- a/src/plugin/nautilus-actions.c
+++ b/src/plugin/nautilus-actions.c
@@ -41,7 +41,7 @@
 #include <common/na-action.h>
 #include <common/na-action-profile.h>
 #include <common/na-pivot.h>
-#include <common/na-ipivot-container.h>
+#include <common/na-ipivot-consumer.h>
 
 #include "nautilus-actions.h"
 
@@ -62,7 +62,7 @@ static GType         st_actions_type = 0;
 
 static void              class_init( NautilusActionsClass *klass );
 static void              menu_provider_iface_init( NautilusMenuProviderIface *iface );
-static void              pivot_container_iface_init( NAIPivotContainerInterface *iface );
+static void              pivot_consumer_iface_init( NAIPivotConsumerInterface *iface );
 static void              instance_init( GTypeInstance *instance, gpointer klass );
 static void              instance_dispose( GObject *object );
 static void              instance_finalize( GObject *object );
@@ -71,7 +71,7 @@ static GList            *get_background_items( NautilusMenuProvider *provider, G
 static GList            *get_file_items( NautilusMenuProvider *provider, GtkWidget *window, GList *files );
 static NautilusMenuItem *create_menu_item( NAAction *action, NAActionProfile *profile, GList *files );
 static void              execute_action( NautilusMenuItem *item, NAActionProfile *profile );
-static void              actions_changed_handler( NAIPivotContainer *instance, gpointer user_data );
+static void              actions_changed_handler( NAIPivotConsumer *instance, gpointer user_data );
 
 GType
 nautilus_actions_get_type( void )
@@ -112,15 +112,15 @@ nautilus_actions_register_type( GTypeModule *module )
 
 	g_type_module_add_interface( module, st_actions_type, NAUTILUS_TYPE_MENU_PROVIDER, &menu_provider_iface_info );
 
-	/* implement IPivotContainer interface
+	/* implement IPivotConsumer interface
 	 */
-	static const GInterfaceInfo pivot_container_iface_info = {
-		( GInterfaceInitFunc ) pivot_container_iface_init,
+	static const GInterfaceInfo pivot_consumer_iface_info = {
+		( GInterfaceInitFunc ) pivot_consumer_iface_init,
 		NULL,
 		NULL
 	};
 
-	g_type_module_add_interface( module, st_actions_type, NA_IPIVOT_CONTAINER_TYPE, &pivot_container_iface_info );
+	g_type_module_add_interface( module, st_actions_type, NA_IPIVOT_CONSUMER_TYPE, &pivot_consumer_iface_info );
 }
 
 static void
@@ -149,9 +149,9 @@ menu_provider_iface_init( NautilusMenuProviderIface *iface )
 }
 
 static void
-pivot_container_iface_init( NAIPivotContainerInterface *iface )
+pivot_consumer_iface_init( NAIPivotConsumerInterface *iface )
 {
-	static const gchar *thisfn = "nautilus_actions_pivot_container_iface_init";
+	static const gchar *thisfn = "nautilus_actions_pivot_consumer_iface_init";
 	g_debug( "%s: iface=%p", thisfn, iface );
 
 	iface->on_actions_changed = actions_changed_handler;
@@ -171,18 +171,6 @@ instance_init( GTypeInstance *instance, gpointer klass )
 
 	/* from na-pivot */
 	self->private->pivot = na_pivot_new( G_OBJECT( self ));
-
-	/* see nautilus_actions_class_init for why we had to connect an
-	 * handler to our signal instead of relying on default handler
-	 * see also nautilus_actions_class_init for why g_signal_connect is
-	 * no more needed
-	 */
-	/*g_signal_connect(
-			G_OBJECT( self ),
-			SIGNAL_ACTION_CHANGED_NAME,
-			( GCallback ) action_changed_handler,
-			NULL
-	);*/
 }
 
 static void
@@ -328,7 +316,7 @@ create_menu_item( NAAction *action, NAActionProfile *profile, GList *files )
 	gchar *tooltip = na_action_get_tooltip( action );
 	gchar* icon_name = na_action_get_verified_icon_name( action );
 
-	NAActionProfile *dup4menu = na_action_profile_duplicate( action, profile );
+	NAActionProfile *dup4menu = NA_ACTION_PROFILE( na_object_duplicate( NA_OBJECT( profile )));
 
 	item = nautilus_menu_item_new( name, label, tooltip, icon_name );
 
@@ -336,7 +324,7 @@ create_menu_item( NAAction *action, NAActionProfile *profile, GList *files )
 				"activate",
 				G_CALLBACK( execute_action ),
 				dup4menu,
-				( GClosureNotify ) na_action_profile_free,
+				( GClosureNotify ) g_object_unref,
 				0
 	);
 
@@ -386,7 +374,7 @@ execute_action( NautilusMenuItem *item, NAActionProfile *profile )
 }
 
 static void
-actions_changed_handler( NAIPivotContainer *instance, gpointer user_data )
+actions_changed_handler( NAIPivotConsumer *instance, gpointer user_data )
 {
 	static const gchar *thisfn = "nautilus_actions_actions_changed_handler";
 	g_debug( "%s: instance=%p, user_data=%p", thisfn, instance, user_data );



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