[nautilus-actions] Rearchitecturing the code



commit 2e66aed18294f93ad768bf5d7c8eb8a0183feda3
Author: Pierre Wieser <pwieser trychlos org>
Date:   Wed Sep 16 23:31:14 2009 +0200

    Rearchitecturing the code

 ChangeLog                                          |   49 +
 configure.ac                                       |    1 -
 doc/objects-hierarchy.odg                          |  Bin 14610 -> 14909 bytes
 src/common/Makefile.am                             |   38 +-
 src/common/na-action-profile.h                     |   92 --
 src/common/na-action.c                             | 1091 ---------------
 src/common/na-action.h                             |   91 --
 .../na-gconf-keys-base.h}                          |   22 +-
 .../na-gconf-keys-schemas.h}                       |   19 +-
 src/common/na-gconf-monitor.c                      |  278 ++++
 src/common/na-gconf-monitor.h                      |   77 +
 .../{na-gconf-keys.h => na-gconf-provider-keys.h}  |   34 +-
 src/common/na-gconf-provider.c                     | 1034 ++++++++++++++
 src/common/na-gconf-provider.h                     |   81 ++
 src/common/na-gconf-utils.c                        |  368 +++++
 src/common/na-gconf-utils.h                        |   65 +
 src/common/na-gconf.c                              | 1237 ----------------
 src/common/na-iduplicable.c                        |  191 ++--
 src/common/na-iduplicable.h                        |   57 +-
 src/common/na-iio-provider.c                       |  248 ++--
 src/common/na-iio-provider.h                       |   48 +-
 src/common/na-ipivot-consumer.c                    |   28 +-
 src/common/na-iprefs.c                             |  179 ++-
 src/common/na-iprefs.h                             |   33 +-
 .../{na-action-class.h => na-obj-action-class.h}   |   44 +-
 src/common/na-obj-action.c                         |  591 ++++++++
 src/common/na-obj-action.h                         |   81 ++
 src/common/{na-action-menu.c => na-obj-menu.c}     |  237 ++--
 src/common/{na-action-menu.h => na-obj-menu.h}     |   47 +-
 ...tion-profile-class.h => na-obj-profile-class.h} |   40 +-
 .../{na-action-profile.c => na-obj-profile.c}      |  771 +++++------
 src/common/na-obj-profile.h                        |   88 ++
 src/common/na-object-api.h                         |   98 ++
 src/common/{na-object.h => na-object-class.h}      |  151 ++-
 src/common/{na-gconf.h => na-object-fn.h}          |   58 +-
 src/common/{na-gconf.h => na-object-id-class.h}    |   49 +-
 .../{na-action-class.h => na-object-id-fn.h}       |   45 +-
 src/common/na-object-id.c                          |  427 ++++++
 .../{na-object-item.h => na-object-item-class.h}   |   38 +-
 src/common/na-object-item-fn.h                     |   74 +
 src/common/na-object-item.c                        |  653 ++++++++--
 src/common/na-object.c                             |  720 +++++-----
 src/common/na-pivot.c                              |  363 +++--
 src/common/na-pivot.h                              |   28 +-
 src/common/na-utils.c                              |   13 +-
 src/common/na-utils.h                              |    2 +-
 src/common/na-xml-writer.c                         |  168 ++--
 src/common/na-xml-writer.h                         |    8 +-
 src/nact/Makefile.am                               |   27 +-
 src/nact/base-application-class.h                  |   62 +-
 src/nact/base-application.c                        |  364 +++--
 src/nact/base-application.h                        |   63 +-
 src/nact/base-assistant.c                          |  617 ++++++++
 src/nact/base-assistant.h                          |  139 ++
 src/nact/base-dialog.c                             |  164 +++
 src/{common/na-gconf.h => nact/base-dialog.h}      |   50 +-
 src/nact/{nact-iprefs.c => base-iprefs.c}          |  403 +++---
 src/nact/base-iprefs.h                             |   82 ++
 src/nact/base-window-class.h                       |   89 ++-
 src/nact/base-window.c                             |  753 +++++++---
 src/nact/base-window.h                             |   37 +-
 src/nact/egg-tree-multi-dnd.c                      |   25 +-
 src/nact/nact-application.c                        |   69 +-
 src/nact/nact-assistant-export.c                   |  267 ++--
 src/nact/nact-assistant-export.h                   |    8 +-
 src/nact/nact-assistant-import.c                   |  116 +-
 src/nact/nact-assistant-import.h                   |    8 +-
 src/nact/nact-assistant.c                          |  492 -------
 src/nact/nact-assistant.h                          |   89 --
 src/nact/nact-clipboard.c                          |  398 ++++++
 src/nact/{nact-selection.h => nact-clipboard.h}    |   18 +-
 src/nact/nact-iaction-tab.c                        |  587 ++++----
 src/nact/nact-iaction-tab.h                        |   29 +-
 src/nact/nact-iactions-list.c                      | 1472 +++++++++++---------
 src/nact/nact-iactions-list.h                      |   86 +-
 src/nact/nact-iadvanced-tab.c                      |  677 +++++----
 src/nact/nact-iadvanced-tab.h                      |   17 +-
 src/nact/nact-icommand-tab.c                       |  632 +++++-----
 src/nact/nact-icommand-tab.h                       |   20 +-
 src/nact/nact-iconditions-tab.c                    |  432 +++---
 src/nact/nact-iconditions-tab.h                    |   19 +-
 src/nact/nact-imenubar.c                           |  905 ------------
 src/nact/nact-imenubar.h                           |   83 --
 src/nact/nact-iprefs.h                             |   88 --
 src/nact/nact-main-menubar.c                       |  682 +++++++++
 src/nact/{nact-statusbar.h => nact-main-menubar.h} |   16 +-
 .../{nact-statusbar.c => nact-main-statusbar.c}    |   35 +-
 .../{nact-selection.h => nact-main-statusbar.h}    |   14 +-
 src/nact/nact-main-tab.c                           |  162 +++
 src/nact/{nact-statusbar.h => nact-main-tab.h}     |   18 +-
 src/nact/nact-main-window.c                        | 1078 +++++++--------
 src/nact/nact-main-window.h                        |   17 +-
 src/nact/nact-preferences-editor.c                 |  180 ++--
 src/nact/nact-preferences-editor.h                 |    8 +-
 src/nact/nact-selection.c                          |  180 ---
 src/nact/nact-tree-model.c                         |  790 +++++++++--
 src/nact/nact-tree-model.h                         |   25 +-
 src/nact/nact-window.c                             |  228 ++--
 src/nact/nact-window.h                             |   25 +-
 src/nact/nact-xml-reader.c                         |  176 ++--
 src/nact/nact-xml-reader.h                         |   10 +-
 src/nact/nautilus-actions-config-tool.actions      |    5 +-
 src/nact/nautilus-actions-config-tool.ui           |   26 +-
 src/plugin/nautilus-actions.c                      |  110 +-
 src/test/.gitignore                                |    3 +
 src/test/Makefile.am                               |   36 +
 src/test/test-iface-base.c                         |  207 +++
 src/{common/na-gconf.h => test/test-iface-base.h}  |   47 +-
 src/test/test-iface-derived.c                      |  225 +++
 src/test/test-iface-derived.h                      |   76 +
 src/test/test-iface-iface.c                        |  203 +++
 src/test/test-iface-iface.h                        |   82 ++
 src/test/test-iface.c                              |   72 +
 src/test/test-virtuals-without-test.c              |  604 ++++++++
 src/test/test-virtuals.c                           |  624 +++++++++
 src/utils/nautilus-actions-new.c                   |   62 +-
 src/utils/nautilus-actions-schemas.c               |    5 +-
 117 files changed, 15352 insertions(+), 10221 deletions(-)
---
diff --git a/ChangeLog b/ChangeLog
index 2a85832..8de95c2 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,52 @@
+2009-09-16 Pierre Wieser <pwieser trychlos org>
+
+	* configure.ac:
+	Remove NAUTILUS_ACTIONS_CONFIG_GCONF_BASEDIR (not a configuration
+	variable).
+
+	* src/common/na-action.c: Renamed as na-obj-action.c.
+	* src/common/na-action.h: Renamed as na-obj-action.h.
+	* src/common/na-action-class.h:	Renamed as na-obj-action-class.h.
+	Takes part of renaming NAAction class to NAObjectAction.
+
+	* src/common/na-action-profile.c: Renamed as na-obj-profile.c.
+	* src/common/na-action-profile.h: Renamed as na-obj-profile.h.
+	* src/common/na-action-profile-class.h:
+	Renamed as na-obj-profile-class.h.
+	Takes part of renaming NAActionProfile class to NAObjectProfile.
+
+	* src/common/na-action-menu.c: Renamed as na-obj-menu.c.
+	* src/common/na-action-menu.h: Renamed as na-obj-menu.h.
+	Takes part of renaming NAActionMenu class to NAObjectMenu.
+
+	* src/common/na-gconf.c: Renamed as na-gconf-provider.c.
+	* src/common/na-gconf.h: Renamed as na-gconf-provider.h.
+	Takes part of NAGConf class to NAGConfProvider.
+	This let us clearly identify the rule of the class, distinguishing
+	it from GConf as a preferences repository.
+
+	* src/common/na-gconf-key.h: Splitted in na-gconf-keys-base.h,
+	na-gconf-keys-schemas.h and na-gconf-provider-keys.h files.
+
+	* src/common/na-gconf-monitor.c: New file.
+	* src/common/na-gconf-monitor.h: New file.
+	New class NAGConfMonitor.
+
+	* src/common/na-gconf-utils.c: New file.
+	* src/common/na-gconf-utils.h: New file.
+	Handle some GConf general utilities.
+
+	* src/common/na-object.h: Splitted in na-object-fn.h,
+	na-object-class.h and na-object-api.h.
+	All NAObject-derived public functions are now declared in
+	na-object-api.h.
+
+	* src/common/na-object-id.h: Splitted in na-object-id-fn.h and
+	na-object-id-class.h.
+
+	* src/common/na-object-item.h: Splitted in na-object-item-fn.h
+	and na-object-item-class.h.
+
 2009-08-30 Pierre Wieser <pwieser trychlos org>
 
 	* data/nautilus-actions.schemas.in:
diff --git a/configure.ac b/configure.ac
index 7f572a4..a40bf26 100644
--- a/configure.ac
+++ b/configure.ac
@@ -156,6 +156,5 @@ AC_CHECK_LIB(nautilus-extension, nautilus_menu_item_new)
 AC_CHECK_FUNCS(nautilus_menu_provider_emit_items_updated_signal)
 
 AC_DEFINE_UNQUOTED(NAUTILUS_ACTIONS_CONFIG_VERSION, "2.0", [Version of the configuration format])
-AC_DEFINE_UNQUOTED(NAUTILUS_ACTIONS_CONFIG_GCONF_BASEDIR, "/apps/nautilus-actions", [GConf base dir where all config will be stored])
 
 AC_OUTPUT
diff --git a/doc/objects-hierarchy.odg b/doc/objects-hierarchy.odg
index 2a2881d..dc0bc33 100644
Binary files a/doc/objects-hierarchy.odg and b/doc/objects-hierarchy.odg differ
diff --git a/src/common/Makefile.am b/src/common/Makefile.am
index dede517..22aace4 100644
--- a/src/common/Makefile.am
+++ b/src/common/Makefile.am
@@ -37,17 +37,15 @@ AM_CPPFLAGS += \
 libnact_la_SOURCES = \
 	na-about.c									\
 	na-about.h									\
-	na-action.c									\
-	na-action.h									\
-	na-action-class.h							\
-	na-action-menu.c							\
-	na-action-menu.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-gconf-keys-base.h						\
+	na-gconf-keys-schemas.h						\
+	na-gconf-monitor.c							\
+	na-gconf-monitor.h							\
+	na-gconf-provider.c							\
+	na-gconf-provider.h							\
+	na-gconf-provider-keys.h					\
+	na-gconf-utils.c							\
+	na-gconf-utils.h							\
 	na-gnome-vfs-uri.c							\
 	na-gnome-vfs-uri.h							\
 	na-iduplicable.c							\
@@ -59,9 +57,23 @@ libnact_la_SOURCES = \
 	na-iprefs.c									\
 	na-iprefs.h									\
 	na-object.c									\
-	na-object.h									\
+	na-object-api.h								\
+	na-object-class.h							\
+	na-object-fn.h								\
+	na-object-id.c								\
+	na-object-id-class.h						\
+	na-object-id-fn.h							\
 	na-object-item.c							\
-	na-object-item.h							\
+	na-object-item-class.h						\
+	na-object-item-fn.h							\
+	na-obj-action.c								\
+	na-obj-action.h								\
+	na-obj-action-class.h						\
+	na-obj-menu.c								\
+	na-obj-menu.h								\
+	na-obj-profile.c							\
+	na-obj-profile.h							\
+	na-obj-profile-class.h						\
 	na-pivot.c									\
 	na-pivot.h									\
 	na-utils.c									\
diff --git a/src/nact/nact-statusbar.h b/src/common/na-gconf-keys-base.h
similarity index 76%
copy from src/nact/nact-statusbar.h
copy to src/common/na-gconf-keys-base.h
index 6d8221a..5ebc0d8 100644
--- a/src/nact/nact-statusbar.h
+++ b/src/common/na-gconf-keys-base.h
@@ -28,16 +28,16 @@
  *   ... and many others (see AUTHORS)
  */
 
-#ifndef __NACT_STATUSBAR_H__
-#define __NACT_STATUSBAR_H__
+#ifndef __NA_GCONF_KEYS_BASE_H__
+#define __NA_GCONF_KEYS_BASE_H__
 
-#include "nact-main-window.h"
-
-G_BEGIN_DECLS
-
-void  nact_statusbar_display_status( NactMainWindow *window, const gchar *context, const gchar *status );
-void  nact_statusbar_hide_status( NactMainWindow *window, const gchar *context );
-
-G_END_DECLS
+/* GConf general information
+ *
+ * They are used both:
+ * - by GConf as a NAIIOProvider
+ * - by GConf as the preferences storage system
+ * - for providing schemas in import/export actions
+ */
+#define NAUTILUS_ACTIONS_GCONF_BASEDIR			"/apps/nautilus-actions"
 
-#endif /* __NACT_STATUSBAR_H__ */
+#endif /* __NA_GCONF_KEYS_BASE_H__ */
diff --git a/src/nact/nact-selection.h b/src/common/na-gconf-keys-schemas.h
similarity index 78%
copy from src/nact/nact-selection.h
copy to src/common/na-gconf-keys-schemas.h
index 0ac54c6..83b9aff 100644
--- a/src/nact/nact-selection.h
+++ b/src/common/na-gconf-keys-schemas.h
@@ -28,18 +28,13 @@
  *   ... and many others (see AUTHORS)
  */
 
-#ifndef __NACT_DND_H__
-#define __NACT_DND_H__
+#ifndef __NA_GCONF_KEYS_SCHEMAS_H__
+#define __NA_GCONF_KEYS_SCHEMAS_H__
 
-#include <glib.h>
+#include "na-gconf-keys-base.h"
 
-G_BEGIN_DECLS
-
-char *nact_selection_get_data_for_intern_use( GSList *selected_items );
-char *nact_selection_get_data_for_extern_use( GSList *selected_items );
-
-void  nact_selection_export_items( const gchar *uri, GSList *items );
-
-G_END_DECLS
+/* GConf general information
+ */
+#define NAUTILUS_ACTIONS_GCONF_SCHEMASDIR		"/schemas"
 
-#endif /* __NACT_DND_H__ */
+#endif /* __NA_GCONF_KEYS_SCHEMAS_H__ */
diff --git a/src/common/na-gconf-monitor.c b/src/common/na-gconf-monitor.c
new file mode 100644
index 0000000..57a8458
--- /dev/null
+++ b/src/common/na-gconf-monitor.c
@@ -0,0 +1,278 @@
+/*
+ * 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-gconf-monitor.h"
+
+/* private class data
+ */
+struct NAGConfMonitorClassPrivate {
+	void *empty;						/* so that gcc -pedantic is happy */
+};
+
+/* private instance data
+ */
+struct NAGConfMonitorPrivate {
+	gboolean              dispose_has_run;
+	GConfClient          *gconf;
+	gchar                *path;
+	gint                  preload;
+	GConfClientNotifyFunc handler;
+	gpointer              user_data;
+	guint                 monitor_id;
+};
+
+static GObjectClass *st_parent_class = NULL;
+
+static GType register_type( void );
+static void  class_init( NAGConfMonitorClass *klass );
+static void  instance_init( GTypeInstance *instance, gpointer klass );
+static void  instance_dispose( GObject *object );
+static void  instance_finalize( GObject *object );
+
+static guint install_monitor( NAGConfMonitor *monitor );
+static void  release_monitor( NAGConfMonitor *monitor );
+
+GType
+na_gconf_monitor_get_type( void )
+{
+	static GType object_type = 0;
+
+	if( !object_type ){
+		object_type = register_type();
+	}
+
+	return( object_type );
+}
+
+static GType
+register_type( void )
+{
+	static const gchar *thisfn = "na_gconf_monitor_register_type";
+	GType type;
+
+	static GTypeInfo info = {
+		sizeof( NAGConfMonitorClass ),
+		NULL,
+		NULL,
+		( GClassInitFunc ) class_init,
+		NULL,
+		NULL,
+		sizeof( NAGConfMonitor ),
+		0,
+		( GInstanceInitFunc ) instance_init
+	};
+
+	g_debug( "%s", thisfn );
+
+	type = g_type_register_static( G_TYPE_OBJECT, "NAGConfMonitor", &info, 0 );
+
+	return( type );
+}
+
+static void
+class_init( NAGConfMonitorClass *klass )
+{
+	static const gchar *thisfn = "na_gconf_monitor_class_init";
+	GObjectClass *object_class;
+
+	g_debug( "%s: klass=%p", thisfn, ( void * ) klass );
+
+	st_parent_class = g_type_class_peek_parent( klass );
+
+	object_class = G_OBJECT_CLASS( klass );
+	object_class->dispose = instance_dispose;
+	object_class->finalize = instance_finalize;
+
+	klass->private = g_new0( NAGConfMonitorClassPrivate, 1 );
+}
+
+static void
+instance_init( GTypeInstance *instance, gpointer klass )
+{
+	static const gchar *thisfn = "na_gconf_monitor_instance_init";
+	NAGConfMonitor *self;
+
+	g_debug( "%s: instance=%p, klass=%p", thisfn, ( void * ) instance, ( void * ) klass );
+	g_return_if_fail( NA_IS_GCONF_MONITOR( instance ));
+	self = NA_GCONF_MONITOR( instance );
+
+	self->private = g_new0( NAGConfMonitorPrivate, 1 );
+}
+
+static void
+instance_dispose( GObject *object )
+{
+	static const gchar *thisfn = "na_gconf_monitor_instance_dispose";
+	NAGConfMonitor *self;
+
+	g_debug( "%s: object=%p", thisfn, ( void * ) object );
+	g_return_if_fail( NA_IS_GCONF_MONITOR( object ));
+	self = NA_GCONF_MONITOR( object );
+
+	if( !self->private->dispose_has_run ){
+
+		self->private->dispose_has_run = TRUE;
+
+		/* release the installed monitor */
+		release_monitor( self );
+
+		/* chain up to the parent class */
+		if( G_OBJECT_CLASS( st_parent_class )->dispose ){
+			G_OBJECT_CLASS( st_parent_class )->dispose( object );
+		}
+	}
+}
+
+static void
+instance_finalize( GObject *object )
+{
+	NAGConfMonitor *self;
+
+	g_return_if_fail( NA_IS_GCONF_MONITOR( object ));
+	self = NA_GCONF_MONITOR( object );
+
+	g_free( self->private->path );
+	g_free( self->private );
+
+	/* chain call to parent class */
+	if( G_OBJECT_CLASS( st_parent_class )->finalize ){
+		G_OBJECT_CLASS( st_parent_class )->finalize( object );
+	}
+}
+
+/**
+ * na_gconf_monitor_new:
+ * @client: a #GConfClient object already initialized by the caller.
+ * @path: the absolute path to monitor.
+ * @preload: a #GConfClientPreloadType for this monitoring.
+ * @handler: the function to be triggered by the monitor.
+ * @user_data: data to pass to the @handler.
+ *
+ * Initializes the monitoring of a GConf path.
+ */
+NAGConfMonitor *
+na_gconf_monitor_new( GConfClient *client, const gchar *path, gint preload, GConfClientNotifyFunc handler, gpointer user_data )
+{
+	static const gchar *thisfn = "na_gconf_monitor_new";
+	NAGConfMonitor *monitor;
+
+	g_debug( "%s: client=%p, path=%s, preload=%d, user_data=%p",
+			thisfn, ( void * ) client, path, preload, ( void * ) user_data );
+
+	monitor = g_object_new( NA_GCONF_MONITOR_TYPE, NULL );
+
+	monitor->private->gconf = client;
+	monitor->private->path = g_strdup( path );
+	monitor->private->preload = preload;
+	monitor->private->handler = handler;
+	monitor->private->user_data = user_data;
+
+	monitor->private->monitor_id = install_monitor( monitor );
+
+	return( monitor );
+}
+
+static guint
+install_monitor( NAGConfMonitor *monitor )
+{
+	static const gchar *thisfn = "na_gconf_monitor_install_monitor";
+	GError *error = NULL;
+	guint notify_id;
+
+	g_return_val_if_fail( NA_IS_GCONF_MONITOR( monitor ), 0 );
+	g_return_val_if_fail( !monitor->private->dispose_has_run, 0 );
+
+	gconf_client_add_dir(
+			monitor->private->gconf,
+			monitor->private->path,
+			monitor->private->preload,
+			&error );
+
+	if( error ){
+		g_warning( "%s[gconf_client_add_dir] path=%s, error=%s", thisfn, monitor->private->path, error->message );
+		g_error_free( error );
+		return( 0 );
+	}
+
+	notify_id = gconf_client_notify_add(
+			monitor->private->gconf,
+			monitor->private->path,
+			monitor->private->handler,
+			monitor->private->user_data,
+			NULL,
+			&error );
+
+	if( error ){
+		g_warning( "%s[gconf_client_notify_add] path=%s, error=%s", thisfn, monitor->private->path, error->message );
+		g_error_free( error );
+		return( 0 );
+	}
+
+	return( notify_id );
+}
+
+/**
+ * na_gconf_monitor_release_monitors:
+ * @monitors: a list of #NAGConfMonitors.
+ *
+ * Release allocated monitors.
+ */
+void
+na_gconf_monitor_release_monitors( GSList *monitors )
+{
+	g_slist_foreach( monitors, ( GFunc ) g_object_unref, NULL );
+	g_slist_free( monitors );
+}
+
+static void
+release_monitor( NAGConfMonitor *monitor )
+{
+	static const gchar *thisfn = "na_gconf_monitor_release_monitor";
+	GError *error = NULL;
+
+	g_debug( "%s: monitor=%p", thisfn, ( void * ) monitor );
+
+	g_return_if_fail( NA_IS_GCONF_MONITOR( monitor ));
+
+	if( monitor->private->monitor_id ){
+		gconf_client_notify_remove( monitor->private->gconf, monitor->private->monitor_id );
+	}
+
+	gconf_client_remove_dir( monitor->private->gconf, monitor->private->path, &error );
+
+	if( error ){
+		g_warning( "%s[gconf_client_remove_dir] path=%s, error=%s", thisfn, monitor->private->path, error->message );
+		g_error_free( error );
+	}
+}
diff --git a/src/common/na-gconf-monitor.h b/src/common/na-gconf-monitor.h
new file mode 100644
index 0000000..a0c6f5c
--- /dev/null
+++ b/src/common/na-gconf-monitor.h
@@ -0,0 +1,77 @@
+/*
+ * 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_GCONF_MONITOR_H__
+#define __NA_GCONF_MONITOR_H__
+
+/**
+ * SECTION: na_gconf_monitor
+ * @short_description: #NAGConfMonitor class definition.
+ * @include: common/na-gconf-monitor.h
+ *
+ * This class manages the GConf monitoring.
+ */
+
+#include <gconf/gconf-client.h>
+
+G_BEGIN_DECLS
+
+#define NA_GCONF_MONITOR_TYPE					( na_gconf_monitor_get_type())
+#define NA_GCONF_MONITOR( object )				( G_TYPE_CHECK_INSTANCE_CAST( object, NA_GCONF_MONITOR_TYPE, NAGConfMonitor ))
+#define NA_GCONF_MONITOR_CLASS( klass )			( G_TYPE_CHECK_CLASS_CAST( klass, NA_GCONF_MONITOR_TYPE, NAGConfMonitorClass ))
+#define NA_IS_GCONF_MONITOR( object )			( G_TYPE_CHECK_INSTANCE_TYPE( object, NA_GCONF_MONITOR_TYPE ))
+#define NA_IS_GCONF_MONITOR_CLASS( klass )		( G_TYPE_CHECK_CLASS_TYPE(( klass ), NA_GCONF_MONITOR_TYPE ))
+#define NA_GCONF_MONITOR_GET_CLASS( object )	( G_TYPE_INSTANCE_GET_CLASS(( object ), NA_GCONF_MONITOR_TYPE, NAGConfMonitorClass ))
+
+typedef struct NAGConfMonitorPrivate NAGConfMonitorPrivate;
+
+typedef struct {
+	GObject                parent;
+	NAGConfMonitorPrivate *private;
+}
+	NAGConfMonitor;
+
+typedef struct NAGConfMonitorClassPrivate NAGConfMonitorClassPrivate;
+
+typedef struct {
+	GObjectClass                parent;
+	NAGConfMonitorClassPrivate *private;
+}
+	NAGConfMonitorClass;
+
+GType           na_gconf_monitor_get_type( void );
+
+NAGConfMonitor *na_gconf_monitor_new( GConfClient *client, const gchar *path, gint preload, GConfClientNotifyFunc handler, gpointer user_data );
+
+void            na_gconf_monitor_release_monitors( GSList *monitors );
+
+G_END_DECLS
+
+#endif /* __NA_GCONF_MONITOR_MONITOR_H__ */
diff --git a/src/common/na-gconf-keys.h b/src/common/na-gconf-provider-keys.h
similarity index 72%
rename from src/common/na-gconf-keys.h
rename to src/common/na-gconf-provider-keys.h
index a3bb325..98e861f 100644
--- a/src/common/na-gconf-keys.h
+++ b/src/common/na-gconf-provider-keys.h
@@ -28,23 +28,33 @@
  *   ... and many others (see AUTHORS)
  */
 
-#ifndef __NA_GCONF_KEYS_H__
-#define __NA_GCONF_KEYS_H__
+#ifndef __NA_GCONF_PROVIDER_KEYS_H__
+#define __NA_GCONF_PROVIDER_KEYS_H__
+
+#include "na-gconf-keys-base.h"
+#include "na-gconf-keys-schemas.h"
 
 /* GConf general information
  */
-#define NA_GCONF_CONFIG_CONFIGURATION	"configurations"
-#define NA_GCONF_CONFIG_PATH			NAUTILUS_ACTIONS_CONFIG_GCONF_BASEDIR "/" NA_GCONF_CONFIG_CONFIGURATION
-#define NA_GCONF_SCHEMA_PREFIX			"/schemas"
-#define NA_GCONF_SCHEMA_PREFERENCES		"preferences"
+#define NA_GCONF_CONFIG_PATH			NAUTILUS_ACTIONS_GCONF_BASEDIR "/configurations"
+
+/* GConf key names (common to menu and actions)
+ */
+#define OBJECT_ITEM_LABEL_ENTRY			"label"
+#define OBJECT_ITEM_TOOLTIP_ENTRY		"tooltip"
+#define OBJECT_ITEM_ICON_ENTRY			"icon"
+#define OBJECT_ITEM_ENABLED_ENTRY		"enabled"
 
-/* GConf key names
+/* GConf key names (specific to menu)
+ */
+#define MENU_ITEMS_ENTRY				"items"
+
+/* GConf key names (specific to action)
  */
 #define ACTION_VERSION_ENTRY			"version"
-#define ACTION_LABEL_ENTRY				"label"
-#define ACTION_TOOLTIP_ENTRY			"tooltip"
-#define ACTION_ICON_ENTRY				"icon"
-#define ACTION_ENABLED_ENTRY			"enabled"
+
+/* GConf key names (specific to profile)
+ */
 #define ACTION_PROFILE_LABEL_ENTRY		"desc-name"
 #define ACTION_PATH_ENTRY				"path"
 #define ACTION_PARAMETERS_ENTRY			"parameters"
@@ -56,4 +66,4 @@
 #define ACTION_MULTIPLE_ENTRY			"accept-multiple-files"
 #define ACTION_SCHEMES_ENTRY			"schemes"
 
-#endif /* __NA_GCONF_KEYS_H__ */
+#endif /* __NA_GCONF_PROVIDER_KEYS_H__ */
diff --git a/src/common/na-gconf-provider.c b/src/common/na-gconf-provider.c
new file mode 100644
index 0000000..08d85fb
--- /dev/null
+++ b/src/common/na-gconf-provider.c
@@ -0,0 +1,1034 @@
+/*
+ * 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 <string.h>
+
+#include "na-object-api.h"
+#include "na-obj-action.h"
+#include "na-obj-profile.h"
+#include "na-obj-menu.h"
+#include "na-gconf-monitor.h"
+#include "na-gconf-provider.h"
+#include "na-gconf-provider-keys.h"
+#include "na-gconf-utils.h"
+#include "na-iio-provider.h"
+#include "na-utils.h"
+
+/* private class data
+ */
+struct NAGConfProviderClassPrivate {
+	void *empty;						/* so that gcc -pedantic is happy */
+};
+
+/* private instance data
+ */
+struct NAGConfProviderPrivate {
+	gboolean     dispose_has_run;
+	GConfClient *gconf;
+	NAPivot     *pivot;
+	GSList      *monitors;
+};
+
+static GObjectClass *st_parent_class = NULL;
+
+static GType          register_type( void );
+static void           class_init( NAGConfProviderClass *klass );
+static void           iio_provider_iface_init( NAIIOProviderInterface *iface );
+static void           instance_init( GTypeInstance *instance, gpointer klass );
+static void           instance_dispose( GObject *object );
+static void           instance_finalize( GObject *object );
+
+static void           install_monitors( NAGConfProvider *provider );
+static void           config_path_changed_cb( GConfClient *client, guint cnxn_id, GConfEntry *entry, NAGConfProvider *provider );
+static NAPivotNotify *entry_to_notify( const GConfEntry *entry );
+
+static GSList        *iio_provider_read_items_list( const NAIIOProvider *provider );
+static NAObjectItem  *read_item( NAGConfProvider *provider, const gchar *path );
+static void           read_item_action( NAGConfProvider *provider, const gchar *path, NAObjectAction *action );
+static void           read_item_action_properties( NAGConfProvider *provider, GSList *entries, NAObjectAction *action );
+static void           read_item_action_properties_v1( NAGConfProvider *gconf, GSList *entries, NAObjectAction *action );
+static void           read_item_action_profile( NAGConfProvider *provider, const gchar *path, NAObjectProfile *profile );
+static void           read_item_action_profile_properties( NAGConfProvider *provider, GSList *entries, NAObjectProfile *profile );
+static void           read_item_menu( NAGConfProvider *provider, const gchar *path, NAObjectMenu *menu );
+static void           read_item_menu_properties( NAGConfProvider *provider, GSList *entries, NAObjectMenu *menu );
+static void           read_object_item_properties( NAGConfProvider *provider, GSList *entries, NAObjectItem *item );
+
+static gboolean       iio_provider_is_willing_to_write( const NAIIOProvider *provider );
+
+static gboolean       iio_provider_is_writable( const NAIIOProvider *provider, const NAObject *item );
+
+static guint          iio_provider_write_item( const NAIIOProvider *provider, NAObject *item, gchar **message );
+static gboolean       write_item_action( NAGConfProvider *gconf, const NAObjectAction *action, gchar **message );
+static gboolean       write_item_menu( NAGConfProvider *gconf, const NAObjectMenu *menu, gchar **message );
+static gboolean       write_object_item( NAGConfProvider *gconf, const NAObjectItem *item, gchar **message );
+
+static guint          iio_provider_delete_item( const NAIIOProvider *provider, const NAObject *item, gchar **message );
+
+static gboolean       key_is_writable( NAGConfProvider *gconf, const gchar *path );
+
+static gboolean       write_str( NAGConfProvider *gconf, const gchar *uuid, const gchar *name, const gchar *key, gchar *value, gchar **message );
+static gboolean       write_bool( NAGConfProvider *gconf, const gchar *uuid, const gchar *name, const gchar *key, gboolean value, gchar **message );
+static gboolean       write_list( NAGConfProvider *gconf, const gchar *uuid, const gchar *name, const gchar *key, GSList *value, gchar **message );
+
+GType
+na_gconf_provider_get_type( void )
+{
+	static GType object_type = 0;
+
+	if( !object_type ){
+		object_type = register_type();
+	}
+
+	return( object_type );
+}
+
+static GType
+register_type( void )
+{
+	static const gchar *thisfn = "na_gconf_provider_register_type";
+	GType type;
+
+	static GTypeInfo info = {
+		sizeof( NAGConfProviderClass ),
+		NULL,
+		NULL,
+		( GClassInitFunc ) class_init,
+		NULL,
+		NULL,
+		sizeof( NAGConfProvider ),
+		0,
+		( GInstanceInitFunc ) instance_init
+	};
+
+	static const GInterfaceInfo iio_provider_iface_info = {
+		( GInterfaceInitFunc ) iio_provider_iface_init,
+		NULL,
+		NULL
+	};
+
+	g_debug( "%s", thisfn );
+
+	type = g_type_register_static( G_TYPE_OBJECT, "NAGConfProvider", &info, 0 );
+
+	g_type_add_interface_static( type, NA_IIO_PROVIDER_TYPE, &iio_provider_iface_info );
+
+	return( type );
+}
+
+static void
+class_init( NAGConfProviderClass *klass )
+{
+	static const gchar *thisfn = "na_gconf_provider_class_init";
+	GObjectClass *object_class;
+
+	g_debug( "%s: klass=%p", thisfn, ( void * ) klass );
+
+	st_parent_class = g_type_class_peek_parent( klass );
+
+	object_class = G_OBJECT_CLASS( klass );
+	object_class->dispose = instance_dispose;
+	object_class->finalize = instance_finalize;
+
+	klass->private = g_new0( NAGConfProviderClassPrivate, 1 );
+}
+
+static void
+iio_provider_iface_init( NAIIOProviderInterface *iface )
+{
+	static const gchar *thisfn = "na_gconf_provider_iio_provider_iface_init";
+
+	g_debug( "%s: iface=%p", thisfn, ( void * ) iface );
+
+	iface->read_items_list = iio_provider_read_items_list;
+	iface->is_willing_to_write = iio_provider_is_willing_to_write;
+	iface->is_writable = iio_provider_is_writable;
+	iface->write_item = iio_provider_write_item;
+	iface->delete_item = iio_provider_delete_item;
+}
+
+static void
+instance_init( GTypeInstance *instance, gpointer klass )
+{
+	static const gchar *thisfn = "na_gconf_provider_instance_init";
+	NAGConfProvider *self;
+
+	g_debug( "%s: instance=%p, klass=%p", thisfn, ( void * ) instance, ( void * ) klass );
+	g_return_if_fail( NA_IS_GCONF_PROVIDER( instance ));
+	self = NA_GCONF_PROVIDER( instance );
+
+	self->private = g_new0( NAGConfProviderPrivate, 1 );
+
+	self->private->dispose_has_run = FALSE;
+	self->private->pivot = NULL;
+	self->private->gconf = NULL;
+	self->private->monitors = NULL;
+}
+
+static void
+instance_dispose( GObject *object )
+{
+	static const gchar *thisfn = "na_gconf_provider_instance_dispose";
+	NAGConfProvider *self;
+
+	g_debug( "%s: object=%p", thisfn, ( void * ) object );
+	g_return_if_fail( NA_IS_GCONF_PROVIDER( object ));
+	self = NA_GCONF_PROVIDER( object );
+
+	if( !self->private->dispose_has_run ){
+
+		self->private->dispose_has_run = TRUE;
+
+		/* release the GConf monitoring */
+		na_gconf_monitor_release_monitors( self->private->monitors );
+
+		/* release the GConf connexion */
+		g_object_unref( self->private->gconf );
+
+		/* chain up to the parent class */
+		if( G_OBJECT_CLASS( st_parent_class )->dispose ){
+			G_OBJECT_CLASS( st_parent_class )->dispose( object );
+		}
+	}
+}
+
+static void
+instance_finalize( GObject *object )
+{
+	NAGConfProvider *self;
+
+	g_assert( NA_IS_GCONF_PROVIDER( object ));
+	self = NA_GCONF_PROVIDER( object );
+
+	g_free( self->private );
+
+	/* chain call to parent class */
+	if( G_OBJECT_CLASS( st_parent_class )->finalize ){
+		G_OBJECT_CLASS( st_parent_class )->finalize( object );
+	}
+}
+
+/**
+ * na_gconf_provider_new:
+ * @handler: the #NAPivot which is to be notified when an
+ * item is added, modified or removed in underlying GConf system.
+ *
+ * Allocates a new #NAGConfProvider object.
+ *
+ * The specified #NAPivot object 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.
+ */
+NAGConfProvider *
+na_gconf_provider_new( NAPivot *handler )
+{
+	NAGConfProvider *provider;
+
+	g_return_val_if_fail( NA_IS_PIVOT( handler ), NULL );
+
+	provider = g_object_new( NA_GCONF_PROVIDER_TYPE, NULL );
+
+	provider->private->gconf = gconf_client_get_default();
+
+	if( handler ){
+		provider->private->pivot = handler;
+		install_monitors( provider );
+	}
+
+	return( provider );
+}
+
+static void
+install_monitors( NAGConfProvider *provider )
+{
+	GSList *list = NULL;
+
+	g_return_if_fail( NA_IS_GCONF_PROVIDER( provider ));
+	g_return_if_fail( NA_IS_IIO_PROVIDER( provider ));
+	g_return_if_fail( !provider->private->dispose_has_run );
+
+	/* monitor the configurations/ directory which contains all menus,
+	 * actions and profiles definitions
+	 */
+	list = g_slist_prepend( list,
+			na_gconf_monitor_new(
+					provider->private->gconf,
+					NA_GCONF_CONFIG_PATH,
+					GCONF_CLIENT_PRELOAD_RECURSIVE,
+					( GConfClientNotifyFunc ) config_path_changed_cb,
+					provider));
+
+	provider->private->monitors = list;
+}
+
+/*
+ * this callback is triggered each time a value is changed under our
+ * configurations/ directory
+ *
+ * if the modification is made from nautilus-actions-config ui, then
+ * the callback is triggered several times (one time for each rewritten
+ * property) as action/profile are edited as blocs of data ; in this
+ * case, the ui takes care (as of of 1.10) of also writing at last a
+ * particular key of the form xxx:yyyyyyyy-yyyy-yyyy-..., where :
+ *    xxx was a sequential number (inside of the ui session)
+ *    yyyyyyyy-yyyy-yyyy-... was the uuid of the involved action
+ *
+ * this was so a sort of hack which simplifies a lot the notification
+ * system (take the new action, replace it in the current global list)
+ * but didn't work if the modification was made from outside of the ui
+ *
+ * if the modification is made elsewhere (an action is imported as a
+ * xml file in gconf, or gconf is directly edited), we'd have to rely
+ * only on the standard mmonitor (GConf watch) mechanism
+ */
+static void
+config_path_changed_cb( GConfClient *client, guint cnxn_id, GConfEntry *entry, NAGConfProvider *provider )
+{
+	/*static const gchar *thisfn = "na_gconf_provider_config_path_changed_cb";*/
+	NAPivotNotify *npn;
+
+	g_return_if_fail( NA_IS_GCONF_PROVIDER( provider ));
+	g_return_if_fail( NA_IS_IIO_PROVIDER( provider ));
+	g_return_if_fail( !provider->private->dispose_has_run );
+
+	/*g_debug( "%s: client=%p, cnxnid=%u, entry=%p, provider=%p",
+			thisfn, ( void * ) client, cnxn_id, ( void * ) entry, ( void * ) provider );*/
+
+	npn = entry_to_notify( entry );
+	g_signal_emit_by_name( provider->private->pivot, NA_IIO_PROVIDER_SIGNAL_ACTION_CHANGED, npn );
+}
+
+/*
+ * 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;
+	NAPivotNotify *npn;
+	gchar **split;
+	const gchar *path;
+	const gchar *subpath;
+	const GConfValue *value;
+
+	g_assert( entry );
+	path = gconf_entry_get_key( entry );
+	g_assert( path );
+
+	npn = g_new0( NAPivotNotify, 1 );
+
+	subpath = path + strlen( NA_GCONF_CONFIG_PATH ) + 1;
+	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 );
+
+	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 = GINT_TO_POINTER( 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 );
+}
+
+/**
+ * iio_provider_read_items_list:
+ *
+ * Note that whatever be the version of the readen action, it will be
+ * stored as a #NAObjectAction and its set of #NAObjectProfile of the same,
+ * latest, version of these classes.
+ */
+static GSList *
+iio_provider_read_items_list( const NAIIOProvider *provider )
+{
+	static const gchar *thisfn = "na_gconf_provider_iio_provider_read_items_list";
+	NAGConfProvider *self;
+	GSList *items_list = NULL;
+	GSList *listpath, *ip;
+	NAObjectItem *item;
+
+	g_debug( "%s: provider=%p", thisfn, ( void * ) provider );
+
+	g_return_val_if_fail( NA_IS_IIO_PROVIDER( provider ), NULL );
+	g_return_val_if_fail( NA_IS_GCONF_PROVIDER( provider ), NULL );
+	self = NA_GCONF_PROVIDER( provider );
+	g_return_val_if_fail( !self->private->dispose_has_run, NULL );
+
+	listpath = na_gconf_utils_get_subdirs( self->private->gconf, NA_GCONF_CONFIG_PATH );
+
+	for( ip = listpath ; ip ; ip = ip->next ){
+
+		const gchar *path = ( const gchar * ) ip->data;
+
+		item = read_item( self, path );
+
+		items_list = g_slist_prepend( items_list, item );
+	}
+
+	na_gconf_utils_free_subdirs( listpath );
+
+	return( items_list );
+}
+
+/*
+ * if there is an "items" entry, this is a menu and there must not
+ * be any subdirectories
+ * else, this is an action, and there must have at least one subdir..
+ */
+static NAObjectItem *
+read_item( NAGConfProvider *provider, const gchar *path )
+{
+	static const gchar *thisfn = "na_gconf_provider_read_item";
+	NAObjectItem *item;
+	gboolean have_items;
+	gboolean have_subdir;
+
+	g_return_val_if_fail( NA_IS_GCONF_PROVIDER( provider ), NULL );
+	g_return_val_if_fail( NA_IS_IIO_PROVIDER( provider ), NULL );
+	g_return_val_if_fail( !provider->private->dispose_has_run, NULL );
+
+	have_subdir = na_gconf_utils_have_subdir( provider->private->gconf, path );
+	have_items = na_gconf_utils_have_entry( provider->private->gconf, path, MENU_ITEMS_ENTRY );
+
+	if( have_subdir && have_items ){
+		g_warning( "%s: found both subdir and \"items\" entry at %s", thisfn, path );
+		return( NULL );
+	}
+
+	if( have_items ){
+		item = NA_OBJECT_ITEM( na_object_menu_new());
+		read_item_menu( provider, path, NA_OBJECT_MENU( item ));
+		return( item );
+	}
+
+	item = NA_OBJECT_ITEM( na_object_action_new());
+	read_item_action( provider, path, NA_OBJECT_ACTION( item ));
+	return( item );
+}
+
+/*
+ * load and set the properties of the specified action
+ * at least we must have a label, as all other entries can have
+ * suitable default values
+ *
+ * we have to deal with successive versions of action schema :
+ *
+ * - version = '1.0'
+ *   action+= uuid+label+tooltip+icon
+ *   action+= path+parameters+basenames+isdir+isfile+multiple+schemes
+ *
+ * - version > '1.0'
+ *   action+= matchcase+mimetypes
+ *
+ * - version = '2.0' which introduces the 'profile' notion
+ *   profile += name+label
+ */
+static void
+read_item_action( NAGConfProvider *provider, const gchar *path, NAObjectAction *action )
+{
+	static const gchar *thisfn = "na_gconf_provider_read_item_action";
+	gchar *uuid;
+	GSList *entries, *list_profiles, *ip;
+	NAObjectProfile *profile;
+
+	g_debug( "%s: provider=%p, path=%s, action=%p",
+			thisfn, ( void * ) provider, path, ( void * ) action );
+	g_return_if_fail( NA_IS_OBJECT_ACTION( action ));
+
+	uuid = na_gconf_utils_path_to_key( path );
+	na_object_set_id( action, uuid );
+	g_free( uuid );
+
+	entries = na_gconf_utils_get_entries( provider->private->gconf, path );
+
+	read_item_action_properties( provider, entries, action  );
+
+	list_profiles = na_gconf_utils_get_subdirs( provider->private->gconf, path );
+
+	if( list_profiles ){
+		for( ip = list_profiles ; ip ; ip = ip->next ){
+
+			const gchar *profile_path = ( const gchar * ) ip->data;
+			profile = na_object_profile_new();
+			read_item_action_profile( provider, profile_path, profile );
+			na_object_action_attach_profile( action, profile );
+		}
+
+	} else {
+		read_item_action_properties_v1( provider, entries, action );
+	}
+
+	na_gconf_utils_free_subdirs( list_profiles );
+	na_gconf_utils_free_entries( entries );
+
+	na_object_action_set_readonly( action, !key_is_writable( provider, path ));
+}
+
+/*
+ * set the item properties into the action, dealing with successive
+ * versions
+ */
+static void
+read_item_action_properties( NAGConfProvider *provider, GSList *entries, NAObjectAction *action )
+{
+	gchar *version;
+
+	read_object_item_properties( provider, entries, NA_OBJECT_ITEM( action ) );
+
+	if( na_gconf_utils_get_string_from_entries( entries, ACTION_VERSION_ENTRY, &version )){
+		na_object_action_set_version( action, version );
+		g_free( version );
+	}
+}
+
+/*
+ * 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
+read_item_action_properties_v1( NAGConfProvider *provider, GSList *entries, NAObjectAction *action )
+{
+	NAObjectProfile *profile = na_object_profile_new();
+
+	na_object_action_attach_profile( action, profile );
+
+	read_item_action_profile_properties( provider, entries, profile );
+}
+
+static void
+read_item_action_profile( NAGConfProvider *provider, const gchar *path, NAObjectProfile *profile )
+{
+	gchar *name;
+	GSList *entries;
+
+	g_return_if_fail( NA_IS_OBJECT_PROFILE( profile ));
+
+	name = na_gconf_utils_path_to_key( path );
+	na_object_set_id( profile, name );
+	g_free( name );
+
+	entries = na_gconf_utils_get_entries( provider->private->gconf, path );
+	read_item_action_profile_properties( provider, entries, profile );
+	na_gconf_utils_free_entries( entries );
+}
+
+static void
+read_item_action_profile_properties( NAGConfProvider *provider, GSList *entries, NAObjectProfile *profile )
+{
+	gchar *label, *path, *parameters;
+	GSList *basenames, *schemes, *mimetypes;
+	gboolean isfile, isdir, multiple, matchcase;
+
+	if( !na_gconf_utils_get_string_from_entries( entries, ACTION_PROFILE_LABEL_ENTRY, &label )){
+		/* i18n: default profile label */
+		label = g_strdup( NA_OBJECT_PROFILE_DEFAULT_LABEL );
+	}
+	na_object_set_label( profile, label );
+	g_free( label );
+
+	if( na_gconf_utils_get_string_from_entries( entries, ACTION_PATH_ENTRY, &path )){
+		na_object_profile_set_path( profile, path );
+		g_free( path );
+	}
+
+	if( na_gconf_utils_get_string_from_entries( entries, ACTION_PARAMETERS_ENTRY, &parameters )){
+		na_object_profile_set_parameters( profile, parameters );
+		g_free( parameters );
+	}
+
+	if( na_gconf_utils_get_string_list_from_entries( entries, ACTION_BASENAMES_ENTRY, &basenames )){
+		na_object_profile_set_basenames( profile, basenames );
+		na_utils_free_string_list( basenames );
+	}
+
+	if( na_gconf_utils_get_bool_from_entries( entries, ACTION_ISFILE_ENTRY, &isfile )){
+		na_object_profile_set_isfile( profile, isfile );
+	}
+
+	if( na_gconf_utils_get_bool_from_entries( entries, ACTION_ISDIR_ENTRY, &isdir )){
+		na_object_profile_set_isdir( profile, isdir );
+	}
+
+	if( na_gconf_utils_get_bool_from_entries( entries, ACTION_MULTIPLE_ENTRY, &multiple )){
+		na_object_profile_set_multiple( profile, multiple );
+	}
+
+	if( na_gconf_utils_get_string_list_from_entries( entries, ACTION_SCHEMES_ENTRY, &schemes )){
+		na_object_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_object_profile_instance_init
+	 */
+	if( na_gconf_utils_get_bool_from_entries( entries, ACTION_MATCHCASE_ENTRY, &matchcase )){
+		na_object_profile_set_matchcase( profile, matchcase );
+	}
+
+	if( na_gconf_utils_get_string_list_from_entries( entries, ACTION_MIMETYPES_ENTRY, &mimetypes )){
+		na_object_profile_set_mimetypes( profile, mimetypes );
+		na_utils_free_string_list( mimetypes );
+	}
+}
+
+static void
+read_item_menu( NAGConfProvider *provider, const gchar *path, NAObjectMenu *menu )
+{
+	static const gchar *thisfn = "na_gconf_provider_read_item_menu";
+	gchar *uuid;
+	GSList *entries;
+
+	g_debug( "%s: provider=%p, path=%s, menu=%p",
+			thisfn, ( void * ) provider, path, ( void * ) menu );
+	g_return_if_fail( NA_IS_OBJECT_MENU( menu ));
+
+	uuid = na_gconf_utils_path_to_key( path );
+	na_object_set_id( menu, uuid );
+	g_free( uuid );
+
+	entries = na_gconf_utils_get_entries( provider->private->gconf, path );
+	read_item_menu_properties( provider, entries, menu  );
+	na_gconf_utils_free_entries( entries );
+}
+
+static void
+read_item_menu_properties( NAGConfProvider *provider, GSList *entries, NAObjectMenu *menu )
+{
+	GSList *items;
+
+	read_object_item_properties( provider, entries, NA_OBJECT_ITEM( menu ) );
+
+	if( na_gconf_utils_get_string_list_from_entries( entries, MENU_ITEMS_ENTRY, &items )){
+		na_object_menu_set_items_list( menu, items );
+		na_utils_free_string_list( items );
+	}
+}
+
+/*
+ * set the properties into the NAObjectItem
+ */
+static void
+read_object_item_properties( NAGConfProvider *provider, GSList *entries, NAObjectItem *item )
+{
+	static const gchar *thisfn = "na_gconf_provider_read_object_item_properties";
+	gchar *id, *label, *tooltip, *icon;
+	gboolean enabled;
+
+	if( !na_gconf_utils_get_string_from_entries( entries, OBJECT_ITEM_LABEL_ENTRY, &label )){
+		id = na_object_get_id( item );
+		g_warning( "%s: no label found for NAObjectItem %s", thisfn, id );
+		g_free( id );
+		label = g_strdup( "" );
+	}
+	na_object_set_label( item, label );
+	g_free( label );
+
+	if( na_gconf_utils_get_string_from_entries( entries, OBJECT_ITEM_TOOLTIP_ENTRY, &tooltip )){
+		na_object_set_tooltip( item, tooltip );
+		g_free( tooltip );
+	}
+
+	if( na_gconf_utils_get_string_from_entries( entries, OBJECT_ITEM_ICON_ENTRY, &icon )){
+		na_object_set_icon( item, icon );
+		g_free( icon );
+	}
+
+	if( na_gconf_utils_get_bool_from_entries( entries, OBJECT_ITEM_ENABLED_ENTRY, &enabled )){
+		na_object_set_enabled( item, enabled );
+	}
+}
+
+static gboolean
+iio_provider_is_willing_to_write( const NAIIOProvider *provider )
+{
+	g_return_val_if_fail( NA_IS_GCONF_PROVIDER( provider ), FALSE );
+	g_return_val_if_fail( NA_IS_IIO_PROVIDER( provider ), FALSE );
+	g_return_val_if_fail( !NA_GCONF_PROVIDER( provider )->private->dispose_has_run, FALSE );
+
+	/* TODO: na_gconf_provider_iio_provider_is_willing_to_write */
+	return( TRUE );
+}
+
+static gboolean
+iio_provider_is_writable( const NAIIOProvider *provider, const NAObject *item )
+{
+	g_return_val_if_fail( NA_IS_GCONF_PROVIDER( provider ), FALSE );
+	g_return_val_if_fail( NA_IS_IIO_PROVIDER( provider ), FALSE );
+	g_return_val_if_fail( !NA_GCONF_PROVIDER( provider )->private->dispose_has_run, FALSE );
+	g_return_val_if_fail( NA_IS_OBJECT_ITEM( item ), FALSE );
+
+	/* TODO: na_gconf_provider_iio_provider_is_writable */
+	return( TRUE );
+}
+
+static guint
+iio_provider_write_item( const NAIIOProvider *provider, NAObject *item, gchar **message )
+{
+	static const gchar *thisfn = "na_gconf_provider_iio_provider_write_item";
+	NAGConfProvider *self;
+
+	g_debug( "%s: provider=%p, item=%p, message=%p",
+			thisfn, ( void * ) provider, ( void * ) item, ( void * ) message );
+
+	g_return_val_if_fail( NA_IS_GCONF_PROVIDER( provider ), NA_IIO_PROVIDER_PROGRAM_ERROR );
+	g_return_val_if_fail( NA_IS_IIO_PROVIDER( provider ), NA_IIO_PROVIDER_PROGRAM_ERROR );
+	g_return_val_if_fail( !NA_GCONF_PROVIDER( provider )->private->dispose_has_run, NA_IIO_PROVIDER_PROGRAM_ERROR );
+	g_return_val_if_fail( NA_IS_OBJECT_ITEM( item ), NA_IIO_PROVIDER_PROGRAM_ERROR );
+
+	self = NA_GCONF_PROVIDER( provider );
+	message = NULL;
+
+	if( NA_IS_OBJECT_ACTION( item )){
+		if( !write_item_action( self, NA_OBJECT_ACTION( item ), message )){
+			return( NA_IIO_PROVIDER_WRITE_ERROR );
+		}
+	}
+
+	if( NA_IS_OBJECT_MENU( item )){
+		if( !write_item_menu( self, NA_OBJECT_MENU( item ), message )){
+			return( NA_IIO_PROVIDER_WRITE_ERROR );
+		}
+	}
+
+	gconf_client_suggest_sync( self->private->gconf, NULL );
+
+	na_object_set_provider( item, provider );
+
+	return( NA_IIO_PROVIDER_WRITE_OK );
+}
+
+static gboolean
+write_item_action( NAGConfProvider *provider, const NAObjectAction *action, gchar **message )
+{
+	gchar *uuid, *name;
+	gboolean ret;
+	GSList *profiles, *ip;
+	NAObjectProfile *profile;
+
+	if( !write_object_item( provider, NA_OBJECT_ITEM( action ), message )){
+		return( FALSE );
+	}
+
+	uuid = na_object_get_id( action );
+
+	ret = write_str( provider, uuid, NULL, ACTION_VERSION_ENTRY, na_object_action_get_version( action ), message );
+
+	profiles = na_object_get_items( action );
+
+	for( ip = profiles ; ip && ret ; ip = ip->next ){
+
+		profile = NA_OBJECT_PROFILE( ip->data );
+		name = na_object_get_id( profile );
+
+		ret =
+			write_str( provider, uuid, name, ACTION_PROFILE_LABEL_ENTRY, na_object_get_label( profile ), message ) &&
+			write_str( provider, uuid, name, ACTION_PATH_ENTRY, na_object_profile_get_path( profile ), message ) &&
+			write_str( provider, uuid, name, ACTION_PARAMETERS_ENTRY, na_object_profile_get_parameters( profile ), message ) &&
+			write_list( provider, uuid, name, ACTION_BASENAMES_ENTRY, na_object_profile_get_basenames( profile ), message ) &&
+			write_bool( provider, uuid, name, ACTION_MATCHCASE_ENTRY, na_object_profile_get_matchcase( profile ), message ) &&
+			write_list( provider, uuid, name, ACTION_MIMETYPES_ENTRY, na_object_profile_get_mimetypes( profile ), message ) &&
+			write_bool( provider, uuid, name, ACTION_ISFILE_ENTRY, na_object_profile_get_is_file( profile ), message ) &&
+			write_bool( provider, uuid, name, ACTION_ISDIR_ENTRY, na_object_profile_get_is_dir( profile ), message ) &&
+			write_bool( provider, uuid, name, ACTION_MULTIPLE_ENTRY, na_object_profile_get_multiple( profile ), message ) &&
+			write_list( provider, uuid, name, ACTION_SCHEMES_ENTRY, na_object_profile_get_schemes( profile ), message );
+
+		g_free( name );
+	}
+
+	na_object_free_items( profiles );
+	g_free( uuid );
+
+	return( ret );
+}
+
+static gboolean
+write_item_menu( NAGConfProvider *provider, const NAObjectMenu *menu, gchar **message )
+{
+	gchar *uuid;
+	gboolean ret;
+
+	if( !write_object_item( provider, NA_OBJECT_ITEM( menu ), message )){
+		return( FALSE );
+	}
+
+	uuid = na_object_get_id( NA_OBJECT( menu ));
+	ret = write_list( provider, uuid, NULL, MENU_ITEMS_ENTRY, na_object_menu_get_items_list( menu ), message );
+	g_free( uuid );
+
+	return( ret );
+}
+
+static gboolean
+write_object_item( NAGConfProvider *provider, const NAObjectItem *item, gchar **message )
+{
+	gchar *uuid;
+	gboolean ret;
+
+	uuid = na_object_get_id( NA_OBJECT( item ));
+
+	ret =
+		write_str( provider, uuid, NULL, OBJECT_ITEM_LABEL_ENTRY, na_object_get_label( NA_OBJECT( item )), message ) &&
+		write_str( provider, uuid, NULL, OBJECT_ITEM_TOOLTIP_ENTRY, na_object_get_tooltip( item ), message ) &&
+		write_str( provider, uuid, NULL, OBJECT_ITEM_ICON_ENTRY, na_object_get_icon( item ), message ) &&
+		write_bool( provider, uuid, NULL, OBJECT_ITEM_ENABLED_ENTRY, na_object_is_enabled( item ), message );
+
+	g_free( uuid );
+	return( ret );
+}
+
+/*
+ * also delete the schema which may be directly attached to this action
+ * cf. http://bugzilla.gnome.org/show_bug.cgi?id=325585
+ */
+static guint
+iio_provider_delete_item( const NAIIOProvider *provider, const NAObject *item, gchar **message )
+{
+	static const gchar *thisfn = "na_gconf_provider_iio_provider_delete_item";
+	NAGConfProvider *self;
+	guint ret;
+	gchar *uuid, *path;
+	GError *error = NULL;
+
+	g_debug( "%s: provider=%p, item=%p, message=%p",
+			thisfn, ( void * ) provider, ( void * ) item, ( void * ) message );
+
+	g_return_val_if_fail( NA_IS_IIO_PROVIDER( provider ), NA_IIO_PROVIDER_PROGRAM_ERROR );
+	g_return_val_if_fail( NA_IS_GCONF_PROVIDER( provider ), NA_IIO_PROVIDER_PROGRAM_ERROR );
+	g_return_val_if_fail( !NA_GCONF_PROVIDER( provider )->private->dispose_has_run, NA_IIO_PROVIDER_PROGRAM_ERROR );
+	g_return_val_if_fail( NA_IS_OBJECT_ITEM( item ), NA_IIO_PROVIDER_PROGRAM_ERROR );
+
+	self = NA_GCONF_PROVIDER( provider );
+
+	message = NULL;
+	ret = NA_IIO_PROVIDER_WRITE_OK;
+	uuid = na_object_get_id( NA_OBJECT( item ));
+
+	path = g_strdup_printf( "%s%s/%s", NAUTILUS_ACTIONS_GCONF_SCHEMASDIR, NA_GCONF_CONFIG_PATH, uuid );
+	gconf_client_recursive_unset( self->private->gconf, path, 0, &error );
+	if( error ){
+		g_warning( "%s: path=%s, error=%s", thisfn, path, error->message );
+		g_error_free( error );
+		error = NULL;
+	}
+	g_free( path );
+
+
+	path = g_strdup_printf( "%s/%s", NA_GCONF_CONFIG_PATH, uuid );
+	if( !gconf_client_recursive_unset( self->private->gconf, path, 0, &error )){
+		g_warning( "%s: path=%s, error=%s", thisfn, path, 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_free( path );
+
+	g_free( uuid );
+
+	return( ret );
+}
+
+/*
+ * gconf_client_key_is_writable doesn't work as I expect: it returns
+ * FALSE without error for our keys !
+ * So I have to actually try a fake write to the key to get the real
+ * writability status...
+ *
+ * TODO: having a NAPivot as Nautilus extension and another NAPivot in
+ * the UI leads to a sort of notification loop: extension's pivot is
+ * not aware of UI's one, and so get notifications from GConf, reloads
+ * the list of actions, retrying to test the writability.
+ * In the meanwhile, UI's pivot has reauthorized notifications, and is
+ * notified of extension's pivot tests, and so on......
+ *
+ * -> Nautilus extension's pivot should not test for writability, as it
+ *    uses actions as read-only, reloading the whole list when one
+ *    action is modified ; this can break the loop
+ *
+ * -> the UI may use the pivot inside of Nautilus extension via a sort
+ *    of API, falling back to its own pivot, when the extension is not
+ *    present.
+ */
+static gboolean
+key_is_writable( NAGConfProvider *gconf, const gchar *path )
+{
+	/*static const gchar *thisfn = "na_gconf_provider_key_is_writable";
+	GError *error = NULL;
+
+	remove_gconf_watched_dir( gconf );
+
+	gboolean ret_gconf = gconf_client_key_is_writable( gconf->private->gconf, path, &error );
+	if( error ){
+		g_warning( "%s: gconf_client_key_is_writable: %s", thisfn, error->message );
+		g_error_free( error );
+		error = NULL;
+	}
+	gboolean ret_try = FALSE;
+	gchar *path_try = g_strdup_printf( "%s/%s", path, "fake_key" );
+	ret_try = gconf_client_set_string( gconf->private->gconf, path_try, "fake_value", &error );
+	if( error ){
+		g_warning( "%s: gconf_client_set_string: %s", thisfn, error->message );
+		g_error_free( error );
+		error = NULL;
+	}
+	if( ret_try ){
+		gconf_client_unset( gconf->private->gconf, path_try, NULL );
+	}
+	g_free( path_try );
+	g_debug( "%s: ret_gconf=%s, ret_try=%s", thisfn, ret_gconf ? "True":"False", ret_try ? "True":"False" );
+
+	install_gconf_watched_dir( gconf );
+	return( ret_try );*/
+
+	return( TRUE );
+}
+
+static gboolean
+write_str( NAGConfProvider *provider, const gchar *uuid, const gchar *name, const gchar *key, gchar *value, gchar **message )
+{
+	gchar *path;
+	gboolean ret;
+
+	if( name && strlen( name )){
+		path = g_strdup_printf( "%s/%s/%s/%s", NA_GCONF_CONFIG_PATH, uuid, name, key );
+	} else {
+		path = g_strdup_printf( "%s/%s/%s", NA_GCONF_CONFIG_PATH, uuid, key );
+	}
+
+	ret = na_gconf_utils_write_string( provider->private->gconf, path, value, message );
+
+	g_free( value );
+	g_free( path );
+
+	return( ret );
+}
+
+static gboolean
+write_bool( NAGConfProvider *provider, const gchar *uuid, const gchar *name, const gchar *key, gboolean value, gchar **message )
+{
+	gboolean ret;
+	gchar *path;
+
+	if( name && strlen( name )){
+		path = g_strdup_printf( "%s/%s/%s/%s", NA_GCONF_CONFIG_PATH, uuid, name, key );
+	} else {
+		path = g_strdup_printf( "%s/%s/%s", NA_GCONF_CONFIG_PATH, uuid, key );
+	}
+
+	ret = na_gconf_utils_write_bool( provider->private->gconf, path, value, message );
+
+	g_free( path );
+
+	return( ret );
+}
+
+static gboolean
+write_list( NAGConfProvider *provider, const gchar *uuid, const gchar *name, const gchar *key, GSList *value, gchar **message )
+{
+	gboolean ret;
+	gchar *path;
+
+	if( name && strlen( name )){
+		path = g_strdup_printf( "%s/%s/%s/%s", NA_GCONF_CONFIG_PATH, uuid, name, key );
+	} else {
+		path = g_strdup_printf( "%s/%s/%s", NA_GCONF_CONFIG_PATH, uuid, key );
+	}
+
+	ret = na_gconf_utils_write_string_list( provider->private->gconf, path, value, message );
+
+	na_utils_free_string_list( value );
+	g_free( path );
+
+	return( ret );
+}
diff --git a/src/common/na-gconf-provider.h b/src/common/na-gconf-provider.h
new file mode 100644
index 0000000..78f7adf
--- /dev/null
+++ b/src/common/na-gconf-provider.h
@@ -0,0 +1,81 @@
+/*
+ * 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_GCONF_PROVIDER_H__
+#define __NA_GCONF_PROVIDER_H__
+
+/**
+ * SECTION: na_gconf_provider_provider
+ * @short_description: #NAGConfProviderProvider class definition.
+ * @include: common/na-gconf-provider.h
+ *
+ * This class manages the GConf I/O storage subsystem, or, in other words,
+ * the GConf subsystem as an NAIIOProvider. As this, it should only be
+ * used through the NAIIOProvider interface.
+ *
+ * #NAGConfProviderProvider monitors the configuration tree. When something is
+ * modified, it sends the appropriate signal to the #NAPivot object it
+ * was created against.
+ */
+
+#include "na-pivot.h"
+
+G_BEGIN_DECLS
+
+#define NA_GCONF_PROVIDER_TYPE					( na_gconf_provider_get_type())
+#define NA_GCONF_PROVIDER( object )				( G_TYPE_CHECK_INSTANCE_CAST( object, NA_GCONF_PROVIDER_TYPE, NAGConfProvider ))
+#define NA_GCONF_PROVIDER_CLASS( klass )		( G_TYPE_CHECK_CLASS_CAST( klass, NA_GCONF_PROVIDER_TYPE, NAGConfProviderClass ))
+#define NA_IS_GCONF_PROVIDER( object )			( G_TYPE_CHECK_INSTANCE_TYPE( object, NA_GCONF_PROVIDER_TYPE ))
+#define NA_IS_GCONF_PROVIDER_CLASS( klass )		( G_TYPE_CHECK_CLASS_TYPE(( klass ), NA_GCONF_PROVIDER_TYPE ))
+#define NA_GCONF_PROVIDER_GET_CLASS( object )	( G_TYPE_INSTANCE_GET_CLASS(( object ), NA_GCONF_PROVIDER_TYPE, NAGConfProviderClass ))
+
+typedef struct NAGConfProviderPrivate NAGConfProviderPrivate;
+
+typedef struct {
+	GObject                 parent;
+	NAGConfProviderPrivate *private;
+}
+	NAGConfProvider;
+
+typedef struct NAGConfProviderClassPrivate NAGConfProviderClassPrivate;
+
+typedef struct {
+	GObjectClass                 parent;
+	NAGConfProviderClassPrivate *private;
+}
+	NAGConfProviderClass;
+
+GType            na_gconf_provider_get_type( void );
+
+NAGConfProvider *na_gconf_provider_new( NAPivot *notified );
+
+G_END_DECLS
+
+#endif /* __NA_GCONF_PROVIDER_PROVIDER_H__ */
diff --git a/src/common/na-gconf-utils.c b/src/common/na-gconf-utils.c
new file mode 100644
index 0000000..0befb23
--- /dev/null
+++ b/src/common/na-gconf-utils.c
@@ -0,0 +1,368 @@
+/*
+ * 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 <string.h>
+
+#include "na-utils.h"
+#include "na-gconf-utils.h"
+
+/*
+ * load the keys which are the subdirs of the given path
+ * returns a list of keys as full path
+ */
+GSList *
+na_gconf_utils_get_subdirs( GConfClient *gconf, const gchar *path )
+{
+	static const gchar *thisfn = "na_gconf_utils_get_subdirs";
+	GError *error = NULL;
+	GSList *list_subdirs;
+
+	list_subdirs = gconf_client_all_dirs( 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_subdirs );
+}
+
+void
+na_gconf_utils_free_subdirs( GSList *subdirs )
+{
+	na_utils_free_string_list( subdirs );
+}
+
+gboolean
+na_gconf_utils_have_subdir( GConfClient *gconf, const gchar *path )
+{
+	GSList *listpath;
+	gboolean have_subdir;
+
+	listpath = na_gconf_utils_get_subdirs( gconf, path );
+	have_subdir = ( listpath && g_slist_length( listpath ));
+	na_gconf_utils_free_subdirs( listpath );
+
+	return( have_subdir );
+}
+
+/*
+ * 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 na_gconf_utils_free_entries().
+ */
+GSList *
+na_gconf_utils_get_entries( GConfClient *gconf, const gchar *path )
+{
+	static const gchar *thisfn = "na_gconf_utils_get_entries";
+	GError *error = NULL;
+	GSList *list_entries;
+
+	list_entries = gconf_client_all_entries( 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_entries );
+}
+
+void
+na_gconf_utils_free_entries( GSList *list )
+{
+	g_slist_foreach( list, ( GFunc ) gconf_entry_unref, NULL );
+	g_slist_free( list );
+}
+
+gboolean
+na_gconf_utils_have_entry( GConfClient *gconf, const gchar *path, const gchar *entry )
+{
+	static const gchar *thisfn = "na_gconf_utils_have_entry";
+	gboolean have_entry = FALSE;
+	GError *error = NULL;
+	gchar *key;
+	GConfValue *value;
+
+	key = g_strdup_printf( "%s/%s", path, entry );
+
+	value = gconf_client_get_without_default( gconf, key, &error );
+
+	if( error ){
+		g_warning( "%s: key=%s, error=%s", thisfn, key, error->message );
+		g_error_free( error );
+		if( value ){
+			gconf_value_free( value );
+			value = NULL;
+		}
+	}
+
+	if( value ){
+		have_entry = TRUE;
+		gconf_value_free( value );
+	}
+
+	g_free( key );
+
+	return( have_entry );
+}
+
+gboolean
+na_gconf_utils_get_bool_from_entries( GSList *entries, const gchar *entry, gboolean *value )
+{
+	GSList *ip;
+	GConfEntry *gconf_entry;
+	GConfValue *gconf_value;
+	gchar *key;
+	gboolean found;
+
+	g_return_val_if_fail( value, FALSE );
+
+	*value = FALSE;
+	found = FALSE;
+
+	for( ip = entries ; ip && !found ; ip = ip->next ){
+		gconf_entry = ( GConfEntry * ) ip->data;
+		key = na_gconf_utils_path_to_key( gconf_entry_get_key( gconf_entry ));
+
+		if( !strcmp( key, entry )){
+			gconf_value = gconf_entry_get_value( gconf_entry );
+
+			if( gconf_value &&
+				gconf_value->type == GCONF_VALUE_BOOL ){
+
+					found = TRUE;
+					*value = gconf_value_get_bool( gconf_value );
+			}
+		}
+		g_free( key );
+	}
+
+	return( found );
+}
+
+gboolean
+na_gconf_utils_get_string_from_entries( GSList *entries, const gchar *entry, gchar **value )
+{
+	GSList *ip;
+	GConfEntry *gconf_entry;
+	GConfValue *gconf_value;
+	gchar *key;
+	gboolean found;
+
+	g_return_val_if_fail( value, FALSE );
+
+	*value = NULL;
+	found = FALSE;
+
+	for( ip = entries ; ip && !found ; ip = ip->next ){
+		gconf_entry = ( GConfEntry * ) ip->data;
+		key = na_gconf_utils_path_to_key( gconf_entry_get_key( gconf_entry ));
+
+		if( !strcmp( key, entry )){
+			gconf_value = gconf_entry_get_value( gconf_entry );
+
+			if( gconf_value &&
+				gconf_value->type == GCONF_VALUE_STRING ){
+
+					found = TRUE;
+					*value = g_strdup( gconf_value_get_string( gconf_value ));
+			}
+		}
+		g_free( key );
+	}
+
+	return( found );
+}
+
+gboolean
+na_gconf_utils_get_string_list_from_entries( GSList *entries, const gchar *entry, GSList **value )
+{
+	GSList *ip, *iv;
+	GConfEntry *gconf_entry;
+	GConfValue *gconf_value;
+	gchar *key;
+	gboolean found;
+	GSList *list_values;
+
+	g_return_val_if_fail( value, FALSE );
+
+	*value = NULL;
+	found = FALSE;
+
+	for( ip = entries ; ip && !found ; ip = ip->next ){
+		gconf_entry = ( GConfEntry * ) ip->data;
+		key = na_gconf_utils_path_to_key( gconf_entry_get_key( gconf_entry ));
+
+		if( !strcmp( key, entry )){
+			gconf_value = gconf_entry_get_value( gconf_entry );
+
+			if( gconf_value &&
+				gconf_value->type == GCONF_VALUE_LIST ){
+
+					found = TRUE;
+					list_values = gconf_value_get_list( gconf_value );
+					for( iv = list_values ; iv ; iv = iv->next ){
+						*value = g_slist_append( *value, g_strdup( gconf_value_get_string(( GConfValue * ) iv->data )));
+					}
+			}
+		}
+		g_free( key );
+	}
+
+	return( found );
+}
+
+gchar *
+na_gconf_utils_path_to_key( const gchar *path )
+{
+	return( na_utils_path_extract_last_dir( path ));
+}
+
+gboolean
+na_gconf_utils_read_bool( GConfClient *gconf, const gchar *path, gboolean use_schema, gboolean default_value )
+{
+	static const gchar *thisfn = "na_gconf_utils_read_bool";
+	GError *error = NULL;
+	GConfValue *value = NULL;
+	gboolean ret;
+
+	ret = default_value;
+
+	if( use_schema ){
+		ret = gconf_client_get_bool( gconf, path, &error );
+	} else {
+		value = gconf_client_get_without_default( gconf, path, &error );
+	}
+
+	if( error ){
+		g_warning( "%s: path=%s, error=%s", thisfn, path, error->message );
+		g_error_free( error );
+		if( value ){
+			gconf_value_free( value );
+			value = NULL;
+		}
+	}
+
+	if( value ){
+		ret = gconf_value_get_bool( value );
+		gconf_value_free( value );
+	}
+
+	return( ret );
+}
+
+/**
+ * Returns: a list of strings.
+ *
+ * The returned list must be released with na_utils_free_string_list().
+ */
+GSList *
+na_gconf_utils_read_string_list( GConfClient *gconf, const gchar *path )
+{
+	static const gchar *thisfn = "na_gconf_utils_read_string_list";
+	GError *error = NULL;
+	GSList *list_strings;
+
+	list_strings = gconf_client_get_list( gconf, path, GCONF_VALUE_STRING, &error );
+
+	if( error ){
+		g_warning( "%s: path=%s, error=%s", thisfn, path, error->message );
+		g_error_free( error );
+		return( NULL );
+	}
+
+	return( list_strings );
+}
+
+gboolean
+na_gconf_utils_write_bool( GConfClient *gconf, const gchar *path, gboolean value, gchar **message )
+{
+	static const gchar *thisfn = "na_gconf_utils_write_bool";
+	gboolean ret = TRUE;
+	GError *error = NULL;
+
+	if( !gconf_client_set_bool( gconf, path, value, &error )){
+		if( message ){
+			*message = g_strdup( error->message );
+		}
+		g_warning( "%s: path=%s, value=%s, error=%s", thisfn, path, value ? "True":"False", error->message );
+		g_error_free( error );
+		ret = FALSE;
+	}
+
+	return( ret );
+}
+
+gboolean
+na_gconf_utils_write_string( GConfClient *gconf, const gchar *path, const gchar *value, gchar **message )
+{
+	static const gchar *thisfn = "na_gconf_utils_write_string";
+	gboolean ret = TRUE;
+	GError *error = NULL;
+
+	if( !gconf_client_set_string( gconf, path, value, &error )){
+		if( message ){
+			*message = g_strdup( error->message );
+		}
+		g_warning( "%s: path=%s, value=%s, error=%s", thisfn, path, value ? "True":"False", error->message );
+		g_error_free( error );
+		ret = FALSE;
+	}
+
+	return( ret );
+}
+
+gboolean
+na_gconf_utils_write_string_list( GConfClient *gconf, const gchar *path, GSList *value, gchar **message )
+{
+	static const gchar *thisfn = "na_gconf_utils_write_string_list";
+	gboolean ret = TRUE;
+	GError *error = NULL;
+
+	if( !gconf_client_set_list( gconf, path, GCONF_VALUE_STRING, value, &error )){
+		if( message ){
+			*message = g_strdup( error->message );
+		}
+		g_warning( "%s: path=%s, value=%s, error=%s", thisfn, path, value ? "True":"False", error->message );
+		g_error_free( error );
+		ret = FALSE;
+	}
+
+	return( ret );
+}
diff --git a/src/common/na-gconf-utils.h b/src/common/na-gconf-utils.h
new file mode 100644
index 0000000..07602cf
--- /dev/null
+++ b/src/common/na-gconf-utils.h
@@ -0,0 +1,65 @@
+/*
+ * 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_GCONF_UTILS_H__
+#define __NA_GCONF_UTILS_H__
+
+/**
+ * SECTION: na_gconf_utils
+ * @short_description: GConf utilities.
+ * @include: common/na-gconf-utils.h
+ */
+
+#include <gconf/gconf.h>
+#include <gconf/gconf-client.h>
+
+GSList  *na_gconf_utils_get_subdirs( GConfClient *gconf, const gchar *path );
+void     na_gconf_utils_free_subdirs( GSList *subdirs );
+gboolean na_gconf_utils_have_subdir( GConfClient *gconf, const gchar *path );
+
+GSList  *na_gconf_utils_get_entries( GConfClient *gconf, const gchar *path );
+void     na_gconf_utils_free_entries( GSList *entries );
+gboolean na_gconf_utils_have_entry( GConfClient *gconf, const gchar *path, const gchar *entry );
+gboolean na_gconf_utils_get_bool_from_entries( GSList *entries, const gchar *entry, gboolean *value );
+gboolean na_gconf_utils_get_string_from_entries( GSList *entries, const gchar *entry, gchar **value );
+gboolean na_gconf_utils_get_string_list_from_entries( GSList *entries, const gchar *entry, GSList **value );
+
+gchar   *na_gconf_utils_path_to_key( const gchar *path );
+
+gboolean na_gconf_utils_read_bool( GConfClient *gconf, const gchar *path, gboolean use_schema, gboolean default_value );
+GSList  *na_gconf_utils_read_string_list( GConfClient *gconf, const gchar *path );
+
+gboolean na_gconf_utils_write_bool( GConfClient *gconf, const gchar *path, gboolean value, gchar **message );
+gboolean na_gconf_utils_write_string( GConfClient *gconf, const gchar *path, const gchar *value, gchar **message );
+gboolean na_gconf_utils_write_string_list( GConfClient *gconf, const gchar *path, GSList *value, gchar **message );
+
+G_END_DECLS
+
+#endif /* __NA_GCONF_UTILS_H__ */
diff --git a/src/common/na-iduplicable.c b/src/common/na-iduplicable.c
index d443940..8e6d9c6 100644
--- a/src/common/na-iduplicable.c
+++ b/src/common/na-iduplicable.c
@@ -42,24 +42,27 @@ struct NAIDuplicableInterfacePrivate {
 
 /* data set against NAIDuplicable-implementated instance
  */
-#define PROP_IDUPLICABLE_ORIGIN			"na-iduplicable-origin"
-#define PROP_IDUPLICABLE_ISMODIFIED		"na-iduplicable-is-modified"
-#define PROP_IDUPLICABLE_ISVALID		"na-iduplicable-is-valid"
+#define NA_IDUPLICABLE_PROP_ORIGIN			"na-iduplicable-origin"
+#define NA_IDUPLICABLE_PROP_IS_MODIFIED		"na-iduplicable-is-modified"
+#define NA_IDUPLICABLE_PROP_IS_VALID		"na-iduplicable-is-valid"
+
+static gboolean st_initialized = FALSE;
+static gboolean st_finalized = FALSE ;
 
 static GType          register_type( void );
 static void           interface_base_init( NAIDuplicableInterface *klass );
 static void           interface_base_finalize( NAIDuplicableInterface *klass );
 
-static void           v_copy( NAIDuplicable *target, const NAIDuplicable *source );
 static NAIDuplicable *v_new( const NAIDuplicable *object );
+static void           v_copy( NAIDuplicable *target, const NAIDuplicable *source );
 static gboolean       v_are_equal( const NAIDuplicable *a, const NAIDuplicable *b );
 static gboolean       v_is_valid( const NAIDuplicable *object );
 
-static NAIDuplicable *get_origin( const NAIDuplicable *object );
-static void           set_origin( const NAIDuplicable *object, const NAIDuplicable *origin );
 static gboolean       get_modified( const NAIDuplicable *object );
-static void           set_modified( const NAIDuplicable *object, gboolean is_modified );
+static NAIDuplicable *get_origin( const NAIDuplicable *object );
 static gboolean       get_valid( const NAIDuplicable *object );
+static void           set_modified( const NAIDuplicable *object, gboolean is_modified );
+static void           set_origin( const NAIDuplicable *object, const NAIDuplicable *origin );
 static void           set_valid( const NAIDuplicable *object, gboolean is_valid );
 
 GType
@@ -105,14 +108,14 @@ static void
 interface_base_init( NAIDuplicableInterface *klass )
 {
 	static const gchar *thisfn = "na_iduplicable_interface_base_init";
-	static gboolean initialized = FALSE;
 
-	if( !initialized ){
+	if( !st_initialized ){
+
 		g_debug( "%s: klass=%p", thisfn, ( void * ) klass );
 
 		klass->private = g_new0( NAIDuplicableInterfacePrivate, 1 );
 
-		initialized = TRUE;
+		st_initialized = TRUE;
 	}
 }
 
@@ -120,14 +123,14 @@ static void
 interface_base_finalize( NAIDuplicableInterface *klass )
 {
 	static const gchar *thisfn = "na_iduplicable_interface_base_finalize";
-	static gboolean finalized = FALSE ;
 
-	if( !finalized ){
+	if( !st_finalized ){
+
+		st_finalized = TRUE;
+
 		g_debug( "%s: klass=%p", thisfn, ( void * ) klass );
 
 		g_free( klass->private );
-
-		finalized = TRUE;
 	}
 }
 
@@ -137,14 +140,14 @@ interface_base_finalize( NAIDuplicableInterface *klass )
  *
  * Initializes the properties of a IDuplicable object.
  *
- * This function should be called by the implementor when creating the
- * object, e.g. from instance_init().
+ * This function should be called by the implementation when creating
+ * the object, e.g. from instance_init().
  */
 void
 na_iduplicable_init( NAIDuplicable *object )
 {
-	g_assert( G_IS_OBJECT( object ));
-	g_assert( NA_IS_IDUPLICABLE( object ));
+	g_return_if_fail( st_initialized && !st_finalized );
+	g_return_if_fail( NA_IS_IDUPLICABLE( object ));
 
 	set_origin( object, NULL );
 	set_modified( object, FALSE );
@@ -159,23 +162,24 @@ na_iduplicable_init( NAIDuplicable *object )
  *
  * We ouput here only the data we set ourselves againt the
  * #NAIDuplicable-implemented object.
+ *
+ * This function should be called by the implementation when it dumps
+ * itself its own content.
  */
 void
 na_iduplicable_dump( const NAIDuplicable *object )
 {
 	static const gchar *thisfn = "na_iduplicable_dump";
-	NAIDuplicable *origin = NULL;
-	gboolean modified = FALSE;
-	gboolean valid = FALSE;				/* may a NULL object be valid ? */
+	NAIDuplicable *origin;
+	gboolean modified;
+	gboolean valid;
 
-	if( object ){
-		g_assert( G_IS_OBJECT( object ));
-		g_assert( NA_IS_IDUPLICABLE( object ));
+	g_return_if_fail( st_initialized && !st_finalized );
+	g_return_if_fail( NA_IS_IDUPLICABLE( object ));
 
-		origin = get_origin( object );
-		modified = get_modified( object );
-		valid = get_valid( object );
-	}
+	origin = get_origin( object );
+	modified = get_modified( object );
+	valid = get_valid( object );
 
 	g_debug( "%s:   origin=%p", thisfn, ( void * ) origin );
 	g_debug( "%s: modified=%s", thisfn, modified ? "True" : "False" );
@@ -187,7 +191,7 @@ na_iduplicable_dump( const NAIDuplicable *object )
  * @object: the #NAIDuplicable object to be duplicated.
  *
  * Exactly duplicates a #NAIDuplicable-implemented object.
- * Properties %PROP_IDUPLICABLE_ORIGIN, %PROP_IDUPLICABLE_ISMODIFIED
+ * Properties %NA_IDUPLICABLE_PROP_ORIGIN, %PROP_IDUPLICABLE_ISMODIFIED
  * and %PROP_IDUPLICABLE_ISVALID are initialized to their default
  * values.
  *
@@ -199,30 +203,28 @@ na_iduplicable_dump( const NAIDuplicable *object )
 NAIDuplicable *
 na_iduplicable_duplicate( const NAIDuplicable *object )
 {
-	static const gchar *thisfn = "na_iduplicable_duplicate";
+	/*static const gchar *thisfn = "na_iduplicable_duplicate";*/
 	NAIDuplicable *dup = NULL;
 
-	g_debug( "%s: object=%p", thisfn, ( void * ) object );
+	/*g_debug( "%s: object=%p", thisfn, ( void * ) object );*/
 
-	if( object ){
-		g_assert( G_IS_OBJECT( object ));
-		g_assert( NA_IS_IDUPLICABLE( object ));
+	g_return_val_if_fail( st_initialized && !st_finalized, NULL );
+	g_return_val_if_fail( NA_IS_IDUPLICABLE( object ), NULL );
 
-		dup = v_new( object );
+	dup = v_new( object );
 
-		if( dup ){
-			v_copy( dup, object );
-			set_origin( dup, object );
-			set_modified( dup, FALSE );
-			set_valid( dup, TRUE );
-		}
+	if( dup ){
+		v_copy( dup, object );
+		set_origin( dup, object );
+		set_modified( dup, FALSE );
+		set_valid( dup, TRUE );
 	}
 
 	return( dup );
 }
 
 /**
- * na_iduplicable_check_edited_status:
+ * na_iduplicable_check_edition_status:
  * @object: the #NAIDuplicable object to be checked.
  *
  * Checks the edition status of the #NAIDuplicable object, and set up
@@ -235,27 +237,25 @@ na_iduplicable_duplicate( const NAIDuplicable *object )
  * then only return the current value of the properties.
  */
 void
-na_iduplicable_check_edited_status( const NAIDuplicable *object )
+na_iduplicable_check_edition_status( const NAIDuplicable *object )
 {
-	/*static const gchar *thisfn = "na_iduplicable_check_edited_status";
+	/*static const gchar *thisfn = "na_iduplicable_check_edition_status";
 	g_debug( "%s: object=%p", thisfn, object );*/
 	gboolean modified = TRUE;
 	NAIDuplicable *origin;
 	gboolean valid;
 
-	if( object ){
-		g_assert( G_IS_OBJECT( object ));
-		g_assert( NA_IS_IDUPLICABLE( object ));
+	g_return_if_fail( st_initialized && !st_finalized );
+	g_return_if_fail( NA_IS_IDUPLICABLE( object ));
 
-		origin = get_origin( object );
-		if( origin ){
-			modified = !v_are_equal( object, origin );
-		}
-		set_modified( object, modified );
-
-		valid = v_is_valid( object );
-		set_valid( object, valid );
+	origin = get_origin( object );
+	if( origin ){
+		modified = !v_are_equal( object, origin );
 	}
+	set_modified( object, modified );
+
+	valid = v_is_valid( object );
+	set_valid( object, valid );
 }
 
 /**
@@ -275,12 +275,10 @@ na_iduplicable_is_modified( const NAIDuplicable *object )
 	g_debug( "%s: object=%p", thisfn, object );*/
 	gboolean is_modified = FALSE;
 
-	if( object ){
-		g_assert( G_IS_OBJECT( object ));
-		g_assert( NA_IS_IDUPLICABLE( object ));
+	g_return_val_if_fail( st_initialized && !st_finalized, FALSE );
+	g_return_val_if_fail( NA_IS_IDUPLICABLE( object ), FALSE );
 
-		is_modified = get_modified( object );
-	}
+	is_modified = get_modified( object );
 
 	return( is_modified );
 }
@@ -301,12 +299,10 @@ na_iduplicable_is_valid( const NAIDuplicable *object )
 	g_debug( "%s: object=%p", thisfn, object );*/
 	gboolean is_valid = FALSE;
 
-	if( object ){
-		g_assert( G_IS_OBJECT( object ));
-		g_assert( NA_IS_IDUPLICABLE( object ));
+	g_return_val_if_fail( st_initialized && !st_finalized, FALSE );
+	g_return_val_if_fail( NA_IS_IDUPLICABLE( object ), FALSE );
 
-		is_valid = get_valid( object );
-	}
+	is_valid = get_valid( object );
 
 	return( is_valid );
 }
@@ -326,19 +322,17 @@ na_iduplicable_get_origin( const NAIDuplicable *object )
 	g_debug( "%s: object=%p", thisfn, object );*/
 	NAIDuplicable *origin = NULL;
 
-	if( object ){
-		g_assert( G_IS_OBJECT( object ));
-		g_assert( NA_IS_IDUPLICABLE( object ));
+	g_return_val_if_fail( st_initialized && !st_finalized, NULL );
+	g_return_val_if_fail( NA_IS_IDUPLICABLE( object ), NULL );
 
-		origin = get_origin( object );
-	}
+	origin = get_origin( object );
 
 	return( origin );
 }
 
 /**
  * na_iduplicable_set_origin:
- * @object: the #NAIDuplicable object whose origin is to be returned.
+ * @object: the #NAIDuplicable object whose origin is to be set.
  * @origin: the new original #NAIDuplicable.
  *
  * Sets the new origin of a duplicated #NAIDuplicable.
@@ -349,20 +343,11 @@ na_iduplicable_set_origin( NAIDuplicable *object, const NAIDuplicable *origin )
 	/*static const gchar *thisfn = "na_iduplicable_is_valid";
 	g_debug( "%s: object=%p", thisfn, object );*/
 
-	if( object ){
-		g_assert( G_IS_OBJECT( object ));
-		g_assert( NA_IS_IDUPLICABLE( object ));
+	g_return_if_fail( st_initialized && !st_finalized );
+	g_return_if_fail( NA_IS_IDUPLICABLE( object ));
+	g_return_if_fail( NA_IS_IDUPLICABLE( origin ) || !origin );
 
-		set_origin( object, origin );
-	}
-}
-
-static void
-v_copy( NAIDuplicable *target, const NAIDuplicable *source )
-{
-	if( NA_IDUPLICABLE_GET_INTERFACE( target )->copy ){
-		NA_IDUPLICABLE_GET_INTERFACE( target )->copy( target, source );
-	}
+	set_origin( object, origin );
 }
 
 static NAIDuplicable *
@@ -375,6 +360,14 @@ v_new( const NAIDuplicable *object )
 	return( NULL );
 }
 
+static void
+v_copy( NAIDuplicable *target, const NAIDuplicable *source )
+{
+	if( NA_IDUPLICABLE_GET_INTERFACE( target )->copy ){
+		NA_IDUPLICABLE_GET_INTERFACE( target )->copy( target, source );
+	}
+}
+
 static gboolean
 v_are_equal( const NAIDuplicable *a, const NAIDuplicable *b )
 {
@@ -382,7 +375,7 @@ v_are_equal( const NAIDuplicable *a, const NAIDuplicable *b )
 		return( NA_IDUPLICABLE_GET_INTERFACE( a )->are_equal( a, b ));
 	}
 
-	return( TRUE );
+	return( FALSE );
 }
 
 static gboolean
@@ -392,41 +385,41 @@ v_is_valid( const NAIDuplicable *object )
 		return( NA_IDUPLICABLE_GET_INTERFACE( object )->is_valid( object ));
 	}
 
-	return( TRUE );
+	return( FALSE );
 }
 
-static NAIDuplicable *
-get_origin( const NAIDuplicable *object )
+static gboolean
+get_modified( const NAIDuplicable *object )
 {
-	return( NA_IDUPLICABLE( g_object_get_data( G_OBJECT( object ), PROP_IDUPLICABLE_ORIGIN )));
+	return(( gboolean ) GPOINTER_TO_UINT( g_object_get_data( G_OBJECT( object ), NA_IDUPLICABLE_PROP_IS_MODIFIED )));
 }
 
-static void
-set_origin( const NAIDuplicable *object, const NAIDuplicable *origin )
+static NAIDuplicable *
+get_origin( const NAIDuplicable *object )
 {
-	g_object_set_data( G_OBJECT( object ), PROP_IDUPLICABLE_ORIGIN, ( gpointer ) origin );
+	return( NA_IDUPLICABLE( g_object_get_data( G_OBJECT( object ), NA_IDUPLICABLE_PROP_ORIGIN )));
 }
 
 static gboolean
-get_modified( const NAIDuplicable *object )
+get_valid( const NAIDuplicable *object )
 {
-	return(( gboolean ) GPOINTER_TO_UINT( g_object_get_data( G_OBJECT( object ), PROP_IDUPLICABLE_ISMODIFIED )));
+	return(( gboolean ) GPOINTER_TO_UINT( g_object_get_data( G_OBJECT( object ), NA_IDUPLICABLE_PROP_IS_VALID )));
 }
 
 static void
 set_modified( const NAIDuplicable *object, gboolean is_modified )
 {
-	g_object_set_data( G_OBJECT( object ), PROP_IDUPLICABLE_ISMODIFIED, GUINT_TO_POINTER( is_modified ));
+	g_object_set_data( G_OBJECT( object ), NA_IDUPLICABLE_PROP_IS_MODIFIED, GUINT_TO_POINTER( is_modified ));
 }
 
-static gboolean
-get_valid( const NAIDuplicable *object )
+static void
+set_origin( const NAIDuplicable *object, const NAIDuplicable *origin )
 {
-	return(( gboolean ) GPOINTER_TO_UINT( g_object_get_data( G_OBJECT( object ), PROP_IDUPLICABLE_ISVALID )));
+	g_object_set_data( G_OBJECT( object ), NA_IDUPLICABLE_PROP_ORIGIN, ( gpointer ) origin );
 }
 
 static void
 set_valid( const NAIDuplicable *object, gboolean is_valid )
 {
-	g_object_set_data( G_OBJECT( object ), PROP_IDUPLICABLE_ISVALID, GUINT_TO_POINTER( is_valid ));
+	g_object_set_data( G_OBJECT( object ), NA_IDUPLICABLE_PROP_IS_VALID, GUINT_TO_POINTER( is_valid ));
 }
diff --git a/src/common/na-iduplicable.h b/src/common/na-iduplicable.h
index 65b7421..76fe5e7 100644
--- a/src/common/na-iduplicable.h
+++ b/src/common/na-iduplicable.h
@@ -28,21 +28,21 @@
  *   ... and many others (see AUTHORS)
  */
 
-#ifndef __NACT_IDUPLICABLE_H__
-#define __NACT_IDUPLICABLE_H__
+#ifndef __NA_IDUPLICABLE_H__
+#define __NA_IDUPLICABLE_H__
 
 /**
  * SECTION: na_iduplicable
- * @short_description: #NAObject IDuplicable interface.
+ * @short_description: #NAIDuplicable 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.
+ * then only checking edition status when explicitely required.
  *
  * As the reference count of the original object is not incremented
- * here, the caller has to garantee himself that the original object
+ * here, the caller has to garantee itself that the original object
  * will stay in life at least as long as the duplicated one.
  */
 
@@ -51,8 +51,8 @@
 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( instance )					( G_TYPE_CHECK_INSTANCE_CAST( instance, NA_IDUPLICABLE_TYPE, NAIDuplicable ))
+#define NA_IS_IDUPLICABLE( instance )				( G_TYPE_CHECK_INSTANCE_TYPE( instance, NA_IDUPLICABLE_TYPE ))
 #define NA_IDUPLICABLE_GET_INTERFACE( instance )	( G_TYPE_INSTANCE_GET_INTERFACE(( instance ), NA_IDUPLICABLE_TYPE, NAIDuplicableInterface ))
 
 typedef struct NAIDuplicable NAIDuplicable;
@@ -64,13 +64,18 @@ typedef struct {
 	NAIDuplicableInterfacePrivate *private;
 
 	/**
-	 * get_new_instance:
-	 * @nstance: a #NAIDuplicable instance of the klass of which we
+	 * new:
+	 * @object: a #NAIDuplicable instance of the class of which we
 	 * want a new instance.
 	 *
-	 * Returns a new instance of the same class.
-	 *
 	 * Returns: a newly allocated #NAIDuplicable object.
+	 *
+	 * The most derived class of the implementation should define this
+	 * virtual function in order to get advantage of #NAIDuplicable
+	 * interface.
+	 *
+	 * This let the target class to do some initialization on the newly
+	 * created object.
 	 */
 	NAIDuplicable * ( *new )      ( const NAIDuplicable *object );
 
@@ -81,6 +86,11 @@ typedef struct {
 	 *
 	 * Copies data from @source to @ŧarget, so that @target becomes an
 	 * exact copy of @source.
+	 *
+	 * Each derived class of the implementation should define this
+	 * function to copy its own data. The implementation should take
+	 * care itself of calling each function in the class hierarchy,
+	 * from topmost base class to most-derived one.
 	 */
 	void            ( *copy )     ( NAIDuplicable *target, const NAIDuplicable *source );
 
@@ -92,11 +102,12 @@ typedef struct {
 	 *
 	 * Compares the two objects.
 	 *
-	 * The implementor should define a are_equal()-equivalent virtual
-	 * function so that each #NAIDuplicable-derived class be able to
-	 * check for identity.
-	 *
 	 * Returns: %TRUE if @a and @b are identical, %FALSE else.
+	 *
+	 * Each derived class of the implementation should define this
+	 * function to compare its own data. The implementation should take
+	 * care itself of calling each function in the class hierarchy,
+	 * from topmost base class to most-derived one.
 	 */
 	gboolean        ( *are_equal )( const NAIDuplicable *a, const NAIDuplicable *b );
 
@@ -106,30 +117,28 @@ typedef struct {
 	 *
 	 * Checks @object for validity.
 	 *
-	 * The implementor should define a is_valid()-equivalent virtual
-	 * function so that each #NAIDuplicable-derived class be able to
-	 * check for validity.
-	 *
 	 * Returns: %TRUE if @object is valid, %FALSE else.
+	 *
+	 * Each derived class of the implementation should define this
+	 * function to compare its own data. The implementation should take
+	 * care itself of calling each function in the class hierarchy,
+	 * from topmost base class to most-derived one.
 	 */
-	gboolean        ( *is_valid ) ( const NAIDuplicable *object );
+	gboolean        ( *is_valid )   ( const NAIDuplicable *object );
 }
 	NAIDuplicableInterface;
 
 GType          na_iduplicable_get_type( void );
 
 void           na_iduplicable_init( NAIDuplicable *object );
-
 void           na_iduplicable_dump( const NAIDuplicable *object );
 
 NAIDuplicable *na_iduplicable_duplicate( const NAIDuplicable *object );
 
-void           na_iduplicable_check_edited_status( const NAIDuplicable *object );
+void           na_iduplicable_check_edition_status( const NAIDuplicable *object );
 
 gboolean       na_iduplicable_is_modified( const NAIDuplicable *object );
-
 gboolean       na_iduplicable_is_valid( const NAIDuplicable *object );
-
 NAIDuplicable *na_iduplicable_get_origin( const NAIDuplicable *object );
 
 void           na_iduplicable_set_origin( NAIDuplicable *object, const NAIDuplicable *origin );
diff --git a/src/common/na-iio-provider.c b/src/common/na-iio-provider.c
index 7f94f58..834c342 100644
--- a/src/common/na-iio-provider.c
+++ b/src/common/na-iio-provider.c
@@ -32,8 +32,12 @@
 #include <config.h>
 #endif
 
-#include "na-action.h"
+#include "na-object-api.h"
+#include "na-obj-action.h"
+#include "na-obj-menu.h"
 #include "na-iio-provider.h"
+#include "na-iprefs.h"
+#include "na-utils.h"
 
 /* private interface data
  */
@@ -41,14 +45,19 @@ struct NAIIOProviderInterfacePrivate {
 	void *empty;						/* so that gcc -pedantic is happy */
 };
 
+static gboolean st_initialized = FALSE;
+static gboolean st_finalized = FALSE;
+
 static GType    register_type( void );
 static void     interface_base_init( NAIIOProviderInterface *klass );
 static void     interface_base_finalize( NAIIOProviderInterface *klass );
 
+static GSList  *get_merged_items_list( const NAPivot *pivot, GSList *providers );
+static guint    try_write_item( const NAIIOProvider *instance, NAObject *item, gchar **message );
+
 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 );
-static gint     compare_actions_label_alpha_fn( const NAAction *a, const NAAction *b );
+static gboolean do_is_writable( const NAIIOProvider *instance, const NAObject *item );
+/*static gint     compare_actions_label_alpha_fn( const NAAction *a, const NAAction *b );*/
 
 /**
  * Registers the GType of this interface.
@@ -96,20 +105,19 @@ static void
 interface_base_init( NAIIOProviderInterface *klass )
 {
 	static const gchar *thisfn = "na_iio_provider_interface_base_init";
-	static gboolean initialized = FALSE;
 
-	if( !initialized ){
+	if( !st_initialized ){
 		g_debug( "%s: klass=%p", thisfn, ( void * ) klass );
 
 		klass->private = g_new0( NAIIOProviderInterfacePrivate, 1 );
 
-		klass->read_actions = NULL;
+		klass->read_items_list = NULL;
 		klass->is_willing_to_write = do_is_willing_to_write;
 		klass->is_writable = do_is_writable;
-		klass->write_action = NULL;
-		klass->delete_action = NULL;
+		klass->write_item = NULL;
+		klass->delete_item = NULL;
 
-		initialized = TRUE;
+		st_initialized = TRUE;
 	}
 }
 
@@ -117,63 +125,85 @@ static void
 interface_base_finalize( NAIIOProviderInterface *klass )
 {
 	static const gchar *thisfn = "na_iio_provider_interface_base_finalize";
-	static gboolean finalized = FALSE ;
 
-	if( !finalized ){
+	if( !st_finalized ){
+
+		st_finalized = TRUE;
+
 		g_debug( "%s: klass=%p", thisfn, ( void * ) klass );
 
 		g_free( klass->private );
-
-		finalized = TRUE;
 	}
 }
 
 /**
- * na_iio_provider_read_actions:
+ * na_iio_provider_get_items_tree:
  * @pivot: the #NAPivot object which owns the list of registered I/O
  * storage providers.
  *
- * Loads the actions from storage subsystems.
+ * Loads the tree from I/O storage subsystems.
  *
- * 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.
+ * Returns: a #GSList of newly allocated objects as a hierarchical tree
+ * in display order. This tree may contain #NAActionMenu menus and
+ * #NAAction actions and their #NAActionProfile profiles.
  */
 GSList *
-na_iio_provider_read_actions( const NAPivot *pivot )
+na_iio_provider_get_items_tree( const NAPivot *pivot )
 {
-	static const gchar *thisfn = "na_iio_provider_read_actions";
-	GSList *actions = NULL;
-	GSList *providers, *ip, *list, *ia;
-	NAIIOProvider *instance;
+	static const gchar *thisfn = "na_iio_provider_get_items_tree";
+	GSList *providers;
+	GSList *merged;
+	GSList *level_zero;
+	gboolean alpha_order;
 
 	g_debug( "%s: pivot=%p", thisfn, ( void * ) pivot );
-	g_assert( NA_IS_PIVOT( pivot ));
+
+	g_return_val_if_fail( st_initialized && !st_finalized, NULL );
+	g_return_val_if_fail( NA_IS_PIVOT( pivot ), NULL );
+	g_return_val_if_fail( NA_IS_IPREFS( pivot ), NULL );
 
 	providers = na_pivot_get_providers( pivot, NA_IIO_PROVIDER_TYPE );
+	merged = get_merged_items_list( pivot, providers );
+	na_pivot_free_providers( providers );
+
+	level_zero = na_iprefs_get_level_zero_items( NA_IPREFS( pivot ));
+	alpha_order = na_iprefs_is_alphabetical_order( NA_IPREFS( pivot ));
+
+	/*if( alpha_order ){
+		actions = na_iio_provider_sort_actions( pivot, actions );
+	}*/
+
+	na_utils_free_string_list( level_zero );
+
+	return( merged );
+}
+
+static GSList *
+get_merged_items_list( const NAPivot *pivot, GSList *providers )
+{
+	GSList *merged = NULL;
+	GSList *ip;
+	GSList *list, *item;
+	NAIIOProvider *instance;
 
 	for( ip = providers ; ip ; ip = ip->next ){
 
 		instance = NA_IIO_PROVIDER( ip->data );
-		if( NA_IIO_PROVIDER_GET_INTERFACE( instance )->read_actions ){
-
-			list = NA_IIO_PROVIDER_GET_INTERFACE( instance )->read_actions( instance );
+		if( NA_IIO_PROVIDER_GET_INTERFACE( instance )->read_items_list ){
 
-			for( ia = list ; ia ; ia = ia->next ){
+			list = NA_IIO_PROVIDER_GET_INTERFACE( instance )->read_items_list( instance );
 
-				na_action_set_provider( NA_ACTION( ia->data ), instance );
+			for( item = list ; item ; item = item->next ){
 
-				na_object_dump( NA_OBJECT( ia->data ));
+				na_object_set_provider( item->data, instance );
+				na_object_dump( item->data );
 			}
 
-			actions = g_slist_concat( actions, list );
+			merged = g_slist_concat( merged, list );
 		}
 	}
 
-	/* TODO: should be done only if prefs is set */
-	return( na_iio_provider_sort_actions( pivot, actions ));
+	return( merged );
 }
 
 /**
@@ -186,7 +216,7 @@ na_iio_provider_read_actions( const NAPivot *pivot )
  *
  * Returns: the sorted list.
  */
-GSList *
+/*GSList *
 na_iio_provider_sort_actions( const NAPivot *pivot, GSList *actions )
 {
 	GSList *sorted;
@@ -194,100 +224,138 @@ na_iio_provider_sort_actions( const NAPivot *pivot, GSList *actions )
 	sorted = g_slist_sort( actions, ( GCompareFunc ) compare_actions_label_alpha_fn );
 
 	return( sorted );
-}
+}*/
 
 /**
- * na_iio_provider_write_action:
+ * na_iio_provider_write_item:
  * @pivot: the #NAPivot object which owns the list of registered I/O
  * storage providers. if NULL, @action must already have registered
  * its own provider.
- * @action: the #NAAction action to be written.
+ * @item: a #NAObject to be written by the storage subsystem.
  * @message: the I/O provider can allocate and store here an error
  * message.
  *
- * Writes an action to a willing-to storage subsystem.
+ * Writes an @item to a willing-to storage subsystem.
  *
  * Returns: the NAIIOProvider return code.
  */
 guint
-na_iio_provider_write_action( const NAPivot *pivot, NAAction *action, gchar **message )
+na_iio_provider_write_item( const NAPivot *pivot, NAObject *item, gchar **message )
 {
-	static const gchar *thisfn = "na_iio_provider_write_action";
+	static const gchar *thisfn = "na_iio_provider_write_item";
 	guint ret;
 	NAIIOProvider *instance;
+	NAIIOProvider *bad_instance;
 	GSList *providers, *ip;
 
-	g_debug( "%s: pivot=%p, action=%p, message=%p",
-			thisfn, ( void * ) pivot, ( void * ) action, ( void * ) message );
-	g_assert( NA_IS_PIVOT( pivot ) || !pivot );
-	g_assert( NA_IS_ACTION( action ));
+	g_debug( "%s: pivot=%p, item=%p, message=%p",
+			thisfn, ( void * ) pivot, ( void * ) item, ( void * ) message );
+
+	g_return_val_if_fail( st_initialized && !st_finalized, NA_IIO_PROVIDER_PROGRAM_ERROR );
+	g_return_val_if_fail(( NA_IS_PIVOT( pivot ) || !pivot ), NA_IIO_PROVIDER_PROGRAM_ERROR );
+	g_return_val_if_fail( NA_IS_OBJECT_ITEM( item ), NA_IIO_PROVIDER_PROGRAM_ERROR );
 
 	ret = NA_IIO_PROVIDER_NOT_WRITABLE;
+	bad_instance = NULL;
 
-	/* try to write to the original provider of the action
+	/* try to write to the original provider of the item
 	 */
-	instance = NA_IIO_PROVIDER( na_action_get_provider( action ));
-
+	instance = NA_IIO_PROVIDER( na_object_get_provider( item ));
 	if( instance ){
-		ret = write_action( instance, action, message );
-	}
-
-	if( ret == NA_IIO_PROVIDER_NOT_WILLING_TO_WRITE || ret == NA_IIO_PROVIDER_NOT_WRITABLE ){
-		instance = NULL;
+		ret = try_write_item( instance, item, message );
+		if( ret == NA_IIO_PROVIDER_NOT_WILLING_TO_WRITE || ret == NA_IIO_PROVIDER_NOT_WRITABLE ){
+			bad_instance = instance;
+			instance = NULL;
+		}
 	}
 
-	/* else, search for a provider which is willing to write the action
+	/* else, search for a provider which is willing to write the item
 	 */
 	if( !instance && pivot ){
 		providers = na_pivot_get_providers( pivot, NA_IIO_PROVIDER_TYPE );
 		for( ip = providers ; ip ; ip = ip->next ){
 
 			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;
+			if( !bad_instance || bad_instance != instance ){
+				ret = try_write_item( instance, item, message );
+				if( ret == NA_IIO_PROVIDER_WRITE_OK ){
+					break;
+				}
 			}
 		}
+		na_pivot_free_providers( providers );
 	}
 
 	return( ret );
 }
 
+static guint
+try_write_item( const NAIIOProvider *provider, NAObject *item, gchar **message )
+{
+	static const gchar *thisfn = "na_iio_provider_try_write_item";
+	guint ret;
+
+	g_debug( "%s: provider=%p, item=%p, message=%p",
+			thisfn, ( void * ) provider, ( void * ) item, ( void * ) 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, item )){
+		return( NA_IIO_PROVIDER_NOT_WRITABLE );
+	}
+
+	if( !NA_IIO_PROVIDER_GET_INTERFACE( provider )->delete_item ||
+		!NA_IIO_PROVIDER_GET_INTERFACE( provider )->write_item ){
+		return( NA_IIO_PROVIDER_NOT_WILLING_TO_WRITE );
+	}
+
+	ret = NA_IIO_PROVIDER_GET_INTERFACE( provider )->delete_item( provider, item, message );
+	if( ret != NA_IIO_PROVIDER_WRITE_OK ){
+		return( ret );
+	}
+
+	return( NA_IIO_PROVIDER_GET_INTERFACE( provider )->write_item( provider, item, message ));
+}
+
 /**
- * na_iio_provider_delete_action:
+ * na_iio_provider_delete_item:
  * @pivot: the #NAPivot object which owns the list of registered I/O
  * storage providers.
- * @action: the #NAAction action to be written.
+ * @item: the #NAObject item to be deleted.
  * @message: the I/O provider can allocate and store here an error
  * message.
  *
- * Deletes an action from the storage subsystem.
+ * Deletes an item (action or menu) from the storage subsystem.
  *
  * Returns: the NAIIOProvider return code.
  *
- * Note that a new action, not already written to an I/O subsystem,
+ * Note that a new item, 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 NAPivot *pivot, const NAAction *action, gchar **message )
+na_iio_provider_delete_item( const NAPivot *pivot, const NAObject *item, gchar **message )
 {
-	static const gchar *thisfn = "na_iio_provider_delete_action";
+	static const gchar *thisfn = "na_iio_provider_delete_item";
 	guint ret;
 	NAIIOProvider *instance;
 
-	g_debug( "%s: pivot=%p, action=%p, message=%p",
-			thisfn, ( void * ) pivot, ( void * ) action, ( void * ) message );
-	g_assert( NA_IS_PIVOT( pivot ));
-	g_assert( NA_IS_ACTION( action ));
+	g_debug( "%s: pivot=%p, item=%p, message=%p",
+			thisfn, ( void * ) pivot, ( void * ) item, ( void * ) message );
+
+	g_return_val_if_fail( st_initialized && !st_finalized, NA_IIO_PROVIDER_PROGRAM_ERROR );
+	g_return_val_if_fail( NA_IS_PIVOT( pivot ), NA_IIO_PROVIDER_PROGRAM_ERROR );
+	g_return_val_if_fail( NA_IS_OBJECT_ITEM( item ), NA_IIO_PROVIDER_PROGRAM_ERROR );
 
 	ret = NA_IIO_PROVIDER_NOT_WRITABLE;
-	instance = NA_IIO_PROVIDER( na_action_get_provider( action ));
+	instance = NA_IIO_PROVIDER( na_object_get_provider( item ));
 
 	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, action, message );
+		if( NA_IIO_PROVIDER_GET_INTERFACE( instance )->delete_item ){
+			ret = NA_IIO_PROVIDER_GET_INTERFACE( instance )->delete_item( instance, item, message );
 		}
 	/*} else {
 		*message = g_strdup( _( "Unable to delete the action: no I/O provider." ));
@@ -304,42 +372,12 @@ do_is_willing_to_write( const NAIIOProvider *instance )
 }
 
 static gboolean
-do_is_writable( const NAIIOProvider *instance, const NAAction *action )
+do_is_writable( const NAIIOProvider *instance, const NAObject *item )
 {
 	return( FALSE );
 }
 
-static guint
-write_action( const NAIIOProvider *provider, NAAction *action, gchar **message )
-{
-	static const gchar *thisfn = "na_iio_provider_write_action";
-	guint ret;
-
-	g_debug( "%s: provider=%p, action=%p, message=%p",
-			thisfn, ( void * ) provider, ( void * ) action, ( void * ) 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 ||
-		!NA_IIO_PROVIDER_GET_INTERFACE( provider )->write_action ){
-		return( NA_IIO_PROVIDER_NOT_WILLING_TO_WRITE );
-	}
-
-	ret = NA_IIO_PROVIDER_GET_INTERFACE( provider )->delete_action( provider, action, message );
-	if( ret != NA_IIO_PROVIDER_WRITE_OK ){
-		return( ret );
-	}
-
-	return( NA_IIO_PROVIDER_GET_INTERFACE( provider )->write_action( provider, action, message ));
-}
-
-static gint
+/*static gint
 compare_actions_label_alpha_fn( const NAAction *a, const NAAction *b )
 {
 	gchar *label_a, *label_b;
@@ -351,4 +389,4 @@ compare_actions_label_alpha_fn( const NAAction *a, const NAAction *b )
 	compare = g_utf8_collate( label_a, label_b );
 
 	return( compare );
-}
+}*/
diff --git a/src/common/na-iio-provider.h b/src/common/na-iio-provider.h
index cfbaca5..3949dcf 100644
--- a/src/common/na-iio-provider.h
+++ b/src/common/na-iio-provider.h
@@ -44,8 +44,6 @@
  * startup time (e.g. on the model of provider interfaces in Nautilus).
  */
 
-#include <glib-object.h>
-
 #include "na-pivot.h"
 
 G_BEGIN_DECLS
@@ -64,14 +62,15 @@ typedef struct {
 	NAIIOProviderInterfacePrivate *private;
 
 	/**
-	 * read_actions:
+	 * read_tree:
 	 * @instance: the #NAIIOProvider provider.
 	 *
-	 * Reads actions from the specified I/O provider.
+	 * Reads the while items tree from the specified I/O provider.
 	 *
-	 * Returns: a #GSList of #NAAction actions.
+	 * Returns: a hierarchical #GSList of menus, actions and
+	 * profiles as #NAObject-derived objects.
 	 */
-	GSList * ( *read_actions )       ( const NAIIOProvider *instance );
+	GSList * ( *read_items_list )    ( const NAIIOProvider *instance );
 
 	/**
 	 * is_willing_to_write:
@@ -84,56 +83,56 @@ typedef struct {
 	 *
 	 * 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.
+	 * being able to update/write/delete a particular item.
 	 */
 	gboolean ( *is_willing_to_write )( const NAIIOProvider *instance );
 
 	/**
 	 * is_writable:
 	 * @instance: the #NAIIOProvider provider.
-	 * @action: a #NAAction action.
+	 * @item: a #NAObject action or menu.
 	 *
-	 * Checks for writability of this particular #NAAction.
+	 * Checks for writability of this particular @item.
 	 *
 	 * Returns: %TRUE if we are able to update/write/delete the
-	 * #NAAction, %FALSE else.
+	 * @item, %FALSE else.
 	 */
-	gboolean ( *is_writable )        ( const NAIIOProvider *instance, const NAAction *action );
+	gboolean ( *is_writable )        ( const NAIIOProvider *instance, const NAObject *item );
 
 	/**
-	 * write_action:
+	 * write_tree_item:
 	 * @instance: the #NAIIOProvider provider.
-	 * @action: a #NAAction action.
+	 * @item: a #NAObject to be written.
 	 * @message: warning/error messages detected in the operation.
 	 *
-	 * Updates an existing #NAAction or write a new #NAAction.
+	 * Updates an existing @item or writes a new one.
 	 *
 	 * 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 );
+	guint    ( *write_item )         ( const NAIIOProvider *instance, NAObject *item, gchar **message );
 
 	/**
-	 * delete_action:
+	 * delete_tree_item:
 	 * @instance: the #NAIIOProvider provider.
-	 * @action: a #NAAction action.
+	 * @item: a #NAObject to be deleted.
 	 * @message: warning/error messages detected in the operation.
 	 *
-	 * Deletes an existing #NAAction from the I/O subsystem.
+	 * Deletes an existing @item 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 );
+	guint    ( *delete_item )        ( const NAIIOProvider *instance, const NAObject *item, gchar **message );
 }
 	NAIIOProviderInterface;
 
 GType   na_iio_provider_get_type( void );
 
-GSList *na_iio_provider_read_actions( const NAPivot *pivot );
-GSList *na_iio_provider_sort_actions( const NAPivot *pivot, GSList *actions );
-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 );
+GSList *na_iio_provider_get_items_tree( const NAPivot *pivot );
+/*GSList *na_iio_provider_sort_tree( const NAPivot *pivot, GSList *tree );*/
+guint   na_iio_provider_write_item( const NAPivot *pivot, NAObject *item, gchar **message );
+guint   na_iio_provider_delete_item( const NAPivot *pivot, const NAObject *item, gchar **message );
 
 /* modification notification message to NAPivot
  */
@@ -148,7 +147,8 @@ enum {
 	NA_IIO_PROVIDER_NOT_WRITABLE,
 	NA_IIO_PROVIDER_NOT_WILLING_TO_WRITE,
 	NA_IIO_PROVIDER_WRITE_ERROR,
-	NA_IIO_PROVIDER_NO_PROVIDER
+	NA_IIO_PROVIDER_NO_PROVIDER,
+	NA_IIO_PROVIDER_PROGRAM_ERROR
 };
 
 G_END_DECLS
diff --git a/src/common/na-ipivot-consumer.c b/src/common/na-ipivot-consumer.c
index a080329..3e585d2 100644
--- a/src/common/na-ipivot-consumer.c
+++ b/src/common/na-ipivot-consumer.c
@@ -42,6 +42,9 @@ struct NAIPivotConsumerInterfacePrivate {
 	void *empty;						/* so that gcc -pedantic is happy */
 };
 
+static gboolean st_initialized = FALSE;
+static gboolean st_finalized = FALSE;
+
 static GType    register_type( void );
 static void     interface_base_init( NAIPivotConsumerInterface *klass );
 static void     interface_base_finalize( NAIPivotConsumerInterface *klass );
@@ -94,16 +97,15 @@ static void
 interface_base_init( NAIPivotConsumerInterface *klass )
 {
 	static const gchar *thisfn = "na_ipivot_consumer_interface_base_init";
-	static gboolean initialized = FALSE;
 
-	if( !initialized ){
+	if( !st_initialized ){
 		g_debug( "%s: klass=%p", thisfn, ( void * ) klass );
 
 		klass->private = g_new0( NAIPivotConsumerInterfacePrivate, 1 );
 
 		klass->on_actions_changed = NULL /*do_actions_changed*/;
 
-		initialized = TRUE;
+		st_initialized = TRUE;
 	}
 }
 
@@ -111,14 +113,14 @@ static void
 interface_base_finalize( NAIPivotConsumerInterface *klass )
 {
 	static const gchar *thisfn = "na_ipivot_consumer_interface_base_finalize";
-	static gboolean finalized = FALSE ;
 
-	if( !finalized ){
+	if( !st_finalized ){
+
+		st_finalized = TRUE;
+
 		g_debug( "%s: klass=%p", thisfn, ( void * ) klass );
 
 		g_free( klass->private );
-
-		finalized = TRUE;
 	}
 }
 
@@ -136,6 +138,9 @@ na_ipivot_consumer_delay_notify( NAIPivotConsumer *instance )
 {
 	GTimeVal *last_delay;
 
+	g_return_if_fail( st_initialized && !st_finalized );
+	g_return_if_fail( NA_IS_IPIVOT_CONSUMER( instance ));
+
 	last_delay = ( GTimeVal * ) g_object_get_data( G_OBJECT( instance ), "na-ipivot-consumer-delay-notify" );
 
 	if( !last_delay ){
@@ -160,6 +165,9 @@ void na_ipivot_consumer_notify( NAIPivotConsumer *instance )
 
 	g_debug( "%s: instance=%p", thisfn, ( void * ) instance );
 
+	g_return_if_fail( st_initialized && !st_finalized );
+	g_return_if_fail( NA_IS_IPIVOT_CONSUMER( instance ));
+
 	if( is_notify_allowed( instance )){
 		if( NA_IPIVOT_CONSUMER_GET_INTERFACE( instance )->on_actions_changed ){
 			NA_IPIVOT_CONSUMER_GET_INTERFACE( instance )->on_actions_changed( instance, NULL );
@@ -177,6 +185,9 @@ void na_ipivot_consumer_notify( NAIPivotConsumer *instance )
 void
 na_ipivot_consumer_notify_display_order_change( NAIPivotConsumer *instance )
 {
+	g_return_if_fail( st_initialized && !st_finalized );
+	g_return_if_fail( NA_IS_IPIVOT_CONSUMER( instance ));
+
 	if( NA_IPIVOT_CONSUMER_GET_INTERFACE( instance )->on_display_order_changed ){
 		NA_IPIVOT_CONSUMER_GET_INTERFACE( instance )->on_display_order_changed( instance, NULL );
 	}
@@ -193,6 +204,9 @@ na_ipivot_consumer_notify_display_order_change( NAIPivotConsumer *instance )
 void
 na_ipivot_consumer_notify_display_about_change( NAIPivotConsumer *instance )
 {
+	g_return_if_fail( st_initialized && !st_finalized );
+	g_return_if_fail( NA_IS_IPIVOT_CONSUMER( instance ));
+
 	if( NA_IPIVOT_CONSUMER_GET_INTERFACE( instance )->on_display_about_changed ){
 		NA_IPIVOT_CONSUMER_GET_INTERFACE( instance )->on_display_about_changed( instance, NULL );
 	}
diff --git a/src/common/na-iprefs.c b/src/common/na-iprefs.c
index 18a5ab1..ed4eb93 100644
--- a/src/common/na-iprefs.c
+++ b/src/common/na-iprefs.c
@@ -33,9 +33,7 @@
 #include <config.h>
 #endif
 
-#include <gconf/gconf.h>
-#include <gconf/gconf-client.h>
-
+#include "na-gconf-utils.h"
 #include "na-iprefs.h"
 
 /* private interface data
@@ -44,12 +42,17 @@ struct NAIPrefsInterfacePrivate {
 	GConfClient *client;
 };
 
+static gboolean st_initialized = FALSE;
+static gboolean st_finalized = FALSE;
+
 static GType    register_type( void );
 static void     interface_base_init( NAIPrefsInterface *klass );
 static void     interface_base_finalize( NAIPrefsInterface *klass );
 
-static gboolean read_key_bool( NAIPrefs *instance, const gchar *name, gboolean default_value );
-static void     write_key_bool( NAIPrefs *instance, const gchar *name, gboolean value );
+static gboolean read_bool( NAIPrefs *instance, const gchar *name, gboolean default_value );
+static GSList  *read_string_list( NAIPrefs *instance, const gchar *name );
+static void     write_bool( NAIPrefs *instance, const gchar *name, gboolean value );
+static void     write_string_list( NAIPrefs *instance, const gchar *name, GSList *list );
 
 GType
 na_iprefs_get_type( void )
@@ -94,16 +97,16 @@ static void
 interface_base_init( NAIPrefsInterface *klass )
 {
 	static const gchar *thisfn = "na_iprefs_interface_base_init";
-	static gboolean initialized = FALSE;
 
-	if( !initialized ){
+	if( !st_initialized ){
+
 		g_debug( "%s: klass=%p", thisfn, ( void * ) klass );
 
 		klass->private = g_new0( NAIPrefsInterfacePrivate, 1 );
 
 		klass->private->client = gconf_client_get_default();
 
-		initialized = TRUE;
+		st_initialized = TRUE;
 	}
 }
 
@@ -111,19 +114,48 @@ static void
 interface_base_finalize( NAIPrefsInterface *klass )
 {
 	static const gchar *thisfn = "na_iprefs_interface_base_finalize";
-	static gboolean finalized = FALSE ;
 
-	if( !finalized ){
+	if( !st_finalized ){
+
+		st_finalized = TRUE;
+
 		g_debug( "%s: klass=%p", thisfn, ( void * ) klass );
 
 		g_free( klass->private );
-
-		finalized = TRUE;
 	}
 }
 
 /**
- * na_iprefs_get_alphabetical_order:
+ * na_iprefs_get_level_zero_items:
+ * @instance: this #NAIPrefs interface instance.
+ */
+GSList *
+na_iprefs_get_level_zero_items( NAIPrefs *instance )
+{
+	g_return_val_if_fail( st_initialized && !st_finalized, NULL );
+	g_return_val_if_fail( NA_IS_IPREFS( instance ), NULL );
+
+	return( read_string_list( instance, PREFS_LEVEL_ZERO_ITEMS ));
+}
+
+/**
+ * na_iprefs_set_level_zero_items:
+ * @instance: this #NAIPrefs interface instance.
+ * @order: a #GSList of item ids.
+ *
+ * Writes the order and the content of the level-zero items.
+ */
+void
+na_iprefs_set_level_zero_items( NAIPrefs *instance, GSList *order )
+{
+	g_return_if_fail( st_initialized && !st_finalized );
+	g_return_if_fail( NA_IS_IPREFS( instance ));
+
+	write_string_list( instance, PREFS_LEVEL_ZERO_ITEMS, order );
+}
+
+/**
+ * na_iprefs_is_alphabetical_order:
  * @instance: this #NAIPrefs interface instance.
  *
  * Returns: #TRUE if the actions are to be maintained in alphabetical
@@ -135,13 +167,30 @@ interface_base_finalize( NAIPrefsInterface *klass )
  * Note: please take care of keeping the default value synchronized with
  * those defined in schemas.
  */
-gboolean na_iprefs_get_alphabetical_order( NAIPrefs *instance )
+gboolean
+na_iprefs_is_alphabetical_order( NAIPrefs *instance )
 {
-	return( read_key_bool( instance, PREFS_DISPLAY_ALPHABETICAL_ORDER, TRUE ));
+	g_return_val_if_fail( st_initialized && !st_finalized, FALSE );
+	g_return_val_if_fail( NA_IS_IPREFS( instance ), FALSE );
+
+	return( read_bool( instance, PREFS_DISPLAY_ALPHABETICAL_ORDER, TRUE ));
 }
 
 /**
- * na_iprefs_get_add_about_item:
+ * na_iprefs_set_alphabetical_order:
+ * @instance: this #NAIPrefs interface instance.
+ */
+void
+na_iprefs_set_alphabetical_order( NAIPrefs *instance, gboolean enabled )
+{
+	g_return_if_fail( st_initialized && !st_finalized );
+	g_return_if_fail( NA_IS_IPREFS( instance ));
+
+	write_bool( instance, PREFS_DISPLAY_ALPHABETICAL_ORDER, enabled );
+}
+
+/**
+ * na_iprefs_should_add_about_item:
  * @instance: this #NAIPrefs interface instance.
  *
  * Returns: #TRUE if an "About Nautilus Actions" item may be added to
@@ -153,93 +202,81 @@ gboolean na_iprefs_get_alphabetical_order( NAIPrefs *instance )
  * Note: please take care of keeping the default value synchronized with
  * those defined in schemas.
  */
-gboolean na_iprefs_get_add_about_item( NAIPrefs *instance )
+gboolean
+na_iprefs_should_add_about_item( NAIPrefs *instance )
 {
-	return( read_key_bool( instance, PREFS_ADD_ABOUT_ITEM, TRUE ));
+	g_return_val_if_fail( st_initialized && !st_finalized, FALSE );
+	g_return_val_if_fail( NA_IS_IPREFS( instance ), FALSE );
+
+	return( read_bool( instance, PREFS_ADD_ABOUT_ITEM, TRUE ));
 }
 
 /**
- * Get a named boolean.
+ * na_iprefs_should_add_about_item:
  * @instance: this #NAIPrefs interface instance.
- * @name: the name of the key to be read.
  *
- * Returns: the boolean attached to the @name key.
+ * Returns: #TRUE if an "About Nautilus Actions" item may be added to
+ * the first level of Nautilus context submenus (if any), #FALSE else.
  *
- * Note that this returns #FALSE if the key doesn't exist.
- * See na_iprefs_get_alphabetical_order() and
- * na_iprefs_get_add_about_item() to get suitable default values.
- */
-gboolean
-na_iprefs_get_bool( NAIPrefs *instance, const gchar *name )
-{
-	return( read_key_bool( instance, name, FALSE ));
-}
-
-/**
- * Set a named boolean.
- * @instance: this #NAIPrefs interface instance.
- * @name: the name of the key to be read.
+ * Note: this function returns a suitable default value if the key is
+ * not found in GConf preferences.
  *
- * Records the specified boolean in the GConf preferences.
+ * Note: please take care of keeping the default value synchronized with
+ * those defined in schemas.
  */
 void
-na_iprefs_set_bool( NAIPrefs *instance, const gchar *name, gboolean value )
+na_iprefs_set_add_about_item( NAIPrefs *instance, gboolean enabled )
 {
-	write_key_bool( instance, name, value );
+	g_return_if_fail( st_initialized && !st_finalized );
+	g_return_if_fail( NA_IS_IPREFS( instance ));
+
+	write_bool( instance, PREFS_ADD_ABOUT_ITEM, enabled );
 }
 
-/*
- * note that don't rely on having correctly installed the schema for the key
- */
 static gboolean
-read_key_bool( NAIPrefs *instance, const gchar *name, gboolean default_value )
+read_bool( NAIPrefs *instance, const gchar *name, gboolean default_value )
 {
-	static const gchar *thisfn = "na_iprefs_read_key_bool";
-	GError *error = NULL;
 	gchar *path;
-	GConfValue *value;
 	gboolean ret;
 
-	ret = default_value;
-
 	path = g_strdup_printf( "%s/%s", NA_GCONF_PREFS_PATH, name );
+	ret = na_gconf_utils_read_bool( NA_IPREFS_GET_INTERFACE( instance )->private->client, path, FALSE, default_value );
+	g_free( path );
 
-	value = gconf_client_get_without_default( NA_IPREFS_GET_INTERFACE( instance )->private->client, path, &error );
-	/*g_debug( "%s: path=%s, value=%p", thisfn, path, ( void * ) value );*/
-
-	if( error ){
-		g_warning( "%s: name=%s, %s", thisfn, name, error->message );
-		g_error_free( error );
-		if( value ){
-			gconf_value_free( value );
-			value = NULL;
-		}
-	}
+	return( ret );
+}
 
-	if( value ){
-		ret = gconf_value_get_bool( value );
-		gconf_value_free( value );
-	}
+static GSList *
+read_string_list( NAIPrefs *instance, const gchar *name )
+{
+	gchar *path;
+	GSList *list;
 
+	path = g_strdup_printf( "%s/%s", NA_GCONF_PREFS_PATH, name );
+	list = na_gconf_utils_read_string_list( NA_IPREFS_GET_INTERFACE( instance )->private->client, path );
 	g_free( path );
-	return( ret );
+
+	return( list );
 }
 
 static void
-write_key_bool( NAIPrefs *instance, const gchar *name, gboolean value )
+write_bool( NAIPrefs *instance, const gchar *name, gboolean value )
 {
-	static const gchar *thisfn = "na_iprefs_write_key_bool";
-	GError *error = NULL;
 	gchar *path;
 
 	path = g_strdup_printf( "%s/%s", NA_GCONF_PREFS_PATH, name );
 
-	gconf_client_set_bool( NA_IPREFS_GET_INTERFACE( instance )->private->client, path, value, &error );
+	na_gconf_utils_write_bool( NA_IPREFS_GET_INTERFACE( instance )->private->client, path, value, NULL );
 
-	if( error ){
-		g_warning( "%s: name=%s, %s", thisfn, name, error->message );
-		g_error_free( error );
-	}
+	g_free( path );
+}
+
+static void
+write_string_list( NAIPrefs *instance, const gchar *name, GSList *list )
+{
+	gchar *path;
 
+	path = g_strdup_printf( "%s/%s", NA_GCONF_PREFS_PATH, name );
+	na_gconf_utils_write_string_list( NA_IPREFS_GET_INTERFACE( instance )->private->client, path, list, NULL );
 	g_free( path );
 }
diff --git a/src/common/na-iprefs.h b/src/common/na-iprefs.h
index 6d2ed40..7e3a34e 100644
--- a/src/common/na-iprefs.h
+++ b/src/common/na-iprefs.h
@@ -36,9 +36,13 @@
  * @short_description: #NAIPrefs interface definition.
  * @include: common/na-iprefs.h
  *
- * This interface is to be implemented by all modules which wish take
- * benefit of preferences management. It only manages preferences which
- * are used by the plugin, and used/updated in the NACT user interface.
+ * This interface should only be implemented by #NAPivot. This is
+ * because the interface stores in its class private area some data
+ * only relevant for one client (GConfClient, GConf monitors, etc.).
+ *
+ * Though all modules may use the public functions na_iprefs_xxx(),
+ * only #NAPivot will receive update notifications, taking itself care
+ * of proxying them to identified consumers.
  *
  * Displaying the actions.
  *
@@ -96,7 +100,7 @@
 
 #include <glib-object.h>
 
-#include "na-gconf-keys.h"
+#include "na-gconf-keys-base.h"
 
 G_BEGIN_DECLS
 
@@ -117,20 +121,25 @@ typedef struct {
 
 GType    na_iprefs_get_type( void );
 
-gboolean na_iprefs_get_alphabetical_order( NAIPrefs *instance );
-gboolean na_iprefs_get_add_about_item( NAIPrefs *instance );
+GSList  *na_iprefs_get_level_zero_items( NAIPrefs *instance );
+void     na_iprefs_set_level_zero_items( NAIPrefs *instance, GSList *order );
+
+gboolean na_iprefs_is_alphabetical_order( NAIPrefs *instance );
+void     na_iprefs_set_alphabetical_order( NAIPrefs *instance, gboolean enabled );
 
-gboolean na_iprefs_get_bool( NAIPrefs *instance, const gchar *key );
-void     na_iprefs_set_bool( NAIPrefs *instance, const gchar *key, gboolean value );
+gboolean na_iprefs_should_add_about_item( NAIPrefs *instance );
+void     na_iprefs_set_add_about_item( NAIPrefs *instance, gboolean enabled );
 
-/* GConf general information
+/* GConf key
  */
-#define NA_GCONF_PREFS_PATH		NAUTILUS_ACTIONS_CONFIG_GCONF_BASEDIR "/" NA_GCONF_SCHEMA_PREFERENCES
+#define NA_GCONF_PREFERENCES				"preferences"
+#define NA_GCONF_PREFS_PATH					NAUTILUS_ACTIONS_GCONF_BASEDIR "/" NA_GCONF_PREFERENCES
 
 /* GConf Preference keys managed by IPrefs interface
  */
-#define PREFS_DISPLAY_ALPHABETICAL_ORDER	"preferences-alphabetical-order"
-#define PREFS_ADD_ABOUT_ITEM				"preferences-add-about-item"
+#define PREFS_LEVEL_ZERO_ITEMS				"iprefs-level-zero"
+#define PREFS_DISPLAY_ALPHABETICAL_ORDER	"iprefs-alphabetical-order"
+#define PREFS_ADD_ABOUT_ITEM				"iprefs-add-about-item"
 
 G_END_DECLS
 
diff --git a/src/common/na-action-class.h b/src/common/na-obj-action-class.h
similarity index 51%
copy from src/common/na-action-class.h
copy to src/common/na-obj-action-class.h
index 38cf758..d0db613 100644
--- a/src/common/na-action-class.h
+++ b/src/common/na-obj-action-class.h
@@ -1,5 +1,5 @@
 /*
- * Nautilus Actions
+ * Nautilus ObjectActions
  * A Nautilus extension which offers configurable context menu actions.
  *
  * Copyright (C) 2005 The GNOME Foundation
@@ -28,42 +28,38 @@
  *   ... and many others (see AUTHORS)
  */
 
-#ifndef __NA_ACTION_CLASS_H__
-#define __NA_ACTION_CLASS_H__
+#ifndef __NA_OBJECT_ACTION_CLASS_H__
+#define __NA_OBJECT_ACTION_CLASS_H__
 
-/**
- * SECTION: na_action
- */
-
-#include "na-object-item.h"
+#include "na-object-item-class.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 ))
+#define NA_OBJECT_ACTION_TYPE					( na_object_action_get_type())
+#define NA_OBJECT_ACTION( object )				( G_TYPE_CHECK_INSTANCE_CAST( object, NA_OBJECT_ACTION_TYPE, NAObjectAction ))
+#define NA_OBJECT_ACTION_CLASS( klass )			( G_TYPE_CHECK_CLASS_CAST( klass, NA_OBJECT_ACTION_TYPE, NAObjectActionClass ))
+#define NA_IS_OBJECT_ACTION( object )			( G_TYPE_CHECK_INSTANCE_TYPE( object, NA_OBJECT_ACTION_TYPE ))
+#define NA_IS_OBJECT_ACTION_CLASS( klass )		( G_TYPE_CHECK_CLASS_TYPE(( klass ), NA_OBJECT_ACTION_TYPE ))
+#define NA_OBJECT_ACTION_GET_CLASS( object )	( G_TYPE_INSTANCE_GET_CLASS(( object ), NA_OBJECT_ACTION_TYPE, NAObjectActionClass ))
 
-typedef struct NAActionPrivate NAActionPrivate;
+typedef struct NAObjectActionPrivate NAObjectActionPrivate;
 
 typedef struct {
-	NAObjectItem     parent;
-	NAActionPrivate *private;
+	NAObjectItem           parent;
+	NAObjectActionPrivate *private;
 }
-	NAAction;
+	NAObjectAction;
 
-typedef struct NAActionClassPrivate NAActionClassPrivate;
+typedef struct NAObjectActionClassPrivate NAObjectActionClassPrivate;
 
 typedef struct {
-	NAObjectItemClass     parent;
-	NAActionClassPrivate *private;
+	NAObjectItemClass           parent;
+	NAObjectActionClassPrivate *private;
 }
-	NAActionClass;
+	NAObjectActionClass;
 
-GType na_action_get_type( void );
+GType na_object_action_get_type( void );
 
 G_END_DECLS
 
-#endif /* __NA_ACTION_CLASS_H__ */
+#endif /* __NA_OBJECT_ACTION_CLASS_H__ */
diff --git a/src/common/na-obj-action.c b/src/common/na-obj-action.c
new file mode 100644
index 0000000..bfd75b5
--- /dev/null
+++ b/src/common/na-obj-action.c
@@ -0,0 +1,591 @@
+/*
+ * 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 <string.h>
+
+#include "na-object-api.h"
+#include "na-obj-action.h"
+#include "na-obj-profile.h"
+#include "na-utils.h"
+
+/* private class data
+ */
+struct NAObjectActionClassPrivate {
+	void *empty;						/* so that gcc -pedantic is happy */
+};
+
+/* private instance data
+ */
+struct NAObjectActionPrivate {
+	gboolean dispose_has_run;
+
+	/* action properties
+	 */
+	gchar   *version;
+
+	/* 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;
+};
+
+/* action properties
+ */
+enum {
+	NAACTION_PROP_VERSION_ID = 1,
+	NAACTION_PROP_READONLY_ID
+};
+
+#define NAACTION_PROP_VERSION			"na-action-version"
+#define NAACTION_PROP_READONLY			"na-action-read-only"
+
+static NAObjectItemClass *st_parent_class = NULL;
+
+static GType     register_type( void );
+static void      class_init( NAObjectActionClass *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      object_dump( const NAObject *object );
+static gchar    *object_get_clipboard_id( const NAObject *action );
+static NAObject *object_new( 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 *object );
+
+GType
+na_object_action_get_type( void )
+{
+	static GType action_type = 0;
+
+	if( !action_type ){
+		action_type = register_type();
+	}
+
+	return( action_type );
+}
+
+static GType
+register_type( void )
+{
+	static const gchar *thisfn = "na_object_register_type";
+
+	static GTypeInfo info = {
+		sizeof( NAObjectActionClass ),
+		( GBaseInitFunc ) NULL,
+		( GBaseFinalizeFunc ) NULL,
+		( GClassInitFunc ) class_init,
+		NULL,
+		NULL,
+		sizeof( NAObjectAction ),
+		0,
+		( GInstanceInitFunc ) instance_init
+	};
+
+	g_debug( "%s", thisfn );
+
+	return( g_type_register_static( NA_OBJECT_ITEM_TYPE, "NAObjectAction", &info, 0 ));
+}
+
+static void
+class_init( NAObjectActionClass *klass )
+{
+	static const gchar *thisfn = "na_object_class_init";
+	GObjectClass *object_class;
+	NAObjectClass *naobject_class;
+	GParamSpec *spec;
+
+	g_debug( "%s: klass=%p", thisfn, ( void * ) klass );
+
+	st_parent_class = g_type_class_peek_parent( klass );
+
+	object_class = G_OBJECT_CLASS( klass );
+	object_class->dispose = instance_dispose;
+	object_class->finalize = instance_finalize;
+	object_class->set_property = instance_set_property;
+	object_class->get_property = instance_get_property;
+
+	spec = g_param_spec_string(
+			NAACTION_PROP_VERSION,
+			"Version",
+			"Version of the schema", "",
+			G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE );
+	g_object_class_install_property( object_class, NAACTION_PROP_VERSION_ID, spec );
+
+	spec = g_param_spec_boolean(
+			NAACTION_PROP_READONLY,
+			"Read-only flag",
+			"Is this action only readable", FALSE,
+			G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE );
+	g_object_class_install_property( object_class, NAACTION_PROP_READONLY_ID, spec );
+
+	klass->private = g_new0( NAObjectActionClassPrivate, 1 );
+
+	naobject_class = NA_OBJECT_CLASS( klass );
+	naobject_class->dump = object_dump;
+	naobject_class->get_clipboard_id = object_get_clipboard_id;
+	naobject_class->ref = NULL;
+	naobject_class->new = object_new;
+	naobject_class->copy = object_copy;
+	naobject_class->are_equal = object_are_equal;
+	naobject_class->is_valid = object_is_valid;
+}
+
+static void
+instance_init( GTypeInstance *instance, gpointer klass )
+{
+	/*static const gchar *thisfn = "na_object_action_instance_init";*/
+	NAObjectAction *self;
+
+	/*g_debug( "%s: instance=%p, klass=%p", thisfn, ( void * ) instance, ( void * ) klass );*/
+	g_return_if_fail( NA_IS_OBJECT_ACTION( instance ));
+	self = NA_OBJECT_ACTION( instance );
+
+	self->private = g_new0( NAObjectActionPrivate, 1 );
+
+	self->private->dispose_has_run = FALSE;
+
+	/* initialize suitable default values
+	 */
+	self->private->version = g_strdup( NAUTILUS_ACTIONS_CONFIG_VERSION );
+	self->private->read_only = FALSE;
+}
+
+static void
+instance_get_property( GObject *object, guint property_id, GValue *value, GParamSpec *spec )
+{
+	NAObjectAction *self;
+
+	g_return_if_fail( NA_IS_OBJECT_ACTION( object ));
+	g_return_if_fail( !NA_OBJECT_ACTION( object )->private->dispose_has_run );
+	self = NA_OBJECT_ACTION( object );
+
+	switch( property_id ){
+		case NAACTION_PROP_VERSION_ID:
+			g_value_set_string( value, self->private->version );
+			break;
+
+		case NAACTION_PROP_READONLY_ID:
+			g_value_set_boolean( value, self->private->read_only );
+			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 )
+{
+	NAObjectAction *self;
+
+	g_return_if_fail( NA_IS_OBJECT_ACTION( object ));
+	g_return_if_fail( !NA_OBJECT_ACTION( object )->private->dispose_has_run );
+	self = NA_OBJECT_ACTION( object );
+
+	switch( property_id ){
+		case NAACTION_PROP_VERSION_ID:
+			g_free( self->private->version );
+			self->private->version = g_value_dup_string( value );
+			break;
+
+		case NAACTION_PROP_READONLY_ID:
+			self->private->read_only = g_value_get_boolean( value );
+			break;
+
+		default:
+			G_OBJECT_WARN_INVALID_PROPERTY_ID( object, property_id, spec );
+			break;
+	}
+}
+
+static void
+instance_dispose( GObject *object )
+{
+	/*static const gchar *thisfn = "na_object_instance_dispose";*/
+	NAObjectAction *self;
+
+	/*g_debug( "%s: object=%p", thisfn, ( void * ) object );*/
+
+	g_return_if_fail( NA_IS_OBJECT_ACTION( object ));
+	self = NA_OBJECT_ACTION( object );
+	g_return_if_fail( !self->private->dispose_has_run );
+
+	if( !self->private->dispose_has_run ){
+
+		self->private->dispose_has_run = TRUE;
+
+		/* chain up to the parent class */
+		if( G_OBJECT_CLASS( st_parent_class )->dispose ){
+			G_OBJECT_CLASS( st_parent_class )->dispose( object );
+		}
+	}
+}
+
+static void
+instance_finalize( GObject *object )
+{
+	/*static const gchar *thisfn = "na_object_instance_finalize";*/
+	NAObjectAction *self;
+
+	/*g_debug( "%s: object=%p", thisfn, ( void * ) object );*/
+
+	g_return_if_fail( NA_IS_OBJECT_ACTION( object ));
+	self = ( NAObjectAction * ) object;
+
+	g_free( self->private->version );
+
+	g_free( self->private );
+
+	/* chain call to parent class */
+	if( G_OBJECT_CLASS( st_parent_class )->finalize ){
+		G_OBJECT_CLASS( st_parent_class )->finalize( object );
+	}
+}
+
+/**
+ * na_object_action_new:
+ *
+ * Allocates a new #NAObjectAction object.
+ *
+ * The new #NAObjectAction object is initialized with suitable default values,
+ * but without any profile.
+ *
+ * Returns: the newly allocated #NAObjectAction object.
+ */
+NAObjectAction *
+na_object_action_new( void )
+{
+	NAObjectAction *action;
+
+	action = g_object_new( NA_OBJECT_ACTION_TYPE, NULL );
+
+	na_object_item_set_new_uuid( NA_OBJECT_ITEM( action ));
+
+	/* i18n: default label for a new action */
+	na_object_set_label( action, NA_OBJECT_ACTION_DEFAULT_LABEL );
+
+	return( action );
+}
+
+/**
+ * na_object_action_new_with_profile:
+ *
+ * Allocates a new #NAObjectAction object along with a default profile.
+ *
+ * Return: the newly allocated #NAObjectAction action.
+ */
+NAObjectAction *
+na_object_action_new_with_profile( void )
+{
+	NAObjectAction *action;
+	NAObjectProfile *profile;
+
+	action = na_object_action_new();
+
+	profile = na_object_profile_new();
+
+	/* i18n: name of the default profile when creating an action */
+	na_object_set_label( profile, _( "Default profile" ));
+	na_object_action_attach_profile( action, profile );
+
+	return( action );
+}
+
+/**
+ * na_object_action_get_version:
+ * @action: the #NAObjectAction object to be requested.
+ *
+ * Returns the version of the description of the action, as found when
+ * reading it from the I/O storage subsystem.
+ *
+ * Returns: the version of the action as a newly allocated string. This
+ * returned string must be g_free() by the caller.
+ *
+ * See na_object_set_version() for some rationale about version.
+ */
+gchar *
+na_object_action_get_version( const NAObjectAction *action )
+{
+	gchar *version;
+
+	g_return_val_if_fail( NA_IS_OBJECT_ACTION( action ), NULL );
+	g_return_val_if_fail( !action->private->dispose_has_run, NULL );
+
+	g_object_get( G_OBJECT( action ), NAACTION_PROP_VERSION, &version, NULL );
+
+	return( version );
+}
+
+/**
+ * na_object_action_is_readonly:
+ * @action: the #NAObjectAction object to be requested.
+ *
+ * Is the specified action only readable ?
+ * Or, in other words, may this action be edited and then saved to the
+ * original I/O storage subsystem ?
+ *
+ * Returns: %TRUE if the action is editable, %FALSE else.
+ */
+gboolean
+na_object_action_is_readonly( const NAObjectAction *action )
+{
+	gboolean readonly;
+
+	g_return_val_if_fail( NA_IS_OBJECT_ACTION( action ), FALSE );
+	g_return_val_if_fail( !action->private->dispose_has_run, FALSE );
+
+	g_object_get( G_OBJECT( action ), NAACTION_PROP_READONLY, &readonly, NULL );
+
+	return( readonly );
+}
+
+/**
+ * na_object_action_set_version:
+ * @action: the #NAObjectAction object to be updated.
+ * @label: the label to be set.
+ *
+ * Sets a new version for the action.
+ *
+ * #NAObjectAction takes a copy of the provided version. This later may so be
+ * g_free() by the caller after this function returns.
+ *
+ * The version describes the schema of the informations in the I/O
+ * storage subsystem.
+ *
+ * Version is stored in the #NAObjectAction object as readen from the I/O
+ * storage subsystem, even if the #NAObjectAction object itself only reflects
+ * the lastest known version. Conversion is made at load time (cf.
+ * na_gconf_load_action()).
+ */
+void
+na_object_action_set_version( NAObjectAction *action, const gchar *version )
+{
+	g_return_if_fail( NA_IS_OBJECT_ACTION( action ));
+	g_return_if_fail( !action->private->dispose_has_run );
+
+	g_object_set( G_OBJECT( action ), NAACTION_PROP_VERSION, version, NULL );
+}
+
+/**
+ * na_object_action_set_readonly:
+ * @action: the #NAObjectAction object to be updated.
+ * @readonly: the indicator to be set.
+ *
+ * Sets whether the action is readonly.
+ */
+void
+na_object_action_set_readonly( NAObjectAction *action, gboolean readonly )
+{
+	g_return_if_fail( NA_IS_OBJECT_ACTION( action ));
+	g_return_if_fail( !action->private->dispose_has_run );
+
+	g_object_set( G_OBJECT( action ), NAACTION_PROP_READONLY, readonly, NULL );
+}
+
+/**
+ * na_object_action_get_new_profile_name:
+ * @action: the #NAObjectAction object which will receive a new profile.
+ *
+ * Returns a name suitable as 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.
+ *
+ * Returns: a newly allocated profile name, which should be g_free() by
+ * the caller.
+ */
+gchar *
+na_object_action_get_new_profile_name( const NAObjectAction *action )
+{
+	int i;
+	gboolean ok = FALSE;
+	gchar *candidate = NULL;
+
+	g_return_val_if_fail( NA_IS_OBJECT_ACTION( action ), NULL );
+	g_return_val_if_fail( !action->private->dispose_has_run, NULL );
+
+	for( i=1 ; !ok ; ++i ){
+		g_free( candidate );
+		candidate = g_strdup_printf( "%s%d", OBJECT_PROFILE_PREFIX, i );
+		if( !na_object_get_item( action, candidate )){
+			ok = TRUE;
+		}
+	}
+
+	if( !ok ){
+		g_free( candidate );
+		candidate = NULL;
+	}
+
+	return( candidate );
+}
+
+/**
+ * na_object_action_attach_profile:
+ * @action: the #NAObjectAction action to which the profile will be attached.
+ * @profile: the #NAObjectProfile profile to be attached to @action.
+ *
+ * Adds a profile at the end of the list of profiles.
+ */
+void
+na_object_action_attach_profile( NAObjectAction *action, NAObjectProfile *profile )
+{
+	g_return_if_fail( NA_IS_OBJECT_ACTION( action ));
+	g_return_if_fail( !action->private->dispose_has_run );
+	g_return_if_fail( NA_IS_OBJECT_PROFILE( profile ));
+
+	na_object_append_item( action, profile );
+	na_object_profile_set_action( profile, action );
+}
+
+static void
+object_dump( const NAObject *action )
+{
+	static const gchar *thisfn = "na_object_action_object_dump";
+	NAObjectAction *self;
+
+	g_return_if_fail( NA_IS_OBJECT_ACTION( action ));
+	self = NA_OBJECT_ACTION( action );
+	g_return_if_fail( !self->private->dispose_has_run );
+
+	g_debug( "%s:   version='%s'", thisfn, self->private->version );
+	g_debug( "%s: read-only='%s'", thisfn, self->private->read_only ? "True" : "False" );
+}
+
+static gchar *
+object_get_clipboard_id( const NAObject *action )
+{
+	gchar *uuid;
+	gchar *clipboard_id;
+
+	uuid = na_object_get_id( action );
+	clipboard_id = g_strdup_printf( "A:%s", uuid );
+	g_free( uuid );
+
+	return( clipboard_id );
+}
+
+static NAObject *
+object_new( const NAObject *action )
+{
+	return( NA_OBJECT( na_object_action_new()));
+}
+
+void
+object_copy( NAObject *target, const NAObject *source )
+{
+	gchar *version;
+	gboolean readonly;
+	GSList *profiles, *ip;
+
+	g_return_if_fail( NA_IS_OBJECT_ACTION( target ));
+	g_return_if_fail( !NA_OBJECT_ACTION( target )->private->dispose_has_run );
+	g_return_if_fail( NA_IS_OBJECT_ACTION( source ));
+	g_return_if_fail( !NA_OBJECT_ACTION( source )->private->dispose_has_run );
+
+	g_object_get( G_OBJECT( source ),
+			NAACTION_PROP_VERSION, &version,
+			NAACTION_PROP_READONLY, &readonly,
+			NULL );
+
+	g_object_set( G_OBJECT( target ),
+			NAACTION_PROP_VERSION, version,
+			NAACTION_PROP_READONLY, readonly,
+			NULL );
+
+	g_free( version );
+
+	/* profiles have been copied (duplicated) as subitems by parent class
+	 * we have to attach new profiles to target action
+	 */
+	profiles = na_object_get_items( target );
+	for( ip = profiles ; ip ; ip = ip->next ){
+		na_object_profile_set_action( NA_OBJECT_PROFILE( ip->data ), NA_OBJECT_ACTION( target ));
+	}
+	na_object_free_items( profiles );
+
+	/*g_debug( "na_object_action_object_copy: end" );*/
+}
+
+static gboolean
+object_are_equal( const NAObject *a, const NAObject *b )
+{
+	NAObjectAction *first, *second;
+	gboolean equal = TRUE;
+
+	g_return_val_if_fail( NA_IS_OBJECT_ACTION( a ), FALSE );
+	g_return_val_if_fail( !NA_OBJECT_ACTION( a )->private->dispose_has_run, FALSE );
+	first = NA_OBJECT_ACTION( a );
+
+	g_return_val_if_fail( NA_IS_OBJECT_ACTION( b ), FALSE );
+	g_return_val_if_fail( !NA_OBJECT_ACTION( b )->private->dispose_has_run, FALSE );
+	second = NA_OBJECT_ACTION( b );
+
+	if( equal ){
+		equal = ( g_utf8_collate( first->private->version, second->private->version ) == 0 );
+	}
+
+	g_debug( "na_object_action_are_equal: %s", equal ? "True":"False" );
+	return( equal );
+}
+
+/*
+ * a valid NAObjectAction requires a not null, not empty label
+ * this is checked here as NAObject doesn't have this condition
+ */
+gboolean
+object_is_valid( const NAObject *action )
+{
+	gchar *label;
+	gboolean is_valid = TRUE;
+
+	g_return_val_if_fail( NA_IS_OBJECT_ACTION( action ), FALSE );
+	g_return_val_if_fail( !NA_OBJECT_ACTION( action )->private->dispose_has_run, FALSE );
+
+	if( is_valid ){
+		label = na_object_get_label( NA_OBJECT_ACTION( action ));
+		is_valid = ( label && g_utf8_strlen( label, -1 ) > 0 );
+		g_free( label );
+	}
+
+	return( is_valid );
+}
diff --git a/src/common/na-obj-action.h b/src/common/na-obj-action.h
new file mode 100644
index 0000000..c111bf6
--- /dev/null
+++ b/src/common/na-obj-action.h
@@ -0,0 +1,81 @@
+/*
+ * Nautilus ObjectActions
+ * 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_OBJECT_ACTION_H__
+#define __NA_OBJECT_ACTION_H__
+
+/**
+ * SECTION: na_object_action
+ * @short_description: #NAObjectAction class definition.
+ * @include: common/na-obj-action.h
+ *
+ * This is the class which maintains data and properties of an Nautilus
+ * action.
+ *
+ * Note about the UUID:
+ *
+ * The uuid is only required when writing the action to GConf in order
+ * to ensure unicity of subdirectories.
+ *
+ * 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. The user has so to modify the UUID before import.
+ */
+
+#include <glib/gi18n.h>
+
+#include "na-obj-action-class.h"
+#include "na-obj-profile-class.h"
+
+G_BEGIN_DECLS
+
+/* i18n: default label for a newly created action */
+#define NA_OBJECT_ACTION_DEFAULT_LABEL		_( "New Nautilus action" )
+
+/* i18n: default label for a newly created profile */
+#define NA_OBJECT_PROFILE_DEFAULT_LABEL		_( "New profile" )
+
+NAObjectAction *na_object_action_new( void );
+NAObjectAction *na_object_action_new_with_profile( void );
+
+gchar          *na_object_action_get_version( const NAObjectAction *action );
+gboolean        na_object_action_is_readonly( const NAObjectAction *action );
+
+void            na_object_action_set_version( NAObjectAction *action, const gchar *version );
+void            na_object_action_set_readonly( NAObjectAction *action, gboolean readonly );
+
+gchar          *na_object_action_get_new_profile_name( const NAObjectAction *action );
+void            na_object_action_attach_profile( NAObjectAction *action, NAObjectProfile *profile );
+
+G_END_DECLS
+
+#endif /* __NA_OBJECT_ACTION_H__ */
diff --git a/src/common/na-action-menu.c b/src/common/na-obj-menu.c
similarity index 53%
rename from src/common/na-action-menu.c
rename to src/common/na-obj-menu.c
index 1230cdc..68b1e97 100644
--- a/src/common/na-action-menu.c
+++ b/src/common/na-obj-menu.c
@@ -32,38 +32,45 @@
 #include <config.h>
 #endif
 
-#include "na-action.h"
-#include "na-action-menu.h"
+#include "na-object-api.h"
+#include "na-obj-action.h"
+#include "na-obj-menu.h"
+#include "na-utils.h"
 
 /* private class data
  */
-struct NAActionMenuClassPrivate {
+struct NAObjectMenuClassPrivate {
 	void *empty;						/* so that gcc -pedantic is happy */
 };
 
 /* private instance data
  */
-struct NAActionMenuPrivate {
+struct NAObjectMenuPrivate {
 	gboolean dispose_has_run;
+
+	/* this is the list of subitems as a list of id strings
+	 * as readen from IIOProviders
+	 */
+	GSList  *items_ids;
 };
 
 static NAObjectClass *st_parent_class = NULL;
 
 static GType     register_type( void );
-static void      class_init( NAActionMenuClass *klass );
+static void      class_init( NAObjectMenuClass *klass );
 static void      instance_init( GTypeInstance *instance, gpointer klass );
 static void      instance_dispose( GObject *object );
 static void      instance_finalize( GObject *object );
 
+static void      object_dump( const NAObject *menu );
+static gchar    *object_get_clipboard_id( const NAObject *menu );
 static NAObject *object_new( const NAObject *menu );
 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 *menu );
-static void      object_dump( const NAObject *menu );
-static gchar    *object_get_clipboard_id( const NAObject *menu );
 
 GType
-na_action_menu_get_type( void )
+na_object_menu_get_type( void )
 {
 	static GType action_type = 0;
 
@@ -77,29 +84,29 @@ na_action_menu_get_type( void )
 static GType
 register_type( void )
 {
-	static const gchar *thisfn = "na_action_menu_register_type";
+	static const gchar *thisfn = "na_object_menu_register_type";
 
 	static GTypeInfo info = {
-		sizeof( NAActionMenuClass ),
+		sizeof( NAObjectMenuClass ),
 		( GBaseInitFunc ) NULL,
 		( GBaseFinalizeFunc ) NULL,
 		( GClassInitFunc ) class_init,
 		NULL,
 		NULL,
-		sizeof( NAActionMenu ),
+		sizeof( NAObjectMenu ),
 		0,
 		( GInstanceInitFunc ) instance_init
 	};
 
 	g_debug( "%s", thisfn );
 
-	return( g_type_register_static( NA_OBJECT_ITEM_TYPE, "NAActionMenu", &info, 0 ));
+	return( g_type_register_static( NA_OBJECT_ITEM_TYPE, "NAObjectMenu", &info, 0 ));
 }
 
 static void
-class_init( NAActionMenuClass *klass )
+class_init( NAObjectMenuClass *klass )
 {
-	static const gchar *thisfn = "na_action_menu_class_init";
+	static const gchar *thisfn = "na_object_menu_class_init";
 	GObjectClass *object_class;
 
 	g_debug( "%s: klass=%p", thisfn, ( void * ) klass );
@@ -110,27 +117,28 @@ class_init( NAActionMenuClass *klass )
 	object_class->dispose = instance_dispose;
 	object_class->finalize = instance_finalize;
 
-	klass->private = g_new0( NAActionMenuClassPrivate, 1 );
+	klass->private = g_new0( NAObjectMenuClassPrivate, 1 );
 
+	NA_OBJECT_CLASS( klass )->dump = object_dump;
+	NA_OBJECT_CLASS( klass )->get_clipboard_id = object_get_clipboard_id;
+	NA_OBJECT_CLASS( klass )->ref = NULL;
 	NA_OBJECT_CLASS( klass )->new = object_new;
 	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;
-	NA_OBJECT_CLASS( klass )->dump = object_dump;
-	NA_OBJECT_CLASS( klass )->get_clipboard_id = object_get_clipboard_id;
 }
 
 static void
 instance_init( GTypeInstance *instance, gpointer klass )
 {
-	static const gchar *thisfn = "na_action_menu_instance_init";
-	NAActionMenu *self;
+	/*static const gchar *thisfn = "na_object_menu_instance_init";*/
+	NAObjectMenu *self;
 
-	g_debug( "%s: instance=%p, klass=%p", thisfn, ( void * ) instance, ( void * ) klass );
-	g_assert( NA_IS_ACTION_MENU( instance ));
-	self = NA_ACTION_MENU( instance );
+	/*g_debug( "%s: instance=%p, klass=%p", thisfn, ( void * ) instance, ( void * ) klass );*/
+	g_return_if_fail( NA_IS_OBJECT_MENU( instance ));
+	self = NA_OBJECT_MENU( instance );
 
-	self->private = g_new0( NAActionMenuPrivate, 1 );
+	self->private = g_new0( NAObjectMenuPrivate, 1 );
 
 	self->private->dispose_has_run = FALSE;
 }
@@ -138,80 +146,151 @@ instance_init( GTypeInstance *instance, gpointer klass )
 static void
 instance_dispose( GObject *object )
 {
-	static const gchar *thisfn = "na_action_menu_instance_dispose";
-	NAActionMenu *self;
+	static const gchar *thisfn = "na_object_menu_instance_dispose";
+	NAObjectMenu *self;
 
 	g_debug( "%s: object=%p", thisfn, ( void * ) object );
-
-	g_assert( NA_IS_ACTION_MENU( object ));
-	self = NA_ACTION_MENU( object );
+	g_return_if_fail( NA_IS_OBJECT_MENU( object ));
+	self = NA_OBJECT_MENU( object );
 
 	if( !self->private->dispose_has_run ){
 
 		self->private->dispose_has_run = TRUE;
 
 		/* chain up to the parent class */
-		G_OBJECT_CLASS( st_parent_class )->dispose( object );
+		if( G_OBJECT_CLASS( st_parent_class )->dispose ){
+			G_OBJECT_CLASS( st_parent_class )->dispose( object );
+		}
 	}
 }
 
 static void
 instance_finalize( GObject *object )
 {
-	static const gchar *thisfn = "na_action_menu_instance_finalize";
-	NAActionMenu *self;
+	static const gchar *thisfn = "na_object_menu_instance_finalize";
+	NAObjectMenu *self;
 
 	g_debug( "%s: object=%p", thisfn, ( void * ) object );
-	g_assert( NA_IS_ACTION_MENU( object ));
-	self = ( NAActionMenu * ) object;
+	g_return_if_fail( NA_IS_OBJECT_MENU( object ));
+	self = ( NAObjectMenu * ) object;
+
+	/* release string list of subitems */
+	na_utils_free_string_list( self->private->items_ids );
 
 	g_free( self->private );
 
 	/* chain call to parent class */
-	if((( GObjectClass * ) st_parent_class )->finalize ){
+	if( G_OBJECT_CLASS( st_parent_class )->finalize ){
 		G_OBJECT_CLASS( st_parent_class )->finalize( object );
 	}
 }
 
 /**
- * na_action_menu_new:
+ * na_object_menu_new:
  *
- * Allocates a new #NAActionMenu object.
+ * Allocates a new #NAObjectMenu object.
  *
- * The new #NAActionMenu object is initialized with suitable default values,
+ * The new #NAObjectMenu object is initialized with suitable default values,
  * but without any profile.
  *
- * Returns: the newly allocated #NAActionMenu object.
+ * Returns: the newly allocated #NAObjectMenu object.
  */
-NAActionMenu *
-na_action_menu_new( void )
+NAObjectMenu *
+na_object_menu_new( void )
 {
-	NAActionMenu *menu;
+	NAObjectMenu *menu;
 
-	menu = g_object_new( NA_ACTION_MENU_TYPE, NULL );
+	menu = g_object_new( NA_OBJECT_MENU_TYPE, NULL );
 
-	na_action_set_new_uuid( NA_ACTION( menu ));
+	na_object_item_set_new_uuid( NA_OBJECT_ITEM( menu ));
 
-	na_object_set_label( NA_OBJECT( menu ), NA_ACTION_MENU_DEFAULT_LABEL );
+	na_object_set_label( menu, NA_OBJECT_MENU_DEFAULT_LABEL );
 
 	return( menu );
 }
 
+/**
+ * Build a string list which contains the ordered list of ids of subitems.
+ *
+ * The list must be na_utils_free_string_list().
+ */
+GSList *
+na_object_menu_get_items_list( const NAObjectMenu *menu )
+{
+	GSList *list = NULL;
+	GSList *items, *it;
+	gchar *uuid;
+
+	g_return_val_if_fail( NA_IS_OBJECT_MENU( menu ), NULL );
+	g_return_val_if_fail( !menu->private->dispose_has_run, NULL );
+
+	items = na_object_get_items( menu );
+
+	for( it = items ; it ; it = it->next ){
+		NAObjectItem *item = NA_OBJECT_ITEM( it->data );
+		uuid = na_object_get_id( item );
+		list = g_slist_prepend( list, uuid );
+	}
+
+	na_object_free_items( items );
+
+	return( g_slist_reverse( list ));
+}
+
+/**
+ *
+ */
+void
+na_object_menu_set_items_list( NAObjectMenu *menu, GSList *items )
+{
+	g_return_if_fail( NA_IS_OBJECT_MENU( menu ));
+	g_return_if_fail( !menu->private->dispose_has_run );
+
+	na_utils_free_string_list( menu->private->items_ids );
+	menu->private->items_ids = na_utils_duplicate_string_list( items );
+}
+
+static void
+object_dump( const NAObject *menu )
+{
+	static const gchar *thisfn = "na_object_menu_object_dump";
+	/*NAObjectMenu *self;*/
+
+	g_return_if_fail( NA_IS_OBJECT_MENU( menu ));
+	g_return_if_fail( !NA_OBJECT_MENU( menu )->private->dispose_has_run );
+
+	g_debug( "%s: (nothing to dump)", thisfn );
+}
+
+static gchar *
+object_get_clipboard_id( const NAObject *menu )
+{
+	gchar *uuid;
+	gchar *clipboard_id;
+
+	g_return_val_if_fail( NA_IS_OBJECT_MENU( menu ), NULL );
+	g_return_val_if_fail( !NA_OBJECT_MENU( menu )->private->dispose_has_run, NULL );
+
+	uuid = na_object_get_id( menu );
+	clipboard_id = g_strdup_printf( "M:%s", uuid );
+	g_free( uuid );
+
+	return( clipboard_id );
+}
+
 static NAObject *
 object_new( const NAObject *menu )
 {
-	return( NA_OBJECT( na_action_menu_new()));
+	return( NA_OBJECT( na_object_menu_new()));
 }
 
-void
+static void
 object_copy( NAObject *target, const NAObject *source )
 {
-	if( st_parent_class->copy ){
-		st_parent_class->copy( target, source );
-	}
-
-	g_assert( NA_IS_ACTION_MENU( source ));
-	g_assert( NA_IS_ACTION_MENU( target ));
+	g_return_if_fail( NA_IS_OBJECT_MENU( target ));
+	g_return_if_fail( !NA_OBJECT_MENU( target )->private->dispose_has_run );
+	g_return_if_fail( NA_IS_OBJECT_MENU( source ));
+	g_return_if_fail( !NA_OBJECT_MENU( source )->private->dispose_has_run );
 }
 
 static gboolean
@@ -219,35 +298,26 @@ object_are_equal( const NAObject *a, const NAObject *b )
 {
 	gboolean equal = TRUE;
 
-	if( equal ){
-		if( st_parent_class->are_equal ){
-			equal = st_parent_class->are_equal( a, b );
-		}
-	}
-
-	g_assert( NA_IS_ACTION_MENU( a ));
-	g_assert( NA_IS_ACTION_MENU( b ));
+	g_return_val_if_fail( NA_IS_OBJECT_MENU( a ), FALSE );
+	g_return_val_if_fail( !NA_OBJECT_MENU( a )->private->dispose_has_run, FALSE );
+	g_return_val_if_fail( NA_IS_OBJECT_MENU( b ), FALSE );
+	g_return_val_if_fail( !NA_OBJECT_MENU( b )->private->dispose_has_run, FALSE );
 
 	return( equal );
 }
 
 /*
- * a valid NAActionMenu requires a not null, not empty label
+ * a valid NAObjectMenu requires a not null, not empty label
  * this is checked here as NAObject doesn't have this condition
  */
-gboolean
+static gboolean
 object_is_valid( const NAObject *menu )
 {
 	gchar *label;
 	gboolean is_valid = TRUE;
 
-	if( is_valid ){
-		if( st_parent_class->is_valid ){
-			is_valid = st_parent_class->is_valid( menu );
-		}
-	}
-
-	g_assert( NA_IS_ACTION_MENU( menu ));
+	g_return_val_if_fail( NA_IS_OBJECT_MENU( menu ), FALSE );
+	g_return_val_if_fail( !NA_OBJECT_MENU( menu )->private->dispose_has_run, FALSE );
 
 	if( is_valid ){
 		label = na_object_get_label( menu );
@@ -257,32 +327,3 @@ object_is_valid( const NAObject *menu )
 
 	return( is_valid );
 }
-
-static void
-object_dump( const NAObject *menu )
-{
-	static const gchar *thisfn = "na_action_menu_object_dump";
-	/*NAActionMenu *self;*/
-
-	if( st_parent_class->dump ){
-		st_parent_class->dump( menu );
-	}
-
-	g_assert( NA_IS_ACTION_MENU( menu ));
-	/*self = NA_ACTION_MENU( menu );*/
-
-	g_debug( "%s: (nothing to dump)", thisfn );
-}
-
-static gchar *
-object_get_clipboard_id( const NAObject *menu )
-{
-	gchar *uuid;
-	gchar *clipboard_id;
-
-	uuid = na_object_get_id( menu );
-	clipboard_id = g_strdup_printf( "M:%s", uuid );
-	g_free( uuid );
-
-	return( clipboard_id );
-}
diff --git a/src/common/na-action-menu.h b/src/common/na-obj-menu.h
similarity index 50%
rename from src/common/na-action-menu.h
rename to src/common/na-obj-menu.h
index 15e380f..7552f2a 100644
--- a/src/common/na-action-menu.h
+++ b/src/common/na-obj-menu.h
@@ -28,51 +28,54 @@
  *   ... and many others (see AUTHORS)
  */
 
-#ifndef __NA_ACTION_MENU_H__
-#define __NA_ACTION_MENU_H__
+#ifndef __NA_OBJECT_MENU_H__
+#define __NA_OBJECT_MENU_H__
 
 /**
- * SECTION: na_action_menu
- * @short_description: #NAActionMenu class definition.
- * @include: common/na-action-menu.h
+ * SECTION: na_object_menu
+ * @short_description: #NAObjectMenu class definition.
+ * @include: common/na-obj-menu.h
  *
  * This is a menu.
  */
 
-#include "na-object-item.h"
+#include "na-object-item-class.h"
 
 G_BEGIN_DECLS
 
-#define NA_ACTION_MENU_TYPE					( na_action_menu_get_type())
-#define NA_ACTION_MENU( object )			( G_TYPE_CHECK_INSTANCE_CAST( object, NA_ACTION_MENU_TYPE, NAActionMenu ))
-#define NA_ACTION_MENU_CLASS( klass )		( G_TYPE_CHECK_CLASS_CAST( klass, NA_ACTION_MENU_TYPE, NAActionMenuClass ))
-#define NA_IS_ACTION_MENU( object )			( G_TYPE_CHECK_INSTANCE_TYPE( object, NA_ACTION_MENU_TYPE ))
-#define NA_IS_ACTION_MENU_CLASS( klass )	( G_TYPE_CHECK_CLASS_TYPE(( klass ), NA_ACTION_MENU_TYPE ))
-#define NA_ACTION_MENU_GET_CLASS( object )	( G_TYPE_INSTANCE_GET_CLASS(( object ), NA_ACTION_MENU_TYPE, NAActionMenuClass ))
+#define NA_OBJECT_MENU_TYPE					( na_object_menu_get_type())
+#define NA_OBJECT_MENU( object )			( G_TYPE_CHECK_INSTANCE_CAST( object, NA_OBJECT_MENU_TYPE, NAObjectMenu ))
+#define NA_OBJECT_MENU_CLASS( klass )		( G_TYPE_CHECK_CLASS_CAST( klass, NA_OBJECT_MENU_TYPE, NAObjectMenuClass ))
+#define NA_IS_OBJECT_MENU( object )			( G_TYPE_CHECK_INSTANCE_TYPE( object, NA_OBJECT_MENU_TYPE ))
+#define NA_IS_OBJECT_MENU_CLASS( klass )	( G_TYPE_CHECK_CLASS_TYPE(( klass ), NA_OBJECT_MENU_TYPE ))
+#define NA_OBJECT_MENU_GET_CLASS( object )	( G_TYPE_INSTANCE_GET_CLASS(( object ), NA_OBJECT_MENU_TYPE, NAObjectMenuClass ))
 
-typedef struct NAActionMenuPrivate NAActionMenuPrivate;
+typedef struct NAObjectMenuPrivate NAObjectMenuPrivate;
 
 typedef struct {
 	NAObjectItem         parent;
-	NAActionMenuPrivate *private;
+	NAObjectMenuPrivate *private;
 }
-	NAActionMenu;
+	NAObjectMenu;
 
-typedef struct NAActionMenuClassPrivate NAActionMenuClassPrivate;
+typedef struct NAObjectMenuClassPrivate NAObjectMenuClassPrivate;
 
 typedef struct {
 	NAObjectItemClass         parent;
-	NAActionMenuClassPrivate *private;
+	NAObjectMenuClassPrivate *private;
 }
-	NAActionMenuClass;
+	NAObjectMenuClass;
 
 /* i18n: default label for a newly created menu */
-#define NA_ACTION_MENU_DEFAULT_LABEL	_( "New Nautilus Menu" )
+#define NA_OBJECT_MENU_DEFAULT_LABEL	_( "New Nautilus menu" )
 
-GType         na_action_menu_get_type( void );
+GType         na_object_menu_get_type( void );
 
-NAActionMenu *na_action_menu_new( void );
+NAObjectMenu *na_object_menu_new( void );
+
+GSList       *na_object_menu_get_items_list( const NAObjectMenu *menu );
+void          na_object_menu_set_items_list( NAObjectMenu *menu, GSList *items );
 
 G_END_DECLS
 
-#endif /* __NA_ACTION_MENU_H__ */
+#endif /* __NA_OBJECT_MENU_H__ */
diff --git a/src/common/na-action-profile-class.h b/src/common/na-obj-profile-class.h
similarity index 52%
rename from src/common/na-action-profile-class.h
rename to src/common/na-obj-profile-class.h
index 5f8eaa7..a62ecd7 100644
--- a/src/common/na-action-profile-class.h
+++ b/src/common/na-obj-profile-class.h
@@ -28,42 +28,42 @@
  *   ... and many others (see AUTHORS)
  */
 
-#ifndef __NA_ACTION_PROFILE_CLASS_H__
-#define __NA_ACTION_PROFILE_CLASS_H__
+#ifndef __NA_OBJECT_PROFILE_CLASS_H__
+#define __NA_OBJECT_PROFILE_CLASS_H__
 
 /**
- * SECTION: na_action_profile
+ * SECTION: na_object_profile
  */
 
-#include "na-object.h"
+#include "na-object-id-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 ))
+#define NA_OBJECT_PROFILE_TYPE					( na_object_profile_get_type())
+#define NA_OBJECT_PROFILE( object )				( G_TYPE_CHECK_INSTANCE_CAST( object, NA_OBJECT_PROFILE_TYPE, NAObjectProfile ))
+#define NA_OBJECT_PROFILE_CLASS( klass )		( G_TYPE_CHECK_CLASS_CAST( klass, NA_OBJECT_PROFILE_TYPE, NAObjectProfileClass ))
+#define NA_IS_OBJECT_PROFILE( object )			( G_TYPE_CHECK_INSTANCE_TYPE( object, NA_OBJECT_PROFILE_TYPE ))
+#define NA_IS_OBJECT_PROFILE_CLASS( klass )		( G_TYPE_CHECK_CLASS_TYPE(( klass ), NA_OBJECT_PROFILE_TYPE ))
+#define NA_OBJECT_PROFILE_GET_CLASS( object )	( G_TYPE_INSTANCE_GET_CLASS(( object ), NA_OBJECT_PROFILE_TYPE, NAObjectProfileClass ))
 
-typedef struct NAActionProfilePrivate NAActionProfilePrivate;
+typedef struct NAObjectProfilePrivate NAObjectProfilePrivate;
 
 typedef struct {
-	NAObject                parent;
-	NAActionProfilePrivate *private;
+	NAObjectId              parent;
+	NAObjectProfilePrivate *private;
 }
-	NAActionProfile;
+	NAObjectProfile;
 
-typedef struct NAActionProfileClassPrivate NAActionProfileClassPrivate;
+typedef struct NAObjectProfileClassPrivate NAObjectProfileClassPrivate;
 
 typedef struct {
-	NAObjectClass                parent;
-	NAActionProfileClassPrivate *private;
+	NAObjectIdClass             parent;
+	NAObjectProfileClassPrivate *private;
 }
-	NAActionProfileClass;
+	NAObjectProfileClass;
 
-GType na_action_profile_get_type( void );
+GType na_object_profile_get_type( void );
 
 G_END_DECLS
 
-#endif /* __NA_ACTION_PROFILE_CLASS_H__ */
+#endif /* __NA_OBJECT_PROFILE_CLASS_H__ */
diff --git a/src/common/na-action-profile.c b/src/common/na-obj-profile.c
similarity index 64%
rename from src/common/na-action-profile.c
rename to src/common/na-obj-profile.c
index 2c64f83..214fd68 100644
--- a/src/common/na-action-profile.c
+++ b/src/common/na-obj-profile.c
@@ -36,69 +36,70 @@
 
 #include <libnautilus-extension/nautilus-file-info.h>
 
-#include "na-action.h"
-#include "na-action-profile.h"
+#include "na-object-api.h"
+#include "na-obj-action.h"
+#include "na-obj-profile.h"
 #include "na-utils.h"
 #include "na-gnome-vfs-uri.h"
 
 /* private class data
  */
-struct NAActionProfileClassPrivate {
+struct NAObjectProfileClassPrivate {
 	void *empty;						/* so that gcc -pedantic is happy */
 };
 
 /* private instance data
  */
-struct NAActionProfilePrivate {
-	gboolean  dispose_has_run;
+struct NAObjectProfilePrivate {
+	gboolean        dispose_has_run;
 
-	/* the NAAction object
+	/* the NAObjectAction object
 	 */
-	NAAction *action;
+	NAObjectAction *action;
 
 	/* profile properties
 	 */
-	gchar    *path;
-	gchar    *parameters;
-	GSList   *basenames;
-	gboolean  match_case;
-	GSList   *mimetypes;
-	gboolean  is_file;
-	gboolean  is_dir;
-	gboolean  accept_multiple;
-	GSList   *schemes;
+	gchar          *path;
+	gchar          *parameters;
+	GSList         *basenames;
+	gboolean        match_case;
+	GSList         *mimetypes;
+	gboolean        is_file;
+	gboolean        is_dir;
+	gboolean        accept_multiple;
+	GSList         *schemes;
 };
 
 /* profile properties
  */
 enum {
-	PROP_NAPROFILE_ACTION = 1,
-	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
+	NAPROFILE_PROP_ACTION_ID = 1,
+	NAPROFILE_PROP_PATH_ID,
+	NAPROFILE_PROP_PARAMETERS_ID,
+	NAPROFILE_PROP_BASENAMES_ID,
+	NAPROFILE_PROP_MATCHCASE_ID,
+	NAPROFILE_PROP_MIMETYPES_ID,
+	NAPROFILE_PROP_ISFILE_ID,
+	NAPROFILE_PROP_ISDIR_ID,
+	NAPROFILE_PROP_ACCEPT_MULTIPLE_ID,
+	NAPROFILE_PROP_SCHEMES_ID
 };
 
-#define PROP_NAPROFILE_ACTION_STR				"na-profile-action"
-#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"
+#define NAPROFILE_PROP_ACTION				"na-profile-action"
+#define NAPROFILE_PROP_PATH					"na-profile-path"
+#define NAPROFILE_PROP_PARAMETERS			"na-profile-parameters"
+#define NAPROFILE_PROP_BASENAMES			"na-profile-basenames"
+#define NAPROFILE_PROP_MATCHCASE			"na-profile-matchcase"
+#define NAPROFILE_PROP_MIMETYPES			"na-profile-mimetypes"
+#define NAPROFILE_PROP_ISFILE				"na-profile-isfile"
+#define NAPROFILE_PROP_ISDIR				"na-profile-isdir"
+#define NAPROFILE_PROP_ACCEPT_MULTIPLE		"na-profile-accept-multiple"
+#define NAPROFILE_PROP_SCHEMES				"na-profile-schemes"
 
 static NAObjectClass *st_parent_class = NULL;
 
 static GType     register_type( void );
-static void      class_init( NAActionProfileClass *klass );
+static void      class_init( NAObjectProfileClass *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 );
@@ -107,16 +108,16 @@ static void      instance_finalize( GObject *object );
 
 static int       validate_schemes( GSList* schemes2test, NautilusFileInfo* file );
 
+static void      object_dump( const NAObject *profile );
+static void      object_dump_list( const gchar *thisfn, const gchar *label, GSList *list );
+static gchar    *object_get_clipboard_id( const NAObject *profile );
 static NAObject *object_new( const NAObject *profile );
 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 *profile );
-static void      object_dump( const NAObject *profile );
-static void      object_dump_list( const gchar *thisfn, const gchar *label, GSList *list );
-static gchar    *object_get_clipboard_id( const NAObject *profile );
 
 GType
-na_action_profile_get_type( void )
+na_object_profile_get_type( void )
 {
 	static GType object_type = 0;
 
@@ -130,29 +131,29 @@ na_action_profile_get_type( void )
 static GType
 register_type( void )
 {
-	static const gchar *thisfn = "na_action_profile_register_type";
+	static const gchar *thisfn = "na_object_profile_register_type";
 
 	static GTypeInfo info = {
-		sizeof( NAActionProfileClass ),
+		sizeof( NAObjectProfileClass ),
 		( GBaseInitFunc ) NULL,
 		( GBaseFinalizeFunc ) NULL,
 		( GClassInitFunc ) class_init,
 		NULL,
 		NULL,
-		sizeof( NAActionProfile ),
+		sizeof( NAObjectProfile ),
 		0,
 		( GInstanceInitFunc ) instance_init
 	};
 
 	g_debug( "%s", thisfn );
 
-	return( g_type_register_static( NA_OBJECT_TYPE, "NAActionProfile", &info, 0 ));
+	return( g_type_register_static( NA_OBJECT_ID_TYPE, "NAObjectProfile", &info, 0 ));
 }
 
 static void
-class_init( NAActionProfileClass *klass )
+class_init( NAObjectProfileClass *klass )
 {
-	static const gchar *thisfn = "na_action_profile_class_init";
+	static const gchar *thisfn = "na_object_profile_class_init";
 	GObjectClass *object_class;
 	GParamSpec *spec;
 
@@ -167,96 +168,97 @@ class_init( NAActionProfileClass *klass )
 	object_class->get_property = instance_get_property;
 
 	spec = g_param_spec_pointer(
-			PROP_NAPROFILE_ACTION_STR,
+			NAPROFILE_PROP_ACTION,
 			"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 );
+	g_object_class_install_property( object_class, NAPROFILE_PROP_ACTION_ID, spec );
 
 	spec = g_param_spec_string(
-			PROP_NAPROFILE_PATH_STR,
+			NAPROFILE_PROP_PATH,
 			"Command path",
 			"Command path", "",
 			G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE );
-	g_object_class_install_property( object_class, PROP_NAPROFILE_PATH, spec );
+	g_object_class_install_property( object_class, NAPROFILE_PROP_PATH_ID, spec );
 
 	spec = g_param_spec_string(
-			PROP_NAPROFILE_PARAMETERS_STR,
+			NAPROFILE_PROP_PARAMETERS,
 			"Command parameters",
 			"Command parameters", "",
 			G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE );
-	g_object_class_install_property( object_class, PROP_NAPROFILE_PARAMETERS, spec );
+	g_object_class_install_property( object_class, NAPROFILE_PROP_PARAMETERS_ID, spec );
 
 	spec = g_param_spec_pointer(
-			PROP_NAPROFILE_BASENAMES_STR,
+			NAPROFILE_PROP_BASENAMES,
 			"Filenames mask",
 			"Filenames mask",
 			G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE );
-	g_object_class_install_property( object_class, PROP_NAPROFILE_BASENAMES, spec );
+	g_object_class_install_property( object_class, NAPROFILE_PROP_BASENAMES_ID, spec );
 
 	spec = g_param_spec_boolean(
-			PROP_NAPROFILE_MATCHCASE_STR,
+			NAPROFILE_PROP_MATCHCASE,
 			"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 );
+	g_object_class_install_property( object_class, NAPROFILE_PROP_MATCHCASE_ID, spec );
 
 	spec = g_param_spec_pointer(
-			PROP_NAPROFILE_MIMETYPES_STR,
+			NAPROFILE_PROP_MIMETYPES,
 			"Mimetypes",
 			"List of selectable mimetypes",
 			G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE );
-	g_object_class_install_property( object_class, PROP_NAPROFILE_MIMETYPES, spec );
+	g_object_class_install_property( object_class, NAPROFILE_PROP_MIMETYPES_ID, spec );
 
 	spec = g_param_spec_boolean(
-			PROP_NAPROFILE_ISFILE_STR,
+			NAPROFILE_PROP_ISFILE,
 			"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_NAPROFILE_ISFILE, spec );
+	g_object_class_install_property( object_class, NAPROFILE_PROP_ISFILE_ID, spec );
 
 	spec = g_param_spec_boolean(
-			PROP_NAPROFILE_ISDIR_STR,
+			NAPROFILE_PROP_ISDIR,
 			"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_NAPROFILE_ISDIR, spec );
+	g_object_class_install_property( object_class, NAPROFILE_PROP_ISDIR_ID, spec );
 
 	spec = g_param_spec_boolean(
-			PROP_NAPROFILE_ACCEPT_MULTIPLE_STR,
+			NAPROFILE_PROP_ACCEPT_MULTIPLE,
 			"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_NAPROFILE_ACCEPT_MULTIPLE, spec );
+	g_object_class_install_property( object_class, NAPROFILE_PROP_ACCEPT_MULTIPLE_ID, spec );
 
 	spec = g_param_spec_pointer(
-			PROP_NAPROFILE_SCHEMES_STR,
+			NAPROFILE_PROP_SCHEMES,
 			"Schemes",
 			"list of selectable schemes",
 			G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE );
-	g_object_class_install_property( object_class, PROP_NAPROFILE_SCHEMES, spec );
+	g_object_class_install_property( object_class, NAPROFILE_PROP_SCHEMES_ID, spec );
 
-	klass->private = g_new0( NAActionProfileClassPrivate, 1 );
+	klass->private = g_new0( NAObjectProfileClassPrivate, 1 );
 
+	NA_OBJECT_CLASS( klass )->dump = object_dump;
+	NA_OBJECT_CLASS( klass )->get_clipboard_id = object_get_clipboard_id;
+	NA_OBJECT_CLASS( klass )->ref = NULL;
 	NA_OBJECT_CLASS( klass )->new = object_new;
 	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;
-	NA_OBJECT_CLASS( klass )->dump = object_dump;
-	NA_OBJECT_CLASS( klass )->get_clipboard_id = object_get_clipboard_id;
 }
 
 static void
 instance_init( GTypeInstance *instance, gpointer klass )
 {
-	/*static const gchar *thisfn = "na_action_profile_instance_init";*/
-	NAActionProfile *self;
+	/*static const gchar *thisfn = "na_object_profile_instance_init";*/
+	NAObjectProfile *self;
 
 	/*g_debug( "%s: instance=%p, klass=%p", thisfn, ( void * ) instance, ( void * ) klass );*/
-	g_assert( NA_IS_ACTION_PROFILE( instance ));
-	self = NA_ACTION_PROFILE( instance );
+	g_return_if_fail( NA_IS_OBJECT_PROFILE( instance ));
+	self = NA_OBJECT_PROFILE( instance );
 
-	self->private = g_new0( NAActionProfilePrivate, 1 );
+	self->private = g_new0( NAObjectProfilePrivate, 1 );
 
 	self->private->dispose_has_run = FALSE;
 
@@ -279,52 +281,53 @@ instance_init( GTypeInstance *instance, gpointer klass )
 static void
 instance_get_property( GObject *object, guint property_id, GValue *value, GParamSpec *spec )
 {
-	NAActionProfile *self;
+	NAObjectProfile *self;
 	GSList *list;
 
-	g_assert( NA_IS_ACTION_PROFILE( object ));
-	self = NA_ACTION_PROFILE( object );
+	g_return_if_fail( NA_IS_OBJECT_PROFILE( object ));
+	g_return_if_fail( !NA_OBJECT_PROFILE( object )->private->dispose_has_run );
+	self = NA_OBJECT_PROFILE( object );
 
 	switch( property_id ){
-		case PROP_NAPROFILE_ACTION:
+		case NAPROFILE_PROP_ACTION_ID:
 			g_value_set_pointer( value, self->private->action );
 			break;
 
-		case PROP_NAPROFILE_PATH:
+		case NAPROFILE_PROP_PATH_ID:
 			g_value_set_string( value, self->private->path );
 			break;
 
-		case PROP_NAPROFILE_PARAMETERS:
+		case NAPROFILE_PROP_PARAMETERS_ID:
 			g_value_set_string( value, self->private->parameters );
 			break;
 
-		case PROP_NAPROFILE_BASENAMES:
+		case NAPROFILE_PROP_BASENAMES_ID:
 			list = na_utils_duplicate_string_list( self->private->basenames );
 			g_value_set_pointer( value, list );
 			break;
 
-		case PROP_NAPROFILE_MATCHCASE:
+		case NAPROFILE_PROP_MATCHCASE_ID:
 			g_value_set_boolean( value, self->private->match_case );
 			break;
 
-		case PROP_NAPROFILE_MIMETYPES:
+		case NAPROFILE_PROP_MIMETYPES_ID:
 			list = na_utils_duplicate_string_list( self->private->mimetypes );
 			g_value_set_pointer( value, list );
 			break;
 
-		case PROP_NAPROFILE_ISFILE:
+		case NAPROFILE_PROP_ISFILE_ID:
 			g_value_set_boolean( value, self->private->is_file );
 			break;
 
-		case PROP_NAPROFILE_ISDIR:
+		case NAPROFILE_PROP_ISDIR_ID:
 			g_value_set_boolean( value, self->private->is_dir );
 			break;
 
-		case PROP_NAPROFILE_ACCEPT_MULTIPLE:
+		case NAPROFILE_PROP_ACCEPT_MULTIPLE_ID:
 			g_value_set_boolean( value, self->private->accept_multiple );
 			break;
 
-		case PROP_NAPROFILE_SCHEMES:
+		case NAPROFILE_PROP_SCHEMES_ID:
 			list = na_utils_duplicate_string_list( self->private->schemes );
 			g_value_set_pointer( value, list );
 			break;
@@ -338,53 +341,54 @@ instance_get_property( GObject *object, guint property_id, GValue *value, GParam
 static void
 instance_set_property( GObject *object, guint property_id, const GValue *value, GParamSpec *spec )
 {
-	NAActionProfile *self;
+	NAObjectProfile *self;
 
-	g_assert( NA_IS_ACTION_PROFILE( object ));
-	self = NA_ACTION_PROFILE( object );
+	g_return_if_fail( NA_IS_OBJECT_PROFILE( object ));
+	g_return_if_fail( !NA_OBJECT_PROFILE( object )->private->dispose_has_run );
+	self = NA_OBJECT_PROFILE( object );
 
 	switch( property_id ){
-		case PROP_NAPROFILE_ACTION:
+		case NAPROFILE_PROP_ACTION_ID:
 			self->private->action = g_value_get_pointer( value );
 			break;
 
-		case PROP_NAPROFILE_PATH:
+		case NAPROFILE_PROP_PATH_ID:
 			g_free( self->private->path );
 			self->private->path = g_value_dup_string( value );
 			break;
 
-		case PROP_NAPROFILE_PARAMETERS:
+		case NAPROFILE_PROP_PARAMETERS_ID:
 			g_free( self->private->parameters );
 			self->private->parameters = g_value_dup_string( value );
 			break;
 
-		case PROP_NAPROFILE_BASENAMES:
+		case NAPROFILE_PROP_BASENAMES_ID:
 			na_utils_free_string_list( self->private->basenames );
 			self->private->basenames = na_utils_duplicate_string_list( g_value_get_pointer( value ));
 			break;
 
-		case PROP_NAPROFILE_MATCHCASE:
+		case NAPROFILE_PROP_MATCHCASE_ID:
 			self->private->match_case = g_value_get_boolean( value );
 			break;
 
-		case PROP_NAPROFILE_MIMETYPES:
+		case NAPROFILE_PROP_MIMETYPES_ID:
 			na_utils_free_string_list( self->private->mimetypes );
 			self->private->mimetypes = na_utils_duplicate_string_list( g_value_get_pointer( value ));
 			break;
 
-		case PROP_NAPROFILE_ISFILE:
+		case NAPROFILE_PROP_ISFILE_ID:
 			self->private->is_file = g_value_get_boolean( value );
 			break;
 
-		case PROP_NAPROFILE_ISDIR:
+		case NAPROFILE_PROP_ISDIR_ID:
 			self->private->is_dir = g_value_get_boolean( value );
 			break;
 
-		case PROP_NAPROFILE_ACCEPT_MULTIPLE:
+		case NAPROFILE_PROP_ACCEPT_MULTIPLE_ID:
 			self->private->accept_multiple = g_value_get_boolean( value );
 			break;
 
-		case PROP_NAPROFILE_SCHEMES:
+		case NAPROFILE_PROP_SCHEMES_ID:
 			na_utils_free_string_list( self->private->schemes );
 			self->private->schemes = na_utils_duplicate_string_list( g_value_get_pointer( value ));
 			break;
@@ -398,12 +402,12 @@ instance_set_property( GObject *object, guint property_id, const GValue *value,
 static void
 instance_dispose( GObject *object )
 {
-	/*static const gchar *thisfn = "na_action_profile_instance_dispose";*/
-	NAActionProfile *self;
+	/*static const gchar *thisfn = "na_object_profile_instance_dispose";*/
+	NAObjectProfile *self;
 
 	/*g_debug( "%s: object=%p", thisfn, ( void * ) object );*/
-	g_assert( NA_IS_ACTION_PROFILE( object ));
-	self = NA_ACTION_PROFILE( object );
+	g_return_if_fail( NA_IS_OBJECT_PROFILE( object ));
+	self = NA_OBJECT_PROFILE( object );
 
 	if( !self->private->dispose_has_run ){
 
@@ -419,12 +423,12 @@ instance_dispose( GObject *object )
 static void
 instance_finalize( GObject *object )
 {
-	/*static const gchar *thisfn = "na_action_profile_instance_finalize";*/
-	NAActionProfile *self;
+	/*static const gchar *thisfn = "na_object_profile_instance_finalize";*/
+	NAObjectProfile *self;
 
 	/*g_debug( "%s: object=%p", thisfn, (void * ) object );*/
-	g_assert( NA_IS_ACTION_PROFILE( object ));
-	self = ( NAActionProfile * ) object;
+	g_return_if_fail( NA_IS_OBJECT_PROFILE( object ));
+	self = ( NAObjectProfile * ) object;
 
 	g_free( self->private->path );
 	g_free( self->private->parameters );
@@ -441,28 +445,28 @@ instance_finalize( GObject *object )
 }
 
 /**
- * na_action_profile_new:
+ * na_object_profile_new:
  *
  * Allocates a new profile of the given name.
  *
- * Returns: the newly allocated #NAActionProfile profile.
+ * Returns: the newly allocated #NAObjectProfile profile.
  */
-NAActionProfile *
-na_action_profile_new( void )
+NAObjectProfile *
+na_object_profile_new( void )
 {
-	NAActionProfile *profile = g_object_new( NA_ACTION_PROFILE_TYPE, NULL );
+	NAObjectProfile *profile = g_object_new( NA_OBJECT_PROFILE_TYPE, NULL );
 
-	na_action_profile_set_name( profile, ACTION_PROFILE_PREFIX "zero" );
+	na_object_set_id( profile, OBJECT_PROFILE_PREFIX "zero" );
 
 	/* i18n: default label for a new profile */
-	na_action_profile_set_label( profile, NA_ACTION_PROFILE_DEFAULT_LABEL );
+	na_object_set_label( profile, NA_OBJECT_PROFILE_DEFAULT_LABEL );
 
 	return( profile );
 }
 
 /**
- * na_action_profile_get_action:
- * @profile: the #NAActionProfile to be requested.
+ * na_object_profile_get_action:
+ * @profile: the #NAObjectProfile to be requested.
  *
  * Returns a pointer to the action to which this profile is attached,
  * or NULL if the profile has never been attached.
@@ -472,55 +476,22 @@ na_action_profile_new( void )
  * Note that the returned #NAAction pointer is owned by the profile.
  * The caller should not try to g_free() nor g_object_unref() it.
  */
-NAAction *
-na_action_profile_get_action( const NAActionProfile *profile )
+NAObjectAction *
+na_object_profile_get_action( const NAObjectProfile *profile )
 {
-	NAAction *action;
+	NAObjectAction *action;
 
-	g_assert( NA_IS_ACTION_PROFILE( profile ));
+	g_return_val_if_fail( NA_IS_OBJECT_PROFILE( profile ), NULL );
+	g_return_val_if_fail( !profile->private->dispose_has_run, NULL );
 
-	g_object_get( G_OBJECT( profile ), PROP_NAPROFILE_ACTION_STR, &action, NULL );
+	g_object_get( G_OBJECT( profile ), NAPROFILE_PROP_ACTION, &action, NULL );
 
 	return( action );
 }
 
 /**
- * na_action_profile_get_name:
- * @profile: the #NAActionProfile to be requested.
- *
- * Returns the internal name (identifier) of the profile.
- *
- * Returns: the name of the profile as a newly allocated string.
- * The returned string must be g_free() by the caller.
- *
- * See na_action_profile_set_name() for some rationales about name.
- */
-gchar *
-na_action_profile_get_name( const NAActionProfile *profile )
-{
-	return( na_object_get_id( NA_OBJECT( profile )));
-}
-
-/**
- * na_action_profile_get_label:
- * @profile: the #NAActionProfile to be requested.
- *
- * Returns the descriptive name (label) of the profile.
- *
- * Returns: the label of the profile as a newly allocated string.
- * The returned string must be g_free() by the caller.
- *
- * See na_action_profile_set_label() for some rationale about label.
- */
-gchar *
-na_action_profile_get_label( const NAActionProfile *profile )
-{
-	return( na_object_get_label( NA_OBJECT( profile )));
-}
-
-/**
- * na_action_profile_get_path:
- * @profile: the #NAActionProfile to be requested.
+ * na_object_profile_get_path:
+ * @profile: the #NAObjectProfile to be requested.
  *
  * Returns the path of the command attached to the profile.
  *
@@ -528,20 +499,21 @@ na_action_profile_get_label( const NAActionProfile *profile )
  * string must be g_free() by the caller.
  */
 gchar *
-na_action_profile_get_path( const NAActionProfile *profile )
+na_object_profile_get_path( const NAObjectProfile *profile )
 {
 	gchar *path;
 
-	g_assert( NA_IS_ACTION_PROFILE( profile ));
+	g_return_val_if_fail( NA_IS_OBJECT_PROFILE( profile ), NULL );
+	g_return_val_if_fail( !profile->private->dispose_has_run, NULL );
 
-	g_object_get( G_OBJECT( profile ), PROP_NAPROFILE_PATH_STR, &path, NULL );
+	g_object_get( G_OBJECT( profile ), NAPROFILE_PROP_PATH, &path, NULL );
 
 	return( path );
 }
 
 /**
- * na_action_profile_get_parameters:
- * @profile: the #NAActionProfile to be requested.
+ * na_object_profile_get_parameters:
+ * @profile: the #NAObjectProfile to be requested.
  *
  * Returns the parameters of the command attached to the profile.
  *
@@ -549,283 +521,256 @@ na_action_profile_get_path( const NAActionProfile *profile )
  * returned string must be g_free() by the caller.
  */
 gchar *
-na_action_profile_get_parameters( const NAActionProfile *profile )
+na_object_profile_get_parameters( const NAObjectProfile *profile )
 {
 	gchar *parameters;
 
-	g_assert( NA_IS_ACTION_PROFILE( profile ));
+	g_return_val_if_fail( NA_IS_OBJECT_PROFILE( profile ), NULL );
+	g_return_val_if_fail( !profile->private->dispose_has_run, NULL );
 
-	g_object_get( G_OBJECT( profile ), PROP_NAPROFILE_PARAMETERS_STR, &parameters, NULL );
+	g_object_get( G_OBJECT( profile ), NAPROFILE_PROP_PARAMETERS, &parameters, NULL );
 
 	return( parameters );
 }
 
 /**
- * na_action_profile_get_basenames:
- * @profile: the #NAActionProfile to be requested.
+ * na_object_profile_get_basenames:
+ * @profile: the #NAObjectProfile to be requested.
  *
  * Returns the basenames of the files to which the profile applies.
  *
  * Returns: a GSList of newly allocated strings. The list must be
  * na_utils_free_string_list() by the caller.
  *
- * See na_action_profile_set_basenames() for some rationale about
+ * See na_object_profile_set_basenames() for some rationale about
  * basenames.
  */
 GSList *
-na_action_profile_get_basenames( const NAActionProfile *profile )
+na_object_profile_get_basenames( const NAObjectProfile *profile )
 {
 	GSList *basenames;
 
-	g_assert( NA_IS_ACTION_PROFILE( profile ));
+	g_return_val_if_fail( NA_IS_OBJECT_PROFILE( profile ), NULL );
+	g_return_val_if_fail( !profile->private->dispose_has_run, NULL );
 
-	g_object_get( G_OBJECT( profile ), PROP_NAPROFILE_BASENAMES_STR, &basenames, NULL );
+	g_object_get( G_OBJECT( profile ), NAPROFILE_PROP_BASENAMES, &basenames, NULL );
 
 	return( basenames );
 }
 
 /**
- * na_action_profile_get_matchcase:
- * @profile: the #NAActionProfile to be requested.
+ * na_object_profile_get_matchcase:
+ * @profile: the #NAObjectProfile to be requested.
  *
  * Are specified basenames case sensitive ?
  *
  * Returns: %TRUE if the provided filenames are case sensitive, %FALSE
  * else.
  *
- * See na_action_profile_set_matchcase() for some rationale about case
+ * See na_object_profile_set_matchcase() for some rationale about case
  * sensitivity.
  */
 gboolean
-na_action_profile_get_matchcase( const NAActionProfile *profile )
+na_object_profile_get_matchcase( const NAObjectProfile *profile )
 {
 	gboolean matchcase;
 
-	g_assert( NA_IS_ACTION_PROFILE( profile ));
+	g_return_val_if_fail( NA_IS_OBJECT_PROFILE( profile ), FALSE );
+	g_return_val_if_fail( !profile->private->dispose_has_run, FALSE );
 
-	g_object_get( G_OBJECT( profile ), PROP_NAPROFILE_MATCHCASE_STR, &matchcase, NULL );
+	g_object_get( G_OBJECT( profile ), NAPROFILE_PROP_MATCHCASE, &matchcase, NULL );
 
 	return( matchcase );
 }
 
 /**
- * na_action_profile_get_mimetypes:
- * @profile: the #NAActionProfile to be requested.
+ * na_object_profile_get_mimetypes:
+ * @profile: the #NAObjectProfile to be requested.
  *
  * Returns the list of mimetypes this profile applies to.
  *
  * Returns: a GSList of newly allocated strings. The list must be
  * na_utils_free_string_list() by the caller.
  *
- * See na_action_profile_set_mimetypes() for some rationale about
+ * See na_object_profile_set_mimetypes() for some rationale about
  * mimetypes.
  */
 GSList *
-na_action_profile_get_mimetypes( const NAActionProfile *profile )
+na_object_profile_get_mimetypes( const NAObjectProfile *profile )
 {
 	GSList *mimetypes;
 
-	g_assert( NA_IS_ACTION_PROFILE( profile ));
+	g_return_val_if_fail( NA_IS_OBJECT_PROFILE( profile ), NULL );
+	g_return_val_if_fail( !profile->private->dispose_has_run, NULL );
 
-	g_object_get( G_OBJECT( profile ), PROP_NAPROFILE_MIMETYPES_STR, &mimetypes, NULL );
+	g_object_get( G_OBJECT( profile ), NAPROFILE_PROP_MIMETYPES, &mimetypes, NULL );
 
 	return( mimetypes );
 }
 
 /**
- * na_action_profile_get_is_file:
- * @profile: the #NAActionProfile to be requested.
+ * na_object_profile_get_is_file:
+ * @profile: the #NAObjectProfile to be requested.
  *
  * 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
+ * See na_object_profile_set_isfiledir() for some rationale about file
  * selection.
  */
 gboolean
-na_action_profile_get_is_file( const NAActionProfile *profile )
+na_object_profile_get_is_file( const NAObjectProfile *profile )
 {
 	gboolean isfile;
 
-	g_assert( NA_IS_ACTION_PROFILE( profile ));
+	g_return_val_if_fail( NA_IS_OBJECT_PROFILE( profile ), FALSE );
+	g_return_val_if_fail( !profile->private->dispose_has_run, FALSE );
 
-	g_object_get( G_OBJECT( profile ), PROP_NAPROFILE_ISFILE_STR, &isfile, NULL );
+	g_object_get( G_OBJECT( profile ), NAPROFILE_PROP_ISFILE, &isfile, NULL );
 
 	return( isfile );
 }
 
 /**
- * na_action_profile_get_is_dir:
- * @profile: the #NAActionProfile to be requested.
+ * na_object_profile_get_is_dir:
+ * @profile: the #NAObjectProfile to be requested.
  *
  * Does this profile apply if the selection contains folders ?
  *
  * Returns: %TRUE if it applies, %FALSE else.
  *
- * See na_action_profile_set_isfiledir() for some rationale about file
+ * See na_object_profile_set_isfiledir() for some rationale about file
  * selection.
  */
 gboolean
-na_action_profile_get_is_dir( const NAActionProfile *profile )
+na_object_profile_get_is_dir( const NAObjectProfile *profile )
 {
 	gboolean isdir;
 
-	g_assert( NA_IS_ACTION_PROFILE( profile ));
+	g_return_val_if_fail( NA_IS_OBJECT_PROFILE( profile ), FALSE );
+	g_return_val_if_fail( !profile->private->dispose_has_run, FALSE );
 
-	g_object_get( G_OBJECT( profile ), PROP_NAPROFILE_ISDIR_STR, &isdir, NULL );
+	g_object_get( G_OBJECT( profile ), NAPROFILE_PROP_ISDIR, &isdir, NULL );
 
 	return( isdir );
 }
 
 /**
- * na_action_profile_get_multiple:
- * @profile: the #NAActionProfile to be requested.
+ * na_object_profile_get_multiple:
+ * @profile: the #NAObjectProfile to be requested.
  *
  * Does this profile apply if selection contains multiple files or
  * folders ?
  *
  * Returns: %TRUE if it applies, %FALSE else.
  *
- * See na_action_profile_set_multiple() for some rationale about
+ * See na_object_profile_set_multiple() for some rationale about
  * multiple selection.
  */
 gboolean
-na_action_profile_get_multiple( const NAActionProfile *profile )
+na_object_profile_get_multiple( const NAObjectProfile *profile )
 {
 	gboolean multiple;
 
-	g_assert( NA_IS_ACTION_PROFILE( profile ));
+	g_return_val_if_fail( NA_IS_OBJECT_PROFILE( profile ), FALSE );
+	g_return_val_if_fail( !profile->private->dispose_has_run, FALSE );
 
-	g_object_get( G_OBJECT( profile ), PROP_NAPROFILE_ACCEPT_MULTIPLE_STR, &multiple, NULL );
+	g_object_get( G_OBJECT( profile ), NAPROFILE_PROP_ACCEPT_MULTIPLE, &multiple, NULL );
 
 	return( multiple );
 }
 
 /**
- * na_action_profile_get_schemes:
- * @profile: the #NAActionProfile to be requested.
+ * na_object_profile_get_schemes:
+ * @profile: the #NAObjectProfile to be requested.
  *
  * Returns the list of schemes this profile applies to.
  *
  * Returns: a GSList of newly allocated strings. The list must be
  * na_utils_free_string_list() by the caller.
  *
- * See na_action_profile_set_schemes() for some rationale about
+ * See na_object_profile_set_schemes() for some rationale about
  * schemes.
  */
 GSList *
-na_action_profile_get_schemes( const NAActionProfile *profile )
+na_object_profile_get_schemes( const NAObjectProfile *profile )
 {
 	GSList *schemes;
 
-	g_assert( NA_IS_ACTION_PROFILE( profile ));
+	g_return_val_if_fail( NA_IS_OBJECT_PROFILE( profile ), NULL );
+	g_return_val_if_fail( !profile->private->dispose_has_run, NULL );
 
-	g_object_get( G_OBJECT( profile ), PROP_NAPROFILE_SCHEMES_STR, &schemes, NULL );
+	g_object_get( G_OBJECT( profile ), NAPROFILE_PROP_SCHEMES, &schemes, NULL );
 
 	return( schemes );
 }
 
 /**
- * na_action_profile_set_action:
- * @profile: the #NAActionProfile to be updated.
+ * na_object_profile_set_action:
+ * @profile: the #NAObjectProfile to be updated.
  * @action: the #NAAction action to which this profile is attached.
  *
  * Sets the action to which this profile is attached.
- */
-void
-na_action_profile_set_action( NAActionProfile *profile, const NAAction *action )
-{
-	g_assert( NA_IS_ACTION_PROFILE( profile ));
-
-	g_object_set( G_OBJECT( profile ), PROP_NAPROFILE_ACTION_STR, action, NULL );
-}
-
-/**
- * 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.
+ * The reference count of the @action is not modified.
  */
 void
-na_action_profile_set_name( NAActionProfile *profile, const gchar *name )
+na_object_profile_set_action( NAObjectProfile *profile, const NAObjectAction *action )
 {
-	na_object_set_id( NA_OBJECT( profile ), name );
-}
+	g_return_if_fail( NA_IS_OBJECT_PROFILE( profile ));
+	g_return_if_fail( !profile->private->dispose_has_run );
+	g_return_if_fail( NA_IS_OBJECT_ACTION( action ));
 
-/**
- * na_action_profile_set_label:
- * @profile: the #NAActionProfile to be updated.
- * @label: the label to be set.
- *
- * Sets the label for this profile.
- *
- * #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 )
-{
-	na_object_set_label( NA_OBJECT( profile ), label );
+	g_object_set( G_OBJECT( profile ), NAPROFILE_PROP_ACTION, action, NULL );
 }
 
 /**
- * na_action_profile_set_path:
- * @profile: the #NAActionProfile to be updated.
+ * na_object_profile_set_path:
+ * @profile: the #NAObjectProfile to be updated.
  * @path: the command path to be set.
  *
  * Sets the path of the command for this profile.
  *
- * #NAActionProfile takes a copy of the provided path. This later may
+ * #NAObjectProfile 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 )
+na_object_profile_set_path( NAObjectProfile *profile, const gchar *path )
 {
-	g_assert( NA_IS_ACTION_PROFILE( profile ));
+	g_return_if_fail( NA_IS_OBJECT_PROFILE( profile ));
+	g_return_if_fail( !profile->private->dispose_has_run );
 
-	g_object_set( G_OBJECT( profile ), PROP_NAPROFILE_PATH_STR, path, NULL );
+	g_object_set( G_OBJECT( profile ), NAPROFILE_PROP_PATH, path, NULL );
 }
 
 /**
- * na_action_profile_set_parameters:
- * @profile: the #NAActionProfile to be updated.
+ * na_object_profile_set_parameters:
+ * @profile: the #NAObjectProfile to be updated.
  * @parameters : the command parameters to be set.
  *
  * Sets the parameters of the command for this profile.
  *
- * #NAActionProfile takes a copy of the provided parameters. This later
+ * #NAObjectProfile 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 )
+na_object_profile_set_parameters( NAObjectProfile *profile, const gchar *parameters )
 {
-	g_assert( NA_IS_ACTION_PROFILE( profile ));
+	g_return_if_fail( NA_IS_OBJECT_PROFILE( profile ));
+	g_return_if_fail( !profile->private->dispose_has_run );
 
-	g_object_set( G_OBJECT( profile ), PROP_NAPROFILE_PARAMETERS_STR, parameters, NULL );
+	g_object_set( G_OBJECT( profile ), NAPROFILE_PROP_PARAMETERS, parameters, NULL );
 }
 
 /**
- * na_action_profile_set_basenames:
- * @profile: the #NAActionProfile to be updated.
+ * na_object_profile_set_basenames:
+ * @profile: the #NAObjectProfile to be updated.
  * @basenames : the basenames to be set.
  *
  * Sets the basenames of the elements on which this profile applies.
  *
- * #NAActionProfile takes a copy of the provided basenames. This later
+ * #NAObjectProfile takes a copy of the provided basenames. This later
  * may so be na_utils_free_string_list() by the caller after this
  * function returns.
  *
@@ -833,16 +778,17 @@ na_action_profile_set_parameters( NAActionProfile *profile, const gchar *paramet
  * that the profile will apply to all basenames.
  */
 void
-na_action_profile_set_basenames( NAActionProfile *profile, GSList *basenames )
+na_object_profile_set_basenames( NAObjectProfile *profile, GSList *basenames )
 {
-	g_assert( NA_IS_ACTION_PROFILE( profile ));
+	g_return_if_fail( NA_IS_OBJECT_PROFILE( profile ));
+	g_return_if_fail( !profile->private->dispose_has_run );
 
-	g_object_set( G_OBJECT( profile ), PROP_NAPROFILE_BASENAMES_STR, basenames, NULL );
+	g_object_set( G_OBJECT( profile ), NAPROFILE_PROP_BASENAMES, basenames, NULL );
 }
 
 /**
- * na_action_profile_set_matchcase:
- * @profile: the #NAActionProfile to be updated.
+ * na_object_profile_set_matchcase:
+ * @profile: the #NAObjectProfile to be updated.
  * @matchcase : whether the basenames are case sensitive or not.
  *
  * Sets the 'match_case' flag, indicating if specified basename
@@ -852,21 +798,22 @@ na_action_profile_set_basenames( NAActionProfile *profile, GSList *basenames )
  * default to be case sensitive.
  */
 void
-na_action_profile_set_matchcase( NAActionProfile *profile, gboolean matchcase )
+na_object_profile_set_matchcase( NAObjectProfile *profile, gboolean matchcase )
 {
-	g_assert( NA_IS_ACTION_PROFILE( profile ));
+	g_return_if_fail( NA_IS_OBJECT_PROFILE( profile ));
+	g_return_if_fail( !profile->private->dispose_has_run );
 
-	g_object_set( G_OBJECT( profile ), PROP_NAPROFILE_MATCHCASE_STR, matchcase, NULL );
+	g_object_set( G_OBJECT( profile ), NAPROFILE_PROP_MATCHCASE, matchcase, NULL );
 }
 
 /**
- * na_action_profile_set_mimetypes:
- * @profile: the #NAActionProfile to be updated.
+ * na_object_profile_set_mimetypes:
+ * @profile: the #NAObjectProfile to be updated.
  * @mimetypes: list of mimetypes to be matched.
  *
  * Sets the mimetypes on which this profile applies.
  *
- * #NAActionProfile takes a copy of the provided mimetypes. This later
+ * #NAObjectProfile takes a copy of the provided mimetypes. This later
  * may so be na_utils_free_string_list() by the caller after this
  * function returns.
  *
@@ -874,46 +821,49 @@ na_action_profile_set_matchcase( NAActionProfile *profile, gboolean matchcase )
  * means that the profile will apply to all types of files.
  */
 void
-na_action_profile_set_mimetypes( NAActionProfile *profile, GSList *mimetypes )
+na_object_profile_set_mimetypes( NAObjectProfile *profile, GSList *mimetypes )
 {
-	g_assert( NA_IS_ACTION_PROFILE( profile ));
+	g_return_if_fail( NA_IS_OBJECT_PROFILE( profile ));
+	g_return_if_fail( !profile->private->dispose_has_run );
 
-	g_object_set( G_OBJECT( profile ), PROP_NAPROFILE_MIMETYPES_STR, mimetypes, NULL );
+	g_object_set( G_OBJECT( profile ), NAPROFILE_PROP_MIMETYPES, mimetypes, NULL );
 }
 
 /**
- * na_action_profile_set_isfile:
- * @profile: the #NAActionProfile to be updated.
+ * na_object_profile_set_isfile:
+ * @profile: the #NAObjectProfile to be updated.
  * @isfile: whether 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 )
+na_object_profile_set_isfile( NAObjectProfile *profile, gboolean isfile )
 {
-	g_assert( NA_IS_ACTION_PROFILE( profile ));
+	g_return_if_fail( NA_IS_OBJECT_PROFILE( profile ));
+	g_return_if_fail( !profile->private->dispose_has_run );
 
-	g_object_set( G_OBJECT( profile ), PROP_NAPROFILE_ISFILE_STR, isfile, NULL );
+	g_object_set( G_OBJECT( profile ), NAPROFILE_PROP_ISFILE, isfile, NULL );
 }
 
 /**
- * na_action_profile_set_isdir:
- * @profile: the #NAActionProfile to be updated.
+ * na_object_profile_set_isdir:
+ * @profile: the #NAObjectProfile 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 )
+na_object_profile_set_isdir( NAObjectProfile *profile, gboolean isdir )
 {
-	g_assert( NA_IS_ACTION_PROFILE( profile ));
+	g_return_if_fail( NA_IS_OBJECT_PROFILE( profile ));
+	g_return_if_fail( !profile->private->dispose_has_run );
 
-	g_object_set( G_OBJECT( profile ), PROP_NAPROFILE_ISDIR_STR, isdir, NULL );
+	g_object_set( G_OBJECT( profile ), NAPROFILE_PROP_ISDIR, isdir, NULL );
 }
 
 /**
- * na_action_profile_set_isfiledir:
- * @profile: the #NAActionProfile to be updated.
+ * na_object_profile_set_isfiledir:
+ * @profile: the #NAObjectProfile to be updated.
  * @isfile: whether the profile applies only to files.
  * @isdir: the profile applies only to folders.
  *
@@ -925,16 +875,17 @@ na_action_profile_set_isdir( NAActionProfile *profile, gboolean isdir )
  * not apply if the selection contains folders.
  */
 void
-na_action_profile_set_isfiledir( NAActionProfile *profile, gboolean isfile, gboolean isdir )
+na_object_profile_set_isfiledir( NAObjectProfile *profile, gboolean isfile, gboolean isdir )
 {
-	g_assert( NA_IS_ACTION_PROFILE( profile ));
+	g_return_if_fail( NA_IS_OBJECT_PROFILE( profile ));
+	g_return_if_fail( !profile->private->dispose_has_run );
 
-	g_object_set( G_OBJECT( profile ), PROP_NAPROFILE_ISFILE_STR, isfile, PROP_NAPROFILE_ISDIR_STR, isdir, NULL );
+	g_object_set( G_OBJECT( profile ), NAPROFILE_PROP_ISFILE, isfile, NAPROFILE_PROP_ISDIR, isdir, NULL );
 }
 
 /**
- * na_action_profile_set_multiple:
- * @profile: the #NAActionProfile to be updated.
+ * na_object_profile_set_multiple:
+ * @profile: the #NAObjectProfile to be updated.
  * @multiple: TRUE if it does.
  *
  * Sets if this profile accept multiple selection ?
@@ -943,28 +894,30 @@ na_action_profile_set_isfiledir( NAActionProfile *profile, gboolean isfile, gboo
  * not apply if the selection contains more than one element.
  */
 void
-na_action_profile_set_multiple( NAActionProfile *profile, gboolean multiple )
+na_object_profile_set_multiple( NAObjectProfile *profile, gboolean multiple )
 {
-	g_assert( NA_IS_ACTION_PROFILE( profile ));
+	g_return_if_fail( NA_IS_OBJECT_PROFILE( profile ));
+	g_return_if_fail( !profile->private->dispose_has_run );
 
-	g_object_set( G_OBJECT( profile ), PROP_NAPROFILE_ACCEPT_MULTIPLE_STR, multiple, NULL );
+	g_object_set( G_OBJECT( profile ), NAPROFILE_PROP_ACCEPT_MULTIPLE, multiple, NULL );
 }
 
 /**
- * na_action_profile_set_scheme:
- * @profile: the #NAActionProfile to be updated.
+ * na_object_profile_set_scheme:
+ * @profile: the #NAObjectProfile 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 )
+na_object_profile_set_scheme( NAObjectProfile *profile, const gchar *scheme, gboolean selected )
 {
-	/*static const gchar *thisfn = "na_action_profile_set_scheme";*/
+	/*static const gchar *thisfn = "na_object_profile_set_scheme";*/
 	gboolean exist;
 
-	g_assert( NA_IS_ACTION_PROFILE( profile ));
+	g_return_if_fail( NA_IS_OBJECT_PROFILE( profile ));
+	g_return_if_fail( !profile->private->dispose_has_run );
 
 	exist = na_utils_find_in_list( profile->private->schemes, scheme );
 	/*g_debug( "%s: scheme=%s exist=%s", thisfn, scheme, exist ? "True":"False" );*/
@@ -978,13 +931,13 @@ na_action_profile_set_scheme( NAActionProfile *profile, const gchar *scheme, gbo
 }
 
 /**
- * na_action_profile_set_schemes:
- * @profile: the #NAActionProfile to be updated.
+ * na_object_profile_set_schemes:
+ * @profile: the #NAObjectProfile to be updated.
  * @schemes: list of schemes which apply.
  *
  * Sets the schemes on which this profile applies.
  *
- * #NAActionProfile takes a copy of the provided mimetypes. This later
+ * #NAObjectProfile takes a copy of the provided mimetypes. This later
  * may so be na_utils_free_string_list() by the caller after this
  * function returns.
  *
@@ -992,16 +945,17 @@ na_action_profile_set_scheme( NAActionProfile *profile, const gchar *scheme, gbo
  * that the profile will only apply to local files.
  */
 void
-na_action_profile_set_schemes( NAActionProfile *profile, GSList *schemes )
+na_object_profile_set_schemes( NAObjectProfile *profile, GSList *schemes )
 {
-	g_assert( NA_IS_ACTION_PROFILE( profile ));
+	g_return_if_fail( NA_IS_OBJECT_PROFILE( profile ));
+	g_return_if_fail( !profile->private->dispose_has_run );
 
-	g_object_set( G_OBJECT( profile ), PROP_NAPROFILE_SCHEMES_STR, schemes, NULL );
+	g_object_set( G_OBJECT( profile ), NAPROFILE_PROP_SCHEMES, schemes, NULL );
 }
 
 /**
- * na_action_profile_is_candidate:
- * @profile: the #NAActionProfile to be checked.
+ * na_object_profile_is_candidate:
+ * @profile: the #NAObjectProfile to be checked.
  * @files: the currently selected items, as provided by Nautilus.
  *
  * Determines if the given profile is candidate to be displayed in the
@@ -1013,7 +967,7 @@ na_action_profile_set_schemes( NAActionProfile *profile, GSList *schemes )
  * else.
  */
 gboolean
-na_action_profile_is_candidate( const NAActionProfile *profile, GList* files )
+na_object_profile_is_candidate( const NAObjectProfile *profile, GList* files )
 {
 	gboolean retv = FALSE;
 	gboolean test_multiple_file = FALSE;
@@ -1036,7 +990,8 @@ na_action_profile_is_candidate( const NAActionProfile *profile, GList* files )
 	gboolean mimetype_match_ok = FALSE;
 	gchar *tmp_pattern, *tmp_filename, *tmp_filename2, *tmp_mimetype, *tmp_mimetype2;
 
-	g_assert( NA_IS_ACTION_PROFILE( profile ));
+	g_return_val_if_fail( NA_IS_OBJECT_PROFILE( profile ), FALSE );
+	g_return_val_if_fail( !profile->private->dispose_has_run, FALSE );
 
 	if (profile->private->basenames && profile->private->basenames->next != NULL &&
 			g_ascii_strcasecmp ((gchar*)(profile->private->basenames->data), "*") == 0)
@@ -1255,13 +1210,13 @@ na_action_profile_is_candidate( const NAActionProfile *profile, GList* files )
  * %% : a percent sign
  *
  * Adding a parameter requires updating of :
- * - src/common/na/na-action-profile.c:na_action_profile_parse_parameters()
+ * - src/common/na/na-action-profile.c:na_object_profile_parse_parameters()
  * - src/common/na/na-xml-names.h
  * - src/nact/nact-icommand-tab.c:parse_parameters()
  * - src/nact/nautilus-actions-config-tool.ui:LegendDialog
  */
 gchar *
-na_action_profile_parse_parameters( const NAActionProfile *profile, GList* files )
+na_object_profile_parse_parameters( const NAObjectProfile *profile, GList* files )
 {
 	gchar *parsed = NULL;
 	GString *string;
@@ -1280,7 +1235,8 @@ na_action_profile_parse_parameters( const NAActionProfile *profile, GList* files
 	gchar *tmp, *iter, *old_iter;
 	NAGnomeVFSURI *vfs;
 
-	g_return_val_if_fail( NA_IS_ACTION_PROFILE( profile ), NULL );
+	g_return_val_if_fail( NA_IS_OBJECT_PROFILE( profile ), NULL );
+	g_return_val_if_fail( !profile->private->dispose_has_run, NULL );
 
 	string = g_string_new( "" );
 	basename_list = g_string_new( "" );
@@ -1457,10 +1413,59 @@ validate_schemes( GSList* schemes2test, NautilusFileInfo* file )
 	return retv;
 }
 
+static void
+object_dump( const NAObject *object )
+{
+	static const gchar *thisfn = "na_object_profile_object_dump";
+	NAObjectProfile *self;
+
+	g_return_if_fail( NA_IS_OBJECT_PROFILE( object ));
+	g_return_if_fail( !NA_OBJECT_PROFILE( object )->private->dispose_has_run );
+	self = NA_OBJECT_PROFILE( object );
+
+	g_debug( "%s:          action=%p", thisfn, ( void * ) 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 gchar *
+object_get_clipboard_id( const NAObject *profile )
+{
+	gchar *uuid;
+	gchar *name;
+	gchar *clipboard_id;
+
+	g_return_val_if_fail( NA_IS_OBJECT_PROFILE( profile ), NULL );
+	g_return_val_if_fail( !NA_OBJECT_PROFILE( profile )->private->dispose_has_run, NULL );
+
+	uuid = na_object_get_id( NA_OBJECT_PROFILE( profile )->private->action );
+	name = na_object_get_id( profile );
+	clipboard_id = g_strdup_printf( "P:%s/%s", uuid, name );
+	g_free( uuid );
+	g_free( name );
+
+	return( clipboard_id );
+}
+
 static NAObject *
 object_new( const NAObject *profile )
 {
-	return( NA_OBJECT( na_action_profile_new()));
+	return( NA_OBJECT( na_object_profile_new()));
 }
 
 static void
@@ -1470,35 +1475,33 @@ object_copy( NAObject *target, const NAObject *source )
 	gboolean matchcase, isfile, isdir, multiple;
 	GSList *basenames, *mimetypes, *schemes;
 
-	if( st_parent_class->copy ){
-		st_parent_class->copy( target, source );
-	}
-
-	g_assert( NA_IS_ACTION_PROFILE( target ));
-	g_assert( NA_IS_ACTION_PROFILE( source ));
+	g_return_if_fail( NA_IS_OBJECT_PROFILE( target ));
+	g_return_if_fail( !NA_OBJECT_PROFILE( target )->private->dispose_has_run );
+	g_return_if_fail( NA_IS_OBJECT_PROFILE( source ));
+	g_return_if_fail( !NA_OBJECT_PROFILE( source )->private->dispose_has_run );
 
 	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,
+			NAPROFILE_PROP_PATH, &path,
+			NAPROFILE_PROP_PARAMETERS, &parameters,
+			NAPROFILE_PROP_BASENAMES, &basenames,
+			NAPROFILE_PROP_MATCHCASE, &matchcase,
+			NAPROFILE_PROP_MIMETYPES, &mimetypes,
+			NAPROFILE_PROP_ISFILE, &isfile,
+			NAPROFILE_PROP_ISDIR, &isdir,
+			NAPROFILE_PROP_ACCEPT_MULTIPLE, &multiple,
+			NAPROFILE_PROP_SCHEMES, &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,
+			NAPROFILE_PROP_PATH, path,
+			NAPROFILE_PROP_PARAMETERS, parameters,
+			NAPROFILE_PROP_BASENAMES, basenames,
+			NAPROFILE_PROP_MATCHCASE, matchcase,
+			NAPROFILE_PROP_MIMETYPES, mimetypes,
+			NAPROFILE_PROP_ISFILE, isfile,
+			NAPROFILE_PROP_ISDIR, isdir,
+			NAPROFILE_PROP_ACCEPT_MULTIPLE, multiple,
+			NAPROFILE_PROP_SCHEMES, schemes,
 			NULL );
 
 	g_free( path );
@@ -1511,18 +1514,14 @@ object_copy( NAObject *target, const NAObject *source )
 gboolean
 object_are_equal( const NAObject *a, const NAObject *b )
 {
-	NAActionProfile *first = NA_ACTION_PROFILE( a );
-	NAActionProfile *second = NA_ACTION_PROFILE( b );
+	NAObjectProfile *first = NA_OBJECT_PROFILE( a );
+	NAObjectProfile *second = NA_OBJECT_PROFILE( b );
 	gboolean equal = TRUE;
 
-	if( equal ){
-		if( st_parent_class->are_equal ){
-			equal = st_parent_class->are_equal( a, b );
-		}
-	}
-
-	g_assert( NA_IS_ACTION_PROFILE( a ));
-	g_assert( NA_IS_ACTION_PROFILE( b ));
+	g_return_val_if_fail( NA_IS_OBJECT_PROFILE( a ), FALSE );
+	g_return_val_if_fail( !NA_OBJECT_PROFILE( a )->private->dispose_has_run, FALSE );
+	g_return_val_if_fail( NA_IS_OBJECT_PROFILE( b ), FALSE );
+	g_return_val_if_fail( !NA_OBJECT_PROFILE( b )->private->dispose_has_run, FALSE );
 
 	if( equal ){
 		equal =
@@ -1555,7 +1554,7 @@ object_are_equal( const NAObject *a, const NAObject *b )
 }
 
 /*
- * a valid NAActionProfile requires a not null, not empty label
+ * a valid NAObjectProfile requires a not null, not empty label
  * this is checked here as NAObject doesn't have this condition
  */
 gboolean
@@ -1564,13 +1563,8 @@ object_is_valid( const NAObject *profile )
 	gchar *label;
 	gboolean is_valid = TRUE;
 
-	if( is_valid ){
-		if( st_parent_class->is_valid ){
-			is_valid = st_parent_class->is_valid( profile );
-		}
-	}
-
-	g_assert( NA_IS_ACTION_PROFILE( profile ));
+	g_return_val_if_fail( NA_IS_OBJECT_PROFILE( profile ), FALSE );
+	g_return_val_if_fail( !NA_OBJECT_PROFILE( profile )->private->dispose_has_run, FALSE );
 
 	if( is_valid ){
 		label = na_object_get_label( profile );
@@ -1580,52 +1574,3 @@ object_is_valid( const NAObject *profile )
 
 	return( is_valid );
 }
-
-static void
-object_dump( const NAObject *object )
-{
-	static const gchar *thisfn = "na_action_profile_object_dump";
-	NAActionProfile *self;
-
-	g_assert( NA_IS_ACTION_PROFILE( object ));
-	self = NA_ACTION_PROFILE( object );
-
-	if( st_parent_class->dump ){
-		st_parent_class->dump( object );
-	}
-
-	g_debug( "%s:          action=%p", thisfn, ( void * ) 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 gchar *
-object_get_clipboard_id( const NAObject *profile )
-{
-	gchar *uuid;
-	gchar *name;
-	gchar *clipboard_id;
-
-	uuid = na_action_get_uuid( NA_ACTION_PROFILE( profile )->private->action );
-	name = na_object_get_id( profile );
-	clipboard_id = g_strdup_printf( "P:%s/%s", uuid, name );
-	g_free( uuid );
-	g_free( name );
-
-	return( clipboard_id );
-}
diff --git a/src/common/na-obj-profile.h b/src/common/na-obj-profile.h
new file mode 100644
index 0000000..91d62ff
--- /dev/null
+++ b/src/common/na-obj-profile.h
@@ -0,0 +1,88 @@
+/*
+ * 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_OBJECT_PROFILE_H__
+#define __NA_OBJECT_PROFILE_H__
+
+/**
+ * SECTION: na_object_profile
+ * @short_description: #NAObjectProfile class definition.
+ * @include: common/na-obj-profile.h
+ *
+ * This is a companion class of NAObjectAction. It embeds the profile
+ * definition of an action.
+ *
+ * As NAObjectAction itself, NAObjectProfile class is derived from
+ * NAObject class, which takes care of IDuplicable interface management.
+ */
+
+#include "na-obj-action-class.h"
+#include "na-obj-profile-class.h"
+
+G_BEGIN_DECLS
+
+/* 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 OBJECT_PROFILE_PREFIX			"profile-"
+
+NAObjectProfile *na_object_profile_new( void );
+
+NAObjectAction  *na_object_profile_get_action( const NAObjectProfile *profile );
+gchar           *na_object_profile_get_path( const NAObjectProfile *profile );
+gchar           *na_object_profile_get_parameters( const NAObjectProfile *profile );
+GSList          *na_object_profile_get_basenames( const NAObjectProfile *profile );
+gboolean         na_object_profile_get_matchcase( const NAObjectProfile *profile );
+GSList          *na_object_profile_get_mimetypes( const NAObjectProfile *profile );
+gboolean         na_object_profile_get_is_file( const NAObjectProfile *profile );
+gboolean         na_object_profile_get_is_dir( const NAObjectProfile *profile );
+gboolean         na_object_profile_get_multiple( const NAObjectProfile *profile );
+GSList          *na_object_profile_get_schemes( const NAObjectProfile *profile );
+
+void             na_object_profile_set_action( NAObjectProfile *profile, const NAObjectAction *action );
+void             na_object_profile_set_path( NAObjectProfile *profile, const gchar *path );
+void             na_object_profile_set_parameters( NAObjectProfile *profile, const gchar *parameters );
+void             na_object_profile_set_basenames( NAObjectProfile *profile, GSList *basenames );
+void             na_object_profile_set_matchcase( NAObjectProfile *profile, gboolean matchcase );
+void             na_object_profile_set_mimetypes( NAObjectProfile *profile, GSList *mimetypes );
+void             na_object_profile_set_isfile( NAObjectProfile *profile, gboolean isfile );
+void             na_object_profile_set_isdir( NAObjectProfile *profile, gboolean isdir );
+void             na_object_profile_set_isfiledir( NAObjectProfile *profile, gboolean isfile, gboolean isdir );
+void             na_object_profile_set_multiple( NAObjectProfile *profile, gboolean multiple );
+void             na_object_profile_set_scheme( NAObjectProfile *profile, const gchar *scheme, gboolean selected );
+void             na_object_profile_set_schemes( NAObjectProfile *profile, GSList *schemes );
+
+gboolean         na_object_profile_is_candidate( const NAObjectProfile *profile, GList *files );
+gchar           *na_object_profile_parse_parameters( const NAObjectProfile *profile, GList *files );
+
+G_END_DECLS
+
+#endif /* __NA_OBJECT_PROFILE_H__ */
diff --git a/src/common/na-object-api.h b/src/common/na-object-api.h
new file mode 100644
index 0000000..ac61cd9
--- /dev/null
+++ b/src/common/na-object-api.h
@@ -0,0 +1,98 @@
+/*
+ * 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_OBJECT_API_H__
+#define __NA_OBJECT_API_H__
+
+/**
+ * SECTION: na_object
+ * @short_description: #NAObject public API.
+ * @include: common/na-object-api.h
+ */
+
+#include "na-object-fn.h"
+#include "na-object-id-fn.h"
+#include "na-object-item-fn.h"
+
+G_BEGIN_DECLS
+
+/* NAObject
+ */
+#define na_object_dump( object )					na_object_object_dump( NA_OBJECT( object ))
+#define na_object_get_clipboard_id( object )		na_object_object_get_clipboard_id( NA_OBJECT( object ))
+#define na_object_ref( object )						na_object_object_ref( NA_OBJECT( object ))
+#define na_object_copy( target, source )			na_object_object_copy( NA_OBJECT( target ), NA_OBJECT( source ))
+
+/* NAIDuplicable
+ */
+#define na_object_duplicate( object )				na_object_iduplicable_duplicate( NA_OBJECT( object ))
+
+#define na_object_check_edition_status( object )	na_object_iduplicable_check_edition_status( NA_OBJECT( object ))
+#define na_object_are_equal( a, b )					na_object_iduplicable_are_equal( NA_OBJECT( a ), NA_OBJECT( b ))
+#define na_object_is_modified( object )				na_object_iduplicable_is_modified( NA_OBJECT( object ))
+#define na_object_is_valid( object )				na_object_iduplicable_is_valid( NA_OBJECT( object ))
+
+#define na_object_get_origin( object )				na_object_iduplicable_get_origin( NA_OBJECT( object ))
+#define na_object_set_origin( object, origin )		na_object_iduplicable_set_origin( NA_OBJECT( object ), NA_OBJECT( origin ))
+
+/* NAObjectId
+ */
+#define na_object_get_id( object )					na_object_id_get_id( NA_OBJECT_ID( object ))
+#define na_object_get_label( object )				na_object_id_get_label( NA_OBJECT_ID( object ))
+
+#define na_object_set_id( object, id )				na_object_id_set_id( NA_OBJECT_ID( object ), id )
+#define na_object_set_new_id( object, id )			na_object_id_set_new_id( NA_OBJECT_ID( object ), id )
+#define na_object_set_label( object, label )		na_object_id_set_label( NA_OBJECT_ID( object ), label )
+
+/* NAObjectItem
+ */
+#define na_object_get_tooltip( object )				na_object_item_get_tooltip( NA_OBJECT_ITEM( object ))
+#define na_object_get_icon( object )				na_object_item_get_icon( NA_OBJECT_ITEM( object ))
+#define na_object_get_pixbuf( object )				na_object_item_get_pixbuf( NA_OBJECT_ITEM( object ))
+#define na_object_get_provider( object )			na_object_item_get_provider( NA_OBJECT_ITEM( object ))
+#define na_object_is_enabled( object )				na_object_item_is_enabled( NA_OBJECT_ITEM( object ))
+#define na_object_get_item( object, id )			na_object_item_get_item( NA_OBJECT_ITEM( object ), id )
+#define na_object_get_items( object )				na_object_item_get_items( NA_OBJECT_ITEM( object ))
+#define na_object_get_items_count( object )			na_object_item_get_items_count( NA_OBJECT_ITEM( object ))
+#define na_object_free_items( list )				na_object_item_free_items( list )
+
+#define na_object_set_tooltip( object, tooltip )	na_object_item_set_tooltip( NA_OBJECT_ITEM( object ), tooltip )
+#define na_object_set_icon( object, icon )			na_object_item_set_icon( NA_OBJECT_ITEM( object ), icon )
+#define na_object_set_provider( object, provider )	na_object_item_set_provider( NA_OBJECT_ITEM( object ), provider )
+#define na_object_set_enabled( object, enabled )	na_object_item_set_enabled( NA_OBJECT_ITEM( object ), enabled )
+#define na_object_set_items( object, list )			na_object_item_set_items( NA_OBJECT_ITEM( object ), list )
+
+#define na_object_append_item( object, item )		na_object_item_append_item( NA_OBJECT_ITEM( object ), NA_OBJECT( item ))
+#define na_object_insert_item( object, item )		na_object_item_insert_item( NA_OBJECT_ITEM( object ), NA_OBJECT( item ))
+#define na_object_remove_item( object, item )		na_object_item_remove_item( NA_OBJECT_ITEM( object ), NA_OBJECT( item ))
+
+G_END_DECLS
+
+#endif /* __NA_OBJECT_API_H__ */
diff --git a/src/common/na-object.h b/src/common/na-object-class.h
similarity index 51%
rename from src/common/na-object.h
rename to src/common/na-object-class.h
index af63318..78a48ee 100644
--- a/src/common/na-object.h
+++ b/src/common/na-object-class.h
@@ -28,23 +28,19 @@
  *   ... and many others (see AUTHORS)
  */
 
-#ifndef __NA_OBJECT_H__
-#define __NA_OBJECT_H__
+#ifndef __NA_OBJECT_CLASS_H__
+#define __NA_OBJECT_CLASS_H__
 
 /**
  * SECTION: na_object
  * @short_description: #NAObject class definition.
- * @include: common/na-object.h
+ * @include: common/na-object-class.h
  *
- * This is the base class for NAAction and NActionProfile.
+ * This is the base class for managed objects.
  *
  * 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.
  */
 
@@ -74,12 +70,59 @@ typedef struct {
 	NAObjectClassPrivate *private;
 
 	/**
+	 * dump:
+	 * @object: the #NAObject-derived object to be dumped.
+	 *
+	 * Dumps via g_debug the content of the object.
+	 *
+	 * #NAObject class takes care of calling this function for each
+	 * derived class, starting from topmost base class up to most-
+	 * derived one. Each derived class has so only to take care of
+	 * dumping its own data.
+	 */
+	void       ( *dump )            ( const NAObject *object );
+
+	/**
+	 * get_clipboard_id:
+	 * @object: the #NAObject-derived object whose id is to be
+	 * retrieved.
+	 *
+	 * Returns: an id suitable for our internal clipboard.
+	 *
+	 * This is a pure virtual function: the most derived class should
+	 * implement it. #NAObject class defaults to return the clipboard
+	 * id of the most derived class which implement this function.
+	 */
+	gchar *    ( *get_clipboard_id )( const NAObject *object );
+
+	/**
+	 * TODO: get ride of this
+	 * ref:
+	 * @object: the #NAObject-derived object to be reffed.
+	 *
+	 * Returns: a reference on the #NAObject.
+	 *
+	 * #NAObject public api implements a bottom-to-top iteration.
+	 * Each derived class has only to take care of ref-ing its own
+	 * childs if applies.
+	 * Finally, the #NAObject class will ref this @object itself.
+	 */
+	void       ( *ref )             ( const NAObject *object );
+
+	/**
 	 * new:
-	 * @object: a #NAObject-derived object.
+	 * @object: a #NAObject-derived object of the class that we want
+	 * be returned.
 	 *
-	 * Returns: a newly allocated object of the same class that @object.
+	 * Returns: a newly allocated #NAObject of the same class that
+	 * @object.
+	 *
+	 * This is a pure virtual function: the most derived class should
+	 * implement it. #NAObject class defaults to return the object
+	 * allocated by the most derived class which implement this
+	 * function.
 	 */
-	NAObject * ( *new )                ( const NAObject *object );
+	NAObject * ( *new )             ( const NAObject *object );
 
 	/**
 	 * copy:
@@ -88,10 +131,13 @@ typedef struct {
 	 *
 	 * Copies data and properties from @source to @target.
 	 *
-	 * Each derived class should take care of calling its parent class
-	 * to complete the copy.
+	 * Each derived class should take care of implementing this function
+	 * when relevant. #NAObject class will take care of calling this
+	 * function for each class of the hierarchy, starting from topmost
+	 * base class up to the most-derived one. Each class has so only to
+	 * take care of dumping its own data.
 	 */
-	void       ( *copy )               ( NAObject *target, const NAObject *source );
+	void       ( *copy )            ( NAObject *target, const NAObject *source );
 
 	/**
 	 * are_equal:
@@ -100,13 +146,17 @@ typedef struct {
 	 *
 	 * 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.
+	 *
+	 * Each derived class should take care of implementing this function
+	 * when relevant. #NAObject class will take care of calling this
+	 * function for each class of the hierarchy, starting from topmost
+	 * base class up to the most-derived one, at least while result
+	 * stays at %TRUE.
+	 * As soon as a difference is detected, the calling sequence will
+	 * be stopped, and the result returned.
 	 */
-	gboolean   ( *are_equal )          ( const NAObject *a, const NAObject *b );
+	gboolean   ( *are_equal )       ( const NAObject *a, const NAObject *b );
 
 	/**
 	 * is_valid:
@@ -114,68 +164,25 @@ typedef struct {
 	 *
 	 * 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 );
-
-	/**
-	 * dump:
-	 * @object: the #NAObject-derived object to be dumped.
 	 *
-	 * Dumps via g_debug the content of the object.
+	 * A #NAObject is valid if its internal identifiant is set.
 	 *
-	 * 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.
+	 * Each derived class should take care of implementing this function
+	 * when relevant. #NAObject class will take care of calling this
+	 * function for each class of the hierarchy, starting from topmost
+	 * base class up to the most-derived one, at least while result
+	 * stays at %TRUE.
+	 * As soon as a difference is detected, the calling sequence will
+	 * be stopped, and the result returned.
 	 */
-	void       ( *dump )               ( const NAObject *object );
+	gboolean   ( *is_valid )        ( const NAObject *object );
 
-	/**
-	 * get_clipboard_id:
-	 * @object: the #NAObject-derived object whose id is to be retrieved.
-	 *
-	 * Returns: an id suitable for the internal clipboard.
-	 */
-	gchar *    ( *get_clipboard_id )   ( const NAObject *object );
 }
 	NAObjectClass;
 
-/* object properties
- * used in derived classes to access 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 );
-
-gchar    *na_object_get_clipboard_id( const NAObject *object );
-
-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 );
-gboolean  na_object_get_modified_status( const NAObject *object );
-gboolean  na_object_get_valid_status( const NAObject *object );
-
-NAObject *na_object_get_origin( const NAObject *object );
-gchar    *na_object_get_id( const NAObject *object );
-gchar    *na_object_get_label( const NAObject *object );
-
-void      na_object_set_origin( NAObject *object, const NAObject *origin );
-void      na_object_set_id( NAObject *object, const gchar *id );
-void      na_object_set_label( NAObject *object, const gchar *label );
-
 G_END_DECLS
 
-#endif /* __NA_OBJECT_H__ */
+#endif /* __NA_OBJECT_CLASS_H__ */
diff --git a/src/common/na-gconf.h b/src/common/na-object-fn.h
similarity index 50%
copy from src/common/na-gconf.h
copy to src/common/na-object-fn.h
index 0a96487..659c9ac 100644
--- a/src/common/na-gconf.h
+++ b/src/common/na-object-fn.h
@@ -28,49 +28,43 @@
  *   ... and many others (see AUTHORS)
  */
 
-#ifndef __NA_GCONF_H__
-#define __NA_GCONF_H__
+#ifndef __NA_OBJECT_FN_H__
+#define __NA_OBJECT_FN_H__
 
 /**
- * SECTION: na_gconf
- * @short_description: #NAGConf class definition.
- * @include: common/na-gconf.h
+ * SECTION: na_object
+ * @short_description: #NAObject public functions definition.
+ * @include: common/na-object-fn.h
  *
- * This class manages the GConf I/O storage subsystem.
- * It should only be used through the NAIIOProvider interface.
+ * Define here the public functions of the #NAObject class.
+ *
+ * Note that most users of the class should rather use macros defined
+ * in na-object-api.h
  */
 
-#include <glib-object.h>
+#include "na-object-class.h"
 
 G_BEGIN_DECLS
 
-#define NA_GCONF_TYPE					( na_gconf_get_type())
-#define NA_GCONF( object )				( G_TYPE_CHECK_INSTANCE_CAST( object, NA_GCONF_TYPE, NAGConf ))
-#define NA_GCONF_CLASS( klass )			( G_TYPE_CHECK_CLASS_CAST( klass, NA_GCONF_TYPE, NAGConfClass ))
-#define NA_IS_GCONF( object )			( G_TYPE_CHECK_INSTANCE_TYPE( object, NA_GCONF_TYPE ))
-#define NA_IS_GCONF_CLASS( klass )		( G_TYPE_CHECK_CLASS_TYPE(( klass ), NA_GCONF_TYPE ))
-#define NA_GCONF_GET_CLASS( object )	( G_TYPE_INSTANCE_GET_CLASS(( object ), NA_GCONF_TYPE, NAGConfClass ))
-
-typedef struct NAGConfPrivate NAGConfPrivate;
-
-typedef struct {
-	GObject         parent;
-	NAGConfPrivate *private;
-}
-	NAGConf;
-
-typedef struct NAGConfClassPrivate NAGConfClassPrivate;
+/* NAObject
+ */
+void      na_object_object_dump( const NAObject *object );
+gchar    *na_object_object_get_clipboard_id( const NAObject *object );
+NAObject *na_object_object_ref( const NAObject *object );
+void      na_object_object_copy( NAObject *target, const NAObject *source );
 
-typedef struct {
-	GObjectClass         parent;
-	NAGConfClassPrivate *private;
-}
-	NAGConfClass;
+/* NAIDuplicable
+ */
+NAObject *na_object_iduplicable_duplicate( const NAObject *object );
 
-GType    na_gconf_get_type( void );
+void      na_object_iduplicable_check_edition_status( const NAObject *object );
+gboolean  na_object_iduplicable_are_equal( const NAObject *a, const NAObject *b );
+gboolean  na_object_iduplicable_is_modified( const NAObject *object );
+gboolean  na_object_iduplicable_is_valid( const NAObject *object );
 
-NAGConf *na_gconf_new( const GObject *notified );
+NAObject *na_object_iduplicable_get_origin( const NAObject *object );
+void      na_object_iduplicable_set_origin( NAObject *object, const NAObject *origin );
 
 G_END_DECLS
 
-#endif /* __NA_GCONF_H__ */
+#endif /* __NA_OBJECT_FN_H__ */
diff --git a/src/common/na-gconf.h b/src/common/na-object-id-class.h
similarity index 51%
copy from src/common/na-gconf.h
copy to src/common/na-object-id-class.h
index 0a96487..5bc5c7d 100644
--- a/src/common/na-gconf.h
+++ b/src/common/na-object-id-class.h
@@ -28,49 +28,46 @@
  *   ... and many others (see AUTHORS)
  */
 
-#ifndef __NA_GCONF_H__
-#define __NA_GCONF_H__
+#ifndef __NA_OBJECT_ID_CLASS_H__
+#define __NA_OBJECT_ID_CLASS_H__
 
 /**
- * SECTION: na_gconf
- * @short_description: #NAGConf class definition.
- * @include: common/na-gconf.h
+ * SECTION: na_object_id
+ * @short_description: #NAObjectId class definition.
+ * @include: common/na-object-id-class.h
  *
- * This class manages the GConf I/O storage subsystem.
- * It should only be used through the NAIIOProvider interface.
+ * The #NAObjectId class is a pure virtual class.
  */
 
-#include <glib-object.h>
+#include "na-object-class.h"
 
 G_BEGIN_DECLS
 
-#define NA_GCONF_TYPE					( na_gconf_get_type())
-#define NA_GCONF( object )				( G_TYPE_CHECK_INSTANCE_CAST( object, NA_GCONF_TYPE, NAGConf ))
-#define NA_GCONF_CLASS( klass )			( G_TYPE_CHECK_CLASS_CAST( klass, NA_GCONF_TYPE, NAGConfClass ))
-#define NA_IS_GCONF( object )			( G_TYPE_CHECK_INSTANCE_TYPE( object, NA_GCONF_TYPE ))
-#define NA_IS_GCONF_CLASS( klass )		( G_TYPE_CHECK_CLASS_TYPE(( klass ), NA_GCONF_TYPE ))
-#define NA_GCONF_GET_CLASS( object )	( G_TYPE_INSTANCE_GET_CLASS(( object ), NA_GCONF_TYPE, NAGConfClass ))
+#define NA_OBJECT_ID_TYPE					( na_object_id_get_type())
+#define NA_OBJECT_ID( object )				( G_TYPE_CHECK_INSTANCE_CAST( object, NA_OBJECT_ID_TYPE, NAObjectId ))
+#define NA_OBJECT_ID_CLASS( klass )			( G_TYPE_CHECK_CLASS_CAST( klass, NA_OBJECT_ID_TYPE, NAObjectIdClass ))
+#define NA_IS_OBJECT_ID( object )			( G_TYPE_CHECK_INSTANCE_TYPE( object, NA_OBJECT_ID_TYPE ))
+#define NA_IS_OBJECT_ID_CLASS( klass )		( G_TYPE_CHECK_CLASS_TYPE(( klass ), NA_OBJECT_ID_TYPE ))
+#define NA_OBJECT_ID_GET_CLASS( object )	( G_TYPE_INSTANCE_GET_CLASS(( object ), NA_OBJECT_ID_TYPE, NAObjectIdClass ))
 
-typedef struct NAGConfPrivate NAGConfPrivate;
+typedef struct NAObjectIdPrivate NAObjectIdPrivate;
 
 typedef struct {
-	GObject         parent;
-	NAGConfPrivate *private;
+	NAObject           parent;
+	NAObjectIdPrivate *private;
 }
-	NAGConf;
+	NAObjectId;
 
-typedef struct NAGConfClassPrivate NAGConfClassPrivate;
+typedef struct NAObjectIdClassPrivate NAObjectIdClassPrivate;
 
 typedef struct {
-	GObjectClass         parent;
-	NAGConfClassPrivate *private;
+	NAObjectClass           parent;
+	NAObjectIdClassPrivate *private;
 }
-	NAGConfClass;
+	NAObjectIdClass;
 
-GType    na_gconf_get_type( void );
-
-NAGConf *na_gconf_new( const GObject *notified );
+GType  na_object_id_get_type( void );
 
 G_END_DECLS
 
-#endif /* __NA_GCONF_H__ */
+#endif /* __NA_OBJECT_ID_CLASS_H__ */
diff --git a/src/common/na-action-class.h b/src/common/na-object-id-fn.h
similarity index 55%
rename from src/common/na-action-class.h
rename to src/common/na-object-id-fn.h
index 38cf758..a2e7ee2 100644
--- a/src/common/na-action-class.h
+++ b/src/common/na-object-id-fn.h
@@ -28,42 +28,31 @@
  *   ... and many others (see AUTHORS)
  */
 
-#ifndef __NA_ACTION_CLASS_H__
-#define __NA_ACTION_CLASS_H__
+#ifndef __NA_OBJECT_ID_FN_H__
+#define __NA_OBJECT_ID_FN_H__
 
 /**
- * SECTION: na_action
+ * SECTION: na_object_id
+ * @short_description: #NAObjectId class definition.
+ * @include: common/na-object-id-fn.h
+ *
+ * A #NAObjectId object is characterized by :
+ * - an internal identifiant (ASCII, case insensitive)
+ * - a libelle (UTF8, localizable).
+ *
+ * The #NAObjectId class is a pure virtual class.
  */
 
-#include "na-object-item.h"
+#include "na-object-id-class.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 {
-	NAObjectItem     parent;
-	NAActionPrivate *private;
-}
-	NAAction;
-
-typedef struct NAActionClassPrivate NAActionClassPrivate;
-
-typedef struct {
-	NAObjectItemClass     parent;
-	NAActionClassPrivate *private;
-}
-	NAActionClass;
+gchar *na_object_id_get_id( const NAObjectId *object );
+gchar *na_object_id_get_label( const NAObjectId *object );
 
-GType na_action_get_type( void );
+void   na_object_id_set_id( NAObjectId *object, const gchar *id );
+void   na_object_id_set_label( NAObjectId *object, const gchar *label );
 
 G_END_DECLS
 
-#endif /* __NA_ACTION_CLASS_H__ */
+#endif /* __NA_OBJECT_ID_FN_H__ */
diff --git a/src/common/na-object-id.c b/src/common/na-object-id.c
new file mode 100644
index 0000000..6a5676f
--- /dev/null
+++ b/src/common/na-object-id.c
@@ -0,0 +1,427 @@
+/*
+ * 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 <string.h>
+
+#include "na-object-id-class.h"
+#include "na-object-id-fn.h"
+
+/* private class data
+ */
+struct NAObjectIdClassPrivate {
+	void *empty;						/* so that gcc -pedantic is happy */
+};
+
+/* private instance data
+ */
+struct NAObjectIdPrivate {
+	gboolean  dispose_has_run;
+	gchar    *id;
+	gchar    *label;
+};
+
+/* object properties
+ */
+enum {
+	NAOBJECT_ID_PROP_ID_ID = 1,
+	NAOBJECT_ID_PROP_LABEL_ID
+};
+
+/* instance properties
+ */
+#define NAOBJECT_ID_PROP_ID				"na-object-id"
+#define NAOBJECT_ID_PROP_LABEL			"na-object-label"
+
+static NAObjectClass *st_parent_class = NULL;
+
+static GType    register_type( void );
+static void     class_init( NAObjectIdClass *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     object_dump( const NAObject *object);
+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 *object );
+
+GType
+na_object_id_get_type( void )
+{
+	static GType object_type = 0;
+
+	if( !object_type ){
+		object_type = register_type();
+	}
+
+	return( object_type );
+}
+
+static GType
+register_type( void )
+{
+	static const gchar *thisfn = "na_object_id_register_type";
+	GType type;
+
+	static GTypeInfo info = {
+		sizeof( NAObjectIdClass ),
+		( GBaseInitFunc ) NULL,
+		( GBaseFinalizeFunc ) NULL,
+		( GClassInitFunc ) class_init,
+		NULL,
+		NULL,
+		sizeof( NAObjectId ),
+		0,
+		( GInstanceInitFunc ) instance_init
+	};
+
+	g_debug( "%s", thisfn );
+
+	type = g_type_register_static( NA_OBJECT_TYPE, "NAObjectId", &info, 0 );
+
+	return( type );
+}
+
+static void
+class_init( NAObjectIdClass *klass )
+{
+	static const gchar *thisfn = "na_object_id_class_init";
+	GObjectClass *object_class;
+	NAObjectClass *naobject_class;
+	GParamSpec *spec;
+
+	g_debug( "%s: klass=%p", thisfn, ( void * ) klass );
+
+	st_parent_class = g_type_class_peek_parent( klass );
+
+	object_class = G_OBJECT_CLASS( klass );
+	object_class->dispose = instance_dispose;
+	object_class->finalize = instance_finalize;
+	object_class->set_property = instance_set_property;
+	object_class->get_property = instance_get_property;
+
+	spec = g_param_spec_string(
+			NAOBJECT_ID_PROP_ID,
+			"NAObjectId identifiant",
+			"Internal identifiant of the NAObjectId object (ASCII, case insensitive)", "",
+			G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE );
+	g_object_class_install_property( object_class, NAOBJECT_ID_PROP_ID_ID, spec );
+
+	spec = g_param_spec_string(
+			NAOBJECT_ID_PROP_LABEL,
+			"NAObjectId libelle",
+			"Libelle of the NAObjectId object (UTF-8, localizable)", "",
+			G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE );
+	g_object_class_install_property( object_class, NAOBJECT_ID_PROP_LABEL_ID, spec );
+
+	klass->private = g_new0( NAObjectIdClassPrivate, 1 );
+
+	naobject_class = NA_OBJECT_CLASS( klass );
+	naobject_class->dump = object_dump;
+	naobject_class->get_clipboard_id = NULL;
+	naobject_class->ref = NULL;
+	naobject_class->new = NULL;
+	naobject_class->copy = object_copy;
+	naobject_class->are_equal = object_are_equal;
+	naobject_class->is_valid = object_is_valid;
+}
+
+static void
+instance_init( GTypeInstance *instance, gpointer klass )
+{
+	/*static const gchar *thisfn = "na_object_id_instance_init";*/
+	NAObjectId *self;
+
+	/*g_debug( "%s: instance=%p, klass=%p", thisfn, ( void * ) instance, ( void * ) klass );*/
+	g_return_if_fail( NA_IS_OBJECT_ID( instance ));
+	self = NA_OBJECT_ID( instance );
+
+	self->private = g_new0( NAObjectIdPrivate, 1 );
+
+	self->private->dispose_has_run = FALSE;
+}
+
+static void
+instance_get_property( GObject *object, guint property_id, GValue *value, GParamSpec *spec )
+{
+	NAObjectId *self;
+
+	g_return_if_fail( NA_IS_OBJECT_ID( object ));
+	g_return_if_fail( !NA_OBJECT_ID( object )->private->dispose_has_run );
+	self = NA_OBJECT_ID( object );
+
+	switch( property_id ){
+		case NAOBJECT_ID_PROP_ID_ID:
+			g_value_set_string( value, self->private->id );
+			break;
+
+		case NAOBJECT_ID_PROP_LABEL_ID:
+			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 )
+{
+	NAObjectId *self;
+
+	g_return_if_fail( NA_IS_OBJECT_ID( object ));
+	g_return_if_fail( !NA_OBJECT_ID( object )->private->dispose_has_run );
+	self = NA_OBJECT_ID( object );
+
+	switch( property_id ){
+		case NAOBJECT_ID_PROP_ID_ID:
+			g_free( self->private->id );
+			self->private->id = g_value_dup_string( value );
+			break;
+
+		case NAOBJECT_ID_PROP_LABEL_ID:
+			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 )
+{
+	/*static const gchar *thisfn = "na_object_id_instance_dispose";*/
+	NAObjectId *self;
+
+	/*g_debug( "%s: object=%p", thisfn, ( void * ) object );*/
+	g_return_if_fail( NA_IS_OBJECT_ID( object ));
+	self = NA_OBJECT_ID( object );
+
+	if( !self->private->dispose_has_run ){
+
+		self->private->dispose_has_run = TRUE;
+
+		/* chain up to the parent class */
+		if( G_OBJECT_CLASS( st_parent_class )->dispose ){
+			G_OBJECT_CLASS( st_parent_class )->dispose( object );
+		}
+	}
+}
+
+static void
+instance_finalize( GObject *object )
+{
+	NAObjectId *self;
+
+	g_return_if_fail( NA_IS_OBJECT_ID( object ));
+	self = NA_OBJECT_ID( object );
+
+	g_free( self->private->id );
+	g_free( self->private->label );
+
+	g_free( self->private );
+
+	/* chain call to parent class */
+	if( G_OBJECT_CLASS( st_parent_class )->finalize ){
+		G_OBJECT_CLASS( st_parent_class )->finalize( object );
+	}
+}
+
+/**
+ * na_object_id_get_id:
+ * @object: the #NAObjectId object whose internal identifiant is
+ * requested.
+ *
+ * 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_id_get_id( const NAObjectId *object )
+{
+	gchar *id;
+
+	g_return_val_if_fail( NA_IS_OBJECT_ID( object ), NULL );
+	g_return_val_if_fail( !object->private->dispose_has_run, NULL );
+
+	g_object_get( G_OBJECT( object ), NAOBJECT_ID_PROP_ID, &id, NULL );
+
+	return( id );
+}
+
+/**
+ * na_object_id_get_label:
+ * @object: the #NAObjectId object whose label is requested.
+ *
+ * Returns: the label of @object as a new string.
+ *
+ * The returned string is an UTF_8 localizable string.
+ * It should be g_free() by the caller.
+ */
+gchar *
+na_object_id_get_label( const NAObjectId *object )
+{
+	gchar *label;
+
+	g_return_val_if_fail( NA_IS_OBJECT_ID( object ), NULL );
+	g_return_val_if_fail( !object->private->dispose_has_run, NULL );
+
+	g_object_get( G_OBJECT( object ), NAOBJECT_ID_PROP_LABEL, &label, NULL );
+
+	return( label );
+}
+
+/**
+ * na_object_id_set_id:
+ * @object: the #NAObjectId 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_id_set_id( NAObjectId *object, const gchar *id )
+{
+	g_return_if_fail( NA_IS_OBJECT_ID( object ));
+	g_return_if_fail( !object->private->dispose_has_run );
+
+	g_object_set( G_OBJECT( object ), NAOBJECT_ID_PROP_ID, id, NULL );
+}
+
+/**
+ * na_object_id_set_label:
+ * @object: the #NAObjectId 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_id_set_label( NAObjectId *object, const gchar *label )
+{
+	g_return_if_fail( NA_IS_OBJECT_ID( object ));
+	g_return_if_fail( !object->private->dispose_has_run );
+
+	g_object_set( G_OBJECT( object ), NAOBJECT_ID_PROP_LABEL, label, NULL );
+}
+
+static void
+object_dump( const NAObject *object )
+{
+	static const char *thisfn = "na_object_id_object_dump";
+
+	g_return_if_fail( NA_IS_OBJECT_ID( object ));
+	g_return_if_fail( !NA_OBJECT_ID( object )->private->dispose_has_run );
+
+	g_debug( "%s:    id=%s", thisfn, NA_OBJECT_ID( object )->private->id );
+	g_debug( "%s: label=%s", thisfn, NA_OBJECT_ID( object )->private->label );
+}
+
+static void
+object_copy( NAObject *target, const NAObject *source )
+{
+	gchar *id, *label;
+
+	g_return_if_fail( NA_IS_OBJECT_ID( target ));
+	g_return_if_fail( !NA_OBJECT_ID( target )->private->dispose_has_run );
+	g_return_if_fail( NA_IS_OBJECT_ID( source ));
+	g_return_if_fail( !NA_OBJECT_ID( source )->private->dispose_has_run );
+
+	g_object_get( G_OBJECT( source ),
+			NAOBJECT_ID_PROP_ID, &id,
+			NAOBJECT_ID_PROP_LABEL, &label,
+			NULL );
+
+	g_object_set( G_OBJECT( target ),
+			NAOBJECT_ID_PROP_ID, id,
+			NAOBJECT_ID_PROP_LABEL, label,
+			NULL );
+
+	g_free( id );
+	g_free( label );
+}
+
+static gboolean
+object_are_equal( const NAObject *a, const NAObject *b )
+{
+	gboolean equal = TRUE;
+
+	g_return_val_if_fail( NA_IS_OBJECT_ID( a ), FALSE );
+	g_return_val_if_fail( !NA_OBJECT_ID( a )->private->dispose_has_run, FALSE );
+	g_return_val_if_fail( NA_IS_OBJECT_ID( b ), FALSE );
+	g_return_val_if_fail( !NA_OBJECT_ID( b )->private->dispose_has_run, FALSE );
+
+	if( equal ){
+		if( g_ascii_strcasecmp( NA_OBJECT_ID( a )->private->id, NA_OBJECT_ID( b )->private->id )){
+			/*g_debug( "a->id=%s, b->id=%s", NA_OBJECT_ID( a )->private->id, NA_OBJECT_ID( b )->private->id );*/
+			equal = FALSE;
+		}
+	}
+
+	if( equal ){
+		if( g_utf8_collate( NA_OBJECT_ID( a )->private->label, NA_OBJECT_ID( b )->private->label )){
+			/*g_debug( "a->label=%s, b->label=%s", NA_OBJECT_ID( a )->private->label, NA_OBJECT_ID( b )->private->label );*/
+			equal = FALSE;
+		}
+	}
+
+	/*g_debug( "na_object_id_are_equal: %s", equal ? "True":"False" );*/
+	return( equal );
+}
+
+/*
+ * from NAObjectId point of view, a valid object requires an id
+ * (not null, not empty)
+ */
+static gboolean
+object_is_valid( const NAObject *object )
+{
+	gboolean valid = TRUE;
+
+	g_return_val_if_fail( NA_IS_OBJECT_ID( object ), FALSE );
+	g_return_val_if_fail( !NA_OBJECT_ID( object )->private->dispose_has_run, FALSE );
+
+	if( valid ){
+		valid = ( NA_OBJECT_ID( object )->private->id && strlen( NA_OBJECT_ID( object )->private->id ));
+	}
+
+	return( valid );
+}
diff --git a/src/common/na-object-item.h b/src/common/na-object-item-class.h
similarity index 68%
rename from src/common/na-object-item.h
rename to src/common/na-object-item-class.h
index a1dc710..9998362 100644
--- a/src/common/na-object-item.h
+++ b/src/common/na-object-item-class.h
@@ -28,19 +28,10 @@
  *   ... and many others (see AUTHORS)
  */
 
-#ifndef __NA_OBJECT_ITEM_H__
-#define __NA_OBJECT_ITEM_H__
+#ifndef __NA_OBJECT_ITEM_CLASS_H__
+#define __NA_OBJECT_ITEM_CLASS_H__
 
-/**
- * SECTION: na_object_item
- * @short_description: #NAObjectItem class definition.
- * @include: common/na-object-item.h
- *
- * Derived from #NAObject class, this class is built to be used as a
- * base class for objects which have a tooltip and an icon.
- */
-
-#include "na-object.h"
+#include "na-object-id-class.h"
 
 G_BEGIN_DECLS
 
@@ -54,7 +45,7 @@ G_BEGIN_DECLS
 typedef struct NAObjectItemPrivate NAObjectItemPrivate;
 
 typedef struct {
-	NAObject             parent;
+	NAObjectId           parent;
 	NAObjectItemPrivate *private;
 }
 	NAObjectItem;
@@ -62,28 +53,13 @@ typedef struct {
 typedef struct NAObjectItemClassPrivate NAObjectItemClassPrivate;
 
 typedef struct {
-	NAObjectClass             parent;
+	NAObjectIdClass           parent;
 	NAObjectItemClassPrivate *private;
 }
 	NAObjectItemClass;
 
-/* object properties
- * used in derived classes to access the properties
- */
-enum {
-	PROP_NAOBJECT_ITEM_TOOLTIP = 1,
-	PROP_NAOBJECT_ITEM_ICON
-};
-
-GType  na_object_item_get_type( void );
-
-gchar *na_object_item_get_tooltip( const NAObjectItem *item );
-gchar *na_object_item_get_icon( const NAObjectItem *item );
-gchar *na_object_item_get_verified_icon_name( const NAObjectItem *item );
-
-void   na_object_item_set_tooltip( NAObjectItem *item, const gchar *tooltip );
-void   na_object_item_set_icon( NAObjectItem *item, const gchar *icon_name );
+GType na_object_item_get_type( void );
 
 G_END_DECLS
 
-#endif /* __NA_OBJECT_ITEM_H__ */
+#endif /* __NA_OBJECT_ITEM_CLASS_H__ */
diff --git a/src/common/na-object-item-fn.h b/src/common/na-object-item-fn.h
new file mode 100644
index 0000000..2a00759
--- /dev/null
+++ b/src/common/na-object-item-fn.h
@@ -0,0 +1,74 @@
+/*
+ * 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_OBJECT_ITEM_FN_H__
+#define __NA_OBJECT_ITEM_FN_H__
+
+/**
+ * SECTION: na_object_item
+ * @short_description: #NAObjectItem class definition.
+ * @include: common/na-object-item.h
+ *
+ * Derived from #NAObjectId class, this class is built to be used as
+ * a base class for objects which have a tooltip and an icon.
+ */
+
+#include <gtk/gtk.h>
+
+#include "na-object-item-class.h"
+#include "na-iio-provider.h"
+
+G_BEGIN_DECLS
+
+gchar         *na_object_item_get_tooltip( const NAObjectItem *item );
+gchar         *na_object_item_get_icon( const NAObjectItem *item );
+gchar         *na_object_item_get_verified_icon_name( const NAObjectItem *item );
+GdkPixbuf     *na_object_item_get_pixbuf( const NAObjectItem *item, GtkWidget *widget );
+gboolean       na_object_item_is_enabled( const NAObjectItem *item );
+NAIIOProvider *na_object_item_get_provider( const NAObjectItem *item );
+NAObject      *na_object_item_get_item( const NAObjectItem *item, const gchar *id );
+GSList        *na_object_item_get_items( const NAObjectItem *item );
+guint          na_object_item_get_items_count( const NAObjectItem *item );
+void           na_object_item_free_items( GSList *items );
+
+void           na_object_item_set_new_uuid( NAObjectItem *item );
+void           na_object_item_set_tooltip( NAObjectItem *item, const gchar *tooltip );
+void           na_object_item_set_icon( NAObjectItem *item, const gchar *icon_name );
+void           na_object_item_set_enabled( NAObjectItem *item, gboolean enabled );
+void           na_object_item_set_provider( NAObjectItem *item, const NAIIOProvider *provider );
+void           na_object_item_set_items( NAObjectItem *item, GSList *items );
+
+void           na_object_item_append_item( NAObjectItem *item, const NAObject *object );
+void           na_object_item_insert_item( NAObjectItem *item, const NAObject *object );
+void           na_object_item_remove_item( NAObjectItem *item, NAObject *object );
+
+G_END_DECLS
+
+#endif /* __NA_OBJECT_ITEM_FN_H__ */
diff --git a/src/common/na-object-item.c b/src/common/na-object-item.c
index 326081e..d539139 100644
--- a/src/common/na-object-item.c
+++ b/src/common/na-object-item.c
@@ -33,8 +33,11 @@
 #endif
 
 #include <string.h>
+#include <uuid/uuid.h>
 
-#include "na-object-item.h"
+#include "na-object-api.h"
+#include "na-object-item-class.h"
+#include "na-object-item-fn.h"
 #include "na-utils.h"
 
 /* private class data
@@ -46,31 +49,55 @@ struct NAObjectItemClassPrivate {
 /* private instance data
  */
 struct NAObjectItemPrivate {
-	gboolean dispose_has_run;
+	gboolean       dispose_has_run;
 
 	/* object_item properties
 	 */
-	gchar   *tooltip;
-	gchar   *icon;
+	gchar         *tooltip;
+	gchar         *icon;
+	gboolean       enabled;
+
+	/* list of NAObjectId subitems
+	 */
+	GSList        *items;
+
+	/* the original provider
+	 * required to be able to edit/delete the item
+	 */
+	NAIIOProvider *provider;
+};
+
+/* object properties
+ */
+enum {
+	NAOBJECT_ITEM_PROP_TOOLTIP_ID = 1,
+	NAOBJECT_ITEM_PROP_ICON_ID,
+	NAOBJECT_ITEM_PROP_ENABLED_ID,
+	NAOBJECT_ITEM_PROP_PROVIDER_ID,
+	NAOBJECT_ITEM_PROP_ITEMS_ID
 };
 
-#define PROP_NAOBJECT_ITEM_TOOLTIP_STR		"na-object-item-tooltip"
-#define PROP_NAOBJECT_ITEM_ICON_STR			"na-object-item-icon"
+#define NAOBJECT_ITEM_PROP_TOOLTIP		"na-object-item-tooltip"
+#define NAOBJECT_ITEM_PROP_ICON			"na-object-item-icon"
+#define NAOBJECT_ITEM_PROP_ENABLED		"na-object-item-enabled"
+#define NAOBJECT_ITEM_PROP_PROVIDER		"na-object-item-provider"
+#define NAOBJECT_ITEM_PROP_ITEMS		"na-object-item-items"
 
-static NAObjectClass *st_parent_class = NULL;
+static NAObjectIdClass *st_parent_class = NULL;
 
-static GType     register_type( void );
-static void      class_init( NAObjectItemClass *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( NAObjectItemClass *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      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 *object_item );
-static void      object_dump( const NAObject *object_item );
+static void     object_dump( const NAObject *object );
+static void     object_ref( 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 *object );
 
 GType
 na_object_item_get_type( void )
@@ -103,7 +130,7 @@ register_type( void )
 
 	g_debug( "%s", thisfn );
 
-	return( g_type_register_static( NA_OBJECT_TYPE, "NAObjectItem", &info, 0 ));
+	return( g_type_register_static( NA_OBJECT_ID_TYPE, "NAObjectItem", &info, 0 ));
 }
 
 static void
@@ -111,6 +138,7 @@ class_init( NAObjectItemClass *klass )
 {
 	static const gchar *thisfn = "na_object_item_class_init";
 	GObjectClass *object_class;
+	NAObjectClass *naobject_class;
 	GParamSpec *spec;
 
 	g_debug( "%s: klass=%p", thisfn, ( void * ) klass );
@@ -124,26 +152,43 @@ class_init( NAObjectItemClass *klass )
 	object_class->get_property = instance_get_property;
 
 	spec = g_param_spec_string(
-			PROP_NAOBJECT_ITEM_TOOLTIP_STR,
+			NAOBJECT_ITEM_PROP_TOOLTIP,
 			"Item tooltip",
 			"Context menu tooltip of the item", "",
 			G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE );
-	g_object_class_install_property( object_class, PROP_NAOBJECT_ITEM_TOOLTIP, spec );
+	g_object_class_install_property( object_class, NAOBJECT_ITEM_PROP_TOOLTIP_ID, spec );
 
 	spec = g_param_spec_string(
-			PROP_NAOBJECT_ITEM_ICON_STR,
+			NAOBJECT_ITEM_PROP_ICON,
 			"Icon name",
 			"Context menu displayable icon for the item", "",
 			G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE );
-	g_object_class_install_property( object_class, PROP_NAOBJECT_ITEM_ICON, spec );
+	g_object_class_install_property( object_class, NAOBJECT_ITEM_PROP_ICON_ID, spec );
+
+	spec = g_param_spec_boolean(
+			NAOBJECT_ITEM_PROP_ENABLED,
+			"Enabled",
+			"Whether this item, and recursively its subitems, is/are enabled", TRUE,
+			G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE );
+	g_object_class_install_property( object_class, NAOBJECT_ITEM_PROP_ENABLED_ID, spec );
+
+	spec = g_param_spec_pointer(
+			NAOBJECT_ITEM_PROP_PROVIDER,
+			"Original provider",
+			"Original provider of the NAObjectItem",
+			G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE );
+	g_object_class_install_property( object_class, NAOBJECT_ITEM_PROP_PROVIDER_ID, spec );
 
 	klass->private = g_new0( NAObjectItemClassPrivate, 1 );
 
-	NA_OBJECT_CLASS( klass )->new = NULL;
-	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;
-	NA_OBJECT_CLASS( klass )->dump = object_dump;
+	naobject_class = NA_OBJECT_CLASS( klass );
+	naobject_class->dump = object_dump;
+	naobject_class->get_clipboard_id = NULL;
+	naobject_class->ref = object_ref;
+	naobject_class->new = NULL;
+	naobject_class->copy = object_copy;
+	naobject_class->are_equal = object_are_equal;
+	naobject_class->is_valid = object_is_valid;
 }
 
 static void
@@ -153,7 +198,7 @@ instance_init( GTypeInstance *instance, gpointer klass )
 	NAObjectItem *self;
 
 	/*g_debug( "%s: instance=%p, klass=%p", thisfn, ( void * ) instance, ( void * ) klass );*/
-	g_assert( NA_IS_OBJECT_ITEM( instance ));
+	g_return_if_fail( NA_IS_OBJECT_ITEM( instance ));
 	self = NA_OBJECT_ITEM( instance );
 
 	self->private = g_new0( NAObjectItemPrivate, 1 );
@@ -164,6 +209,8 @@ instance_init( GTypeInstance *instance, gpointer klass )
 	 */
 	self->private->tooltip = g_strdup( "" );
 	self->private->icon = g_strdup( "" );
+	self->private->enabled = TRUE;
+	self->private->provider = NULL;
 }
 
 static void
@@ -171,18 +218,27 @@ instance_get_property( GObject *object, guint property_id, GValue *value, GParam
 {
 	NAObjectItem *self;
 
-	g_assert( NA_IS_OBJECT_ITEM( object ));
+	g_return_if_fail( NA_IS_OBJECT_ITEM( object ));
+	g_return_if_fail( !NA_OBJECT_ITEM( object )->private->dispose_has_run );
 	self = NA_OBJECT_ITEM( object );
 
 	switch( property_id ){
-		case PROP_NAOBJECT_ITEM_TOOLTIP:
+		case NAOBJECT_ITEM_PROP_TOOLTIP_ID:
 			g_value_set_string( value, self->private->tooltip );
 			break;
 
-		case PROP_NAOBJECT_ITEM_ICON:
+		case NAOBJECT_ITEM_PROP_ICON_ID:
 			g_value_set_string( value, self->private->icon );
 			break;
 
+		case NAOBJECT_ITEM_PROP_ENABLED_ID:
+			g_value_set_boolean( value, self->private->enabled );
+			break;
+
+		case NAOBJECT_ITEM_PROP_PROVIDER_ID:
+			g_value_set_pointer( value, self->private->provider );
+			break;
+
 		default:
 			G_OBJECT_WARN_INVALID_PROPERTY_ID( object, property_id, spec );
 			break;
@@ -194,20 +250,29 @@ instance_set_property( GObject *object, guint property_id, const GValue *value,
 {
 	NAObjectItem *self;
 
-	g_assert( NA_IS_OBJECT_ITEM( object ));
+	g_return_if_fail( NA_IS_OBJECT_ITEM( object ));
+	g_return_if_fail( !NA_OBJECT_ITEM( object )->private->dispose_has_run );
 	self = NA_OBJECT_ITEM( object );
 
 	switch( property_id ){
-		case PROP_NAOBJECT_ITEM_TOOLTIP:
+		case NAOBJECT_ITEM_PROP_TOOLTIP_ID:
 			g_free( self->private->tooltip );
 			self->private->tooltip = g_value_dup_string( value );
 			break;
 
-		case PROP_NAOBJECT_ITEM_ICON:
+		case NAOBJECT_ITEM_PROP_ICON_ID:
 			g_free( self->private->icon );
 			self->private->icon = g_value_dup_string( value );
 			break;
 
+		case NAOBJECT_ITEM_PROP_ENABLED_ID:
+			self->private->enabled = g_value_get_boolean( value );
+			break;
+
+		case NAOBJECT_ITEM_PROP_PROVIDER_ID:
+			self->private->provider = g_value_get_pointer( value );
+			break;
+
 		default:
 			G_OBJECT_WARN_INVALID_PROPERTY_ID( object, property_id, spec );
 			break;
@@ -221,11 +286,13 @@ instance_dispose( GObject *object )
 	NAObjectItem *self;
 
 	/*g_debug( "%s: object=%p", thisfn, ( void * ) object );*/
-	g_assert( NA_IS_OBJECT_ITEM( object ));
+	g_return_if_fail( NA_IS_OBJECT_ITEM( object ));
 	self = NA_OBJECT_ITEM( object );
 
 	if( !self->private->dispose_has_run ){
 
+		na_object_item_free_items( self->private->items );
+
 		self->private->dispose_has_run = TRUE;
 
 		/* chain up to the parent class */
@@ -242,7 +309,7 @@ instance_finalize( GObject *object )
 	NAObjectItem *self;
 
 	/*g_debug( "%s: object=%p", thisfn, ( void * ) object );*/
-	g_assert( NA_IS_OBJECT_ITEM( object ));
+	g_return_if_fail( NA_IS_OBJECT_ITEM( object ));
 	self = NA_OBJECT_ITEM( object );
 
 	g_free( self->private->tooltip );
@@ -271,9 +338,10 @@ na_object_item_get_tooltip( const NAObjectItem *item )
 {
 	gchar *tooltip;
 
-	g_assert( NA_IS_OBJECT_ITEM( item ));
+	g_return_val_if_fail( NA_IS_OBJECT_ITEM( item ), NULL );
+	g_return_val_if_fail( !item->private->dispose_has_run, NULL );
 
-	g_object_get( G_OBJECT( item ), PROP_NAOBJECT_ITEM_TOOLTIP_STR, &tooltip, NULL );
+	g_object_get( G_OBJECT( item ), NAOBJECT_ITEM_PROP_TOOLTIP, &tooltip, NULL );
 
 	return( tooltip );
 }
@@ -293,9 +361,10 @@ na_object_item_get_icon( const NAObjectItem *item )
 {
 	gchar *icon;
 
-	g_assert( NA_IS_OBJECT_ITEM( item ));
+	g_return_val_if_fail( NA_IS_OBJECT_ITEM( item ), NULL );
+	g_return_val_if_fail( !item->private->dispose_has_run, NULL );
 
-	g_object_get( G_OBJECT( item ), PROP_NAOBJECT_ITEM_ICON_STR, &icon, NULL );
+	g_object_get( G_OBJECT( item ), NAOBJECT_ITEM_PROP_ICON, &icon, NULL );
 
 	return( icon );
 }
@@ -308,9 +377,10 @@ na_object_item_get_verified_icon_name( const NAObjectItem *item )
 {
 	gchar *icon_name;
 
-	g_assert( NA_IS_OBJECT_ITEM( item ));
+	g_return_val_if_fail( NA_IS_OBJECT_ITEM( item ), NULL );
+	g_return_val_if_fail( !item->private->dispose_has_run, NULL );
 
-	g_object_get( G_OBJECT( item ), PROP_NAOBJECT_ITEM_ICON_STR, &icon_name, NULL );
+	g_object_get( G_OBJECT( item ), NAOBJECT_ITEM_PROP_ICON, &icon_name, NULL );
 
 	if( icon_name[0] == '/' ){
 		if( !g_file_test( icon_name, G_FILE_TEST_IS_REGULAR )){
@@ -326,6 +396,213 @@ na_object_item_get_verified_icon_name( const NAObjectItem *item )
 }
 
 /**
+ * na_object_item_get_pixbuf:
+ * @item: this #NAObjectItem.
+ * @widget: the widget for which the icon must be rendered.
+ *
+ * Returns the #GdkPixbuf image corresponding to the icon.
+ * The image has a size of %GTK_ICON_SIZE_MENU.
+ */
+GdkPixbuf *na_object_item_get_pixbuf( const NAObjectItem *item, GtkWidget *widget )
+{
+	static const gchar *thisfn = "na_object_item_get_pixbuf";
+	gchar *iconname;
+	GtkStockItem stock_item;
+	GdkPixbuf* icon = NULL;
+	gint width, height;
+	GError* error = NULL;
+
+	g_return_val_if_fail( NA_IS_OBJECT_ITEM( item ), NULL );
+	g_return_val_if_fail( !item->private->dispose_has_run, NULL );
+
+	iconname = na_object_item_get_icon( item );
+
+	/* TODO: use the same algorythm than Nautilus to find and
+	 * display an icon + move the code to NAAction class +
+	 * remove na_action_get_verified_icon_name
+	 */
+	if( iconname ){
+		if( gtk_stock_lookup( iconname, &stock_item )){
+			icon = gtk_widget_render_icon( widget, iconname, GTK_ICON_SIZE_MENU, NULL );
+
+		} else if( g_file_test( iconname, G_FILE_TEST_EXISTS )
+			   && g_file_test( iconname, G_FILE_TEST_IS_REGULAR )){
+
+			gtk_icon_size_lookup (GTK_ICON_SIZE_MENU, &width, &height);
+			icon = gdk_pixbuf_new_from_file_at_size( iconname, width, height, &error );
+			if( error ){
+				g_warning( "%s: iconname=%s, error=%s", thisfn, iconname, error->message );
+				g_error_free( error );
+				error = NULL;
+				icon = NULL;
+			}
+		}
+	}
+
+	g_free( iconname );
+	return( icon );
+}
+
+/**
+ * na_object_item_get_provider:
+ * @item: the #NAObjectItem object to be requested.
+ *
+ * Returns the initial provider of the item (or the last which has
+ * accepted a write operation). At the time of this request, this is
+ * the most probable provider willing to accept a next writing
+ * operation.
+ *
+ * Returns: a #NAIIOProvider object. The reference is
+ * owned by #NAPivot pivot and should not be g_object_unref() by the
+ * caller.
+ */
+NAIIOProvider *
+na_object_item_get_provider( const NAObjectItem *item )
+{
+	NAIIOProvider *provider;
+
+	g_return_val_if_fail( NA_IS_OBJECT_ITEM( item ), NULL );
+	g_return_val_if_fail( !item->private->dispose_has_run, NULL );
+
+	g_object_get( G_OBJECT( item ), NAOBJECT_ITEM_PROP_PROVIDER, &provider, NULL );
+
+	return( provider );
+}
+
+/**
+ * na_object_item_get_item:
+ * @item: the #NAObjectItem from which we want retrieve a subitem.
+ * @id: the id of the searched subitem.
+ *
+ * Returns: a pointer to the #NAObject subitem with the required id.
+ *
+ * The returned #NAObject is owned by the @item object ; the
+ * caller should not try to g_free() nor g_object_unref() it.
+ */
+NAObject *
+na_object_item_get_item( const NAObjectItem *item, const gchar *id )
+{
+	GSList *it;
+	NAObject *found = NULL;
+	NAObject *isub;
+	gchar *isubid;
+
+	g_return_val_if_fail( NA_IS_OBJECT_ITEM( item ), NULL );
+	g_return_val_if_fail( !item->private->dispose_has_run, NULL );
+
+	for( it = item->private->items ; it && !found ; it = it->next ){
+		isub = NA_OBJECT( it->data );
+		isubid = na_object_get_id( isub );
+		if( !strcmp( id, isubid )){
+			found = isub;
+		}
+		g_free( isubid );
+	}
+
+	return( found );
+}
+
+/**
+ * na_object_item_get_items:
+ * @item: the #NAObjectItem from which we want a list of subitems.
+ *
+ * Returns: a newly allocated #GSList of #NAObject objects which are
+ * embedded in the @item. Depending of the exact nature of @item, these
+ * may be #NAObjectMenu, #NAObjectAction or #NAObjectProfile subitems.
+ *
+ * The returned pointer should be na_object_item_free_items() by the
+ * caller.
+ */
+GSList *
+na_object_item_get_items( const NAObjectItem *item )
+{
+	GSList *items, *it;
+
+	g_return_val_if_fail( NA_IS_OBJECT_ITEM( item ), NULL );
+	g_return_val_if_fail( !item->private->dispose_has_run, NULL );
+
+	items = NULL;
+	for( it = item->private->items ; it ; it = it->next ){
+		items = g_slist_prepend( items, g_object_ref( it->data ));
+	}
+
+	return( g_slist_reverse( items ));
+}
+
+/**
+ * na_object_item_get_items_count:
+ * @item: the #NAObjectItem from which we want a count of subitems.
+ *
+ * Returns: the count of subitems of @item.
+ */
+guint
+na_object_item_get_items_count( const NAObjectItem *item )
+{
+	g_return_val_if_fail( NA_IS_OBJECT_ITEM( item ), 0 );
+	g_return_val_if_fail( !item->private->dispose_has_run, 0 );
+
+	return( item->private->items ? g_slist_length( item->private->items ) : 0 );
+}
+
+/**
+ * na_object_item_free_items:
+ * @list: a list of #NAObject subitems as returned by
+ * na_object_item_get_items().
+ *
+ * Frees the list.
+ */
+void
+na_object_item_free_items( GSList *items )
+{
+	g_slist_foreach( items, ( GFunc ) g_object_unref, NULL );
+	g_slist_free( items );
+}
+
+/**
+ * na_object_item_is_enabled:
+ * @item: the #NAObjectItem object to be requested.
+ *
+ * Is the specified item enabled ?
+ * When disabled, the item, not its subitems if any, is/are never
+ * candidate to any selection.
+ *
+ * Returns: %TRUE if the item is enabled, %FALSE else.
+ */
+gboolean
+na_object_item_is_enabled( const NAObjectItem *item )
+{
+	gboolean enabled;
+
+	g_return_val_if_fail( NA_IS_OBJECT_ITEM( item ), FALSE );
+	g_return_val_if_fail( !item->private->dispose_has_run, FALSE );
+
+	g_object_get( G_OBJECT( item ), NAOBJECT_ITEM_PROP_ENABLED, &enabled, NULL );
+
+	return( enabled );
+}
+
+/**
+ * na_object_item_set_new_uuid:
+ * @item: the #NAObjectItem object to be updated.
+ *
+ * Set a new UUID for the item (an action or a menu).
+ */
+void
+na_object_item_set_new_uuid( NAObjectItem *item )
+{
+	uuid_t uuid;
+	gchar uuid_str[64];
+
+	g_return_if_fail( NA_IS_OBJECT_ITEM( item ));
+	g_return_if_fail( !item->private->dispose_has_run );
+
+	uuid_generate( uuid );
+	uuid_unparse_lower( uuid, uuid_str );
+
+	na_object_set_id( item, uuid_str );
+}
+
+/**
  * na_object_item_set_tooltip:
  * @item: the #NAObjectItem object to be updated.
  * @tooltip: the tooltip to be set.
@@ -340,9 +617,10 @@ na_object_item_get_verified_icon_name( const NAObjectItem *item )
 void
 na_object_item_set_tooltip( NAObjectItem *item, const gchar *tooltip )
 {
-	g_assert( NA_IS_OBJECT_ITEM( item ));
+	g_return_if_fail( NA_IS_OBJECT_ITEM( item ));
+	g_return_if_fail( !item->private->dispose_has_run );
 
-	g_object_set( G_OBJECT( item ), PROP_NAOBJECT_ITEM_TOOLTIP_STR, tooltip, NULL );
+	g_object_set( G_OBJECT( item ), NAOBJECT_ITEM_PROP_TOOLTIP, tooltip, NULL );
 }
 
 /**
@@ -358,91 +636,284 @@ na_object_item_set_tooltip( NAObjectItem *item, const gchar *tooltip )
 void
 na_object_item_set_icon( NAObjectItem *item, const gchar *icon )
 {
-	g_assert( NA_IS_OBJECT_ITEM( item ));
+	g_return_if_fail( NA_IS_OBJECT_ITEM( item ));
+	g_return_if_fail( !item->private->dispose_has_run );
 
-	g_object_set( G_OBJECT( item ), PROP_NAOBJECT_ITEM_ICON_STR, icon, NULL );
+	g_object_set( G_OBJECT( item ), NAOBJECT_ITEM_PROP_ICON, icon, NULL );
 }
 
+/**
+ * na_object_item_set_enabled:
+ * @item: the #NAObjectItem object to be updated.
+ * @enabled: the indicator to be set.
+ *
+ * Sets whether the item, and its subitems if any, is/are enabled or not.
+ */
 void
-object_copy( NAObject *target, const NAObject *source )
+na_object_item_set_enabled( NAObjectItem *item, gboolean enabled )
 {
-	gchar *tooltip, *icon;
+	g_return_if_fail( NA_IS_OBJECT_ITEM( item ));
+	g_return_if_fail( !item->private->dispose_has_run );
+
+	g_object_set( G_OBJECT( item ), NAOBJECT_ITEM_PROP_ENABLED, enabled, NULL );
+}
+
+/**
+ * na_object_item_set_provider:
+ * @item: the #NAObjectItem object to be updated.
+ * @provider: the #NAIIOProvider to be set.
+ *
+ * Sets the I/O provider for this #NAObjectItem.
+ */
+void
+na_object_item_set_provider( NAObjectItem *item, const NAIIOProvider *provider )
+{
+	g_return_if_fail( NA_IS_OBJECT_ITEM( item ));
+	g_return_if_fail( !item->private->dispose_has_run );
+
+	g_object_set( G_OBJECT( item ), NAOBJECT_ITEM_PROP_PROVIDER, provider, NULL );
+}
+
+/**
+ * na_object_item_set_items:
+ * @item: the #NAObjectItem whose subitems have to be set.
+ * @list: a #GSList list of #NAObject subitems to be installed.
+ *
+ * Sets the list of the subitems for the @item.
+ *
+ * The previously existing list is removed and replaced by the provided
+ * one. As we create here a new list with a new reference on provided
+ * subitems, the provided list can be safely na_object_items_free_items()
+ * by the caller.
+ */
+void
+na_object_item_set_items( NAObjectItem *item, GSList *items )
+{
+	GSList *it;
+
+	g_return_if_fail( NA_IS_OBJECT_ITEM( item ));
+	g_return_if_fail( !item->private->dispose_has_run );
+
+	na_object_item_free_items( item->private->items );
+	item->private->items = NULL;
+
+	for( it = items ; it ; it = it->next ){
+		item->private->items = g_slist_prepend( item->private->items, g_object_ref( it->data ));
+	}
+	item->private->items = g_slist_reverse( item->private->items );
+}
+
+/**
+ * na_object_item_append_item:
+ * @item: the #NAObjectItem to which add the subitem.
+ * @object: a #NAObject to be added to list of subitems.
+ *
+ * Appends a new @object to the list of subitems of @item.
+ *
+ * We add a reference on provided @object.
+ */
+void
+na_object_item_append_item( NAObjectItem *item, const NAObject *object )
+{
+	g_return_if_fail( NA_IS_OBJECT_ITEM( item ));
+	g_return_if_fail( !item->private->dispose_has_run );
+	g_return_if_fail( NA_IS_OBJECT( object ));
+
+	item->private->items = g_slist_append( item->private->items, g_object_ref(( gpointer ) object ));
+}
+
+/**
+ * na_object_item_insert_item:
+ * @item: the #NAObjectItem to which add the subitem.
+ * @object: a #NAObject to be inserted at the list of subitems.
+ *
+ * Inserts a new @object at the beginning of the list of subitems of
+ * @item.
+ *
+ * We add a reference on provided @object.
+ */
+void
+na_object_item_insert_item( NAObjectItem *item, const NAObject *object )
+{
+	g_return_if_fail( NA_IS_OBJECT_ITEM( item ));
+	g_return_if_fail( !item->private->dispose_has_run );
+	g_return_if_fail( NA_IS_OBJECT( object ));
+
+	item->private->items = g_slist_prepend( item->private->items, g_object_ref(( gpointer ) object ));
+}
+
+/**
+ * na_object_item_remove_item:
+ * @item: the #NAObjectItem item from which the subitems must be removed.
+ * @object: a #NAObject object to be removed from list of subitems.
+ *
+ * Removes a subitem from the list of subitems.
+ *
+ * We also decrement the reference count on removed subitem.
+ */
+void
+na_object_item_remove_item( NAObjectItem *item, NAObject *object )
+{
+	g_return_if_fail( NA_IS_OBJECT_ITEM( item ));
+	g_return_if_fail( !item->private->dispose_has_run );
+	g_return_if_fail( NA_IS_OBJECT( object ));
 
-	if( st_parent_class->copy ){
-		st_parent_class->copy( target, source );
+	item->private->items = g_slist_remove( item->private->items, ( gconstpointer ) object );
+	g_object_unref( object );
+}
+
+static void
+object_dump( const NAObject *item )
+{
+	static const gchar *thisfn = "na_object_item_object_dump";
+	GSList *it;
+
+	g_return_if_fail( NA_IS_OBJECT_ITEM( item ));
+	g_return_if_fail( !NA_OBJECT_ITEM( item )->private->dispose_has_run );
+
+	g_debug( "%s:  tooltip='%s'", thisfn, NA_OBJECT_ITEM( item )->private->tooltip );
+	g_debug( "%s:     icon='%s'", thisfn, NA_OBJECT_ITEM( item )->private->icon );
+	g_debug( "%s:  enabled='%s'", thisfn, NA_OBJECT_ITEM( item )->private->enabled ? "True" : "False" );
+	g_debug( "%s: provider=%p", thisfn, ( void * ) NA_OBJECT_ITEM( item )->private->provider );
+
+	/* dump subitems */
+	g_debug( "%s: %d subitem(s) at %p",
+			thisfn,
+			NA_OBJECT_ITEM( item )->private->items ? g_slist_length( NA_OBJECT_ITEM( item )->private->items ) : 0,
+			( void * ) NA_OBJECT_ITEM( item )->private->items );
+
+	for( it = NA_OBJECT_ITEM( item )->private->items ; it ; it = it->next ){
+		na_object_dump( it->data );
 	}
+}
+
+static void
+object_ref( const NAObject *item )
+{
+	g_slist_foreach( NA_OBJECT_ITEM( item )->private->items, ( GFunc ) g_object_ref, NULL );
+}
+
+static void
+object_copy( NAObject *target, const NAObject *source )
+{
+	gchar *tooltip, *icon;
+	gboolean enabled;
+	gpointer provider;
+	GSList *subitems, *it;
 
-	g_assert( NA_IS_OBJECT_ITEM( source ));
-	g_assert( NA_IS_OBJECT_ITEM( target ));
+	g_return_if_fail( NA_IS_OBJECT_ITEM( target ));
+	g_return_if_fail( !NA_OBJECT_ITEM( target )->private->dispose_has_run );
+	g_return_if_fail( NA_IS_OBJECT_ITEM( source ));
+	g_return_if_fail( !NA_OBJECT_ITEM( source )->private->dispose_has_run );
 
 	g_object_get( G_OBJECT( source ),
-			PROP_NAOBJECT_ITEM_TOOLTIP_STR, &tooltip,
-			PROP_NAOBJECT_ITEM_ICON_STR, &icon,
+			NAOBJECT_ITEM_PROP_TOOLTIP, &tooltip,
+			NAOBJECT_ITEM_PROP_ICON, &icon,
+			NAOBJECT_ITEM_PROP_ENABLED, &enabled,
+			NAOBJECT_ITEM_PROP_PROVIDER, &provider,
 			NULL );
 
 	g_object_set( G_OBJECT( target ),
-			PROP_NAOBJECT_ITEM_TOOLTIP_STR, tooltip,
-			PROP_NAOBJECT_ITEM_ICON_STR, icon,
+			NAOBJECT_ITEM_PROP_TOOLTIP, tooltip,
+			NAOBJECT_ITEM_PROP_ICON, icon,
+			NAOBJECT_ITEM_PROP_ENABLED, enabled,
+			NAOBJECT_ITEM_PROP_PROVIDER, provider,
 			NULL );
 
 	g_free( tooltip );
 	g_free( icon );
+
+	subitems = NULL;
+	for( it = NA_OBJECT_ITEM( source )->private->items ; it ; it = it->next ){
+		subitems = g_slist_prepend( subitems, na_object_duplicate( it->data ));
+	}
+	subitems = g_slist_reverse( subitems );
+	na_object_set_items( target, subitems );
+	na_object_free_items( subitems );
+
+	/*g_debug( "na_object_item_object_copy: end" );*/
 }
 
+/*
+ * note that provider is not consider as pertinent here
+ */
 static gboolean
 object_are_equal( const NAObject *a, const NAObject *b )
 {
-	NAObjectItem *first, *second;
 	gboolean equal = TRUE;
+	GSList *it;
+	NAObject *first_obj, *second_obj;
+	gchar *first_id, *second_id;
+
+	g_return_val_if_fail( NA_IS_OBJECT_ITEM( a ), FALSE );
+	g_return_val_if_fail( !NA_OBJECT_ITEM( a )->private->dispose_has_run, FALSE );
+	g_return_val_if_fail( NA_IS_OBJECT_ITEM( b ), FALSE );
+	g_return_val_if_fail( !NA_OBJECT_ITEM( b )->private->dispose_has_run, FALSE );
 
 	if( equal ){
-		if( st_parent_class->are_equal ){
-			equal = st_parent_class->are_equal( a, b );
-		}
+		equal =
+			( g_utf8_collate( NA_OBJECT_ITEM( a )->private->tooltip, NA_OBJECT_ITEM( b )->private->tooltip ) == 0 ) &&
+			( g_utf8_collate( NA_OBJECT_ITEM( a )->private->icon, NA_OBJECT_ITEM( b )->private->icon ) == 0 );
 	}
 
 	if( equal ){
-		g_assert( NA_IS_OBJECT_ITEM( a ));
-		first = NA_OBJECT_ITEM( a );
-
-		g_assert( NA_IS_OBJECT_ITEM( b ));
-		second = NA_OBJECT_ITEM( b );
-
-		equal =
-			( g_utf8_collate( first->private->tooltip, second->private->tooltip ) == 0 ) &&
-			( g_utf8_collate( first->private->icon, second->private->icon ) == 0 );
+		equal = ( NA_OBJECT_ITEM( a )->private->enabled && NA_OBJECT_ITEM( b )->private->enabled ) ||
+				( !NA_OBJECT_ITEM( a )->private->enabled && !NA_OBJECT_ITEM( b )->private->enabled );
 	}
 
-	return( equal );
-}
+	if( equal ){
+		equal = ( g_slist_length( NA_OBJECT_ITEM( a )->private->items ) == g_slist_length( NA_OBJECT_ITEM( b )->private->items ));
+	}
 
-gboolean
-object_is_valid( const NAObject *item )
-{
-	gboolean is_valid = TRUE;
+	if( equal ){
+		for( it = NA_OBJECT_ITEM( a )->private->items ; it && equal ; it = it->next ){
+			first_obj = NA_OBJECT( it->data );
+			first_id = na_object_get_id( first_obj );
+			second_obj = NA_OBJECT( na_object_get_item( b, first_id ));
+			g_free( first_id );
+			if( second_obj ){
+				equal = na_object_are_equal( first_obj, second_obj );
+			} else {
+				equal = FALSE;
+			}
+		}
+	}
 
-	if( is_valid ){
-		if( st_parent_class->is_valid ){
-			is_valid = st_parent_class->is_valid( item );
+	if( equal ){
+		for( it = NA_OBJECT_ITEM( b )->private->items ; it && equal ; it = it->next ){
+			second_obj = NA_OBJECT( it->data );
+			second_id = na_object_get_id( second_obj );
+			first_obj = NA_OBJECT( na_object_get_item( a, second_id ));
+			g_free( second_id );
+			if( first_obj ){
+				equal = na_object_are_equal( first_obj, second_obj );
+			} else {
+				equal = FALSE;
+			}
 		}
 	}
 
-	return( is_valid );
+	g_debug( "na_object_item_are_equal: %s", equal ? "True":"False" );
+	return( equal );
 }
 
-static void
-object_dump( const NAObject *item )
+/*
+ * from NAObjectItem point of view, all objects are valid
+ */
+static gboolean
+object_is_valid( const NAObject *object )
 {
-	static const gchar *thisfn = "na_object_item_object_dump";
-	NAObjectItem *self;
+	gboolean valid = TRUE;
+	GSList *it;
 
-	if( st_parent_class->dump ){
-		st_parent_class->dump( item );
-	}
+	g_return_val_if_fail( NA_IS_OBJECT_ITEM( object ), FALSE );
+	g_return_val_if_fail( !NA_OBJECT_ITEM( object )->private->dispose_has_run, FALSE );
 
-	g_assert( NA_IS_OBJECT_ITEM( item ));
-	self = NA_OBJECT_ITEM( item );
+	if( valid ){
+		for( it = NA_OBJECT_ITEM( object )->private->items ; it && valid ; it = it->next ){
+			valid = na_object_is_valid( it->data );
+		}
+	}
 
-	g_debug( "%s: tooltip='%s'", thisfn, self->private->tooltip );
-	g_debug( "%s:    icon='%s'", thisfn, self->private->icon );
+	return( valid );
 }
diff --git a/src/common/na-object.c b/src/common/na-object.c
index 87d4023..3746a8a 100644
--- a/src/common/na-object.c
+++ b/src/common/na-object.c
@@ -34,7 +34,8 @@
 
 #include <string.h>
 
-#include "na-object.h"
+#include "na-object-class.h"
+#include "na-object-fn.h"
 #include "na-iduplicable.h"
 
 /* private class data
@@ -46,16 +47,9 @@ struct NAObjectClassPrivate {
 /* private instance data
  */
 struct NAObjectPrivate {
-	gboolean  dispose_has_run;
-	gchar    *id;
-	gchar    *label;
+	gboolean dispose_has_run;
 };
 
-/* instance properties
- */
-#define PROP_NAOBJECT_ID_STR			"na-object-id"
-#define PROP_NAOBJECT_LABEL_STR			"na-object-label"
-
 static GObjectClass *st_parent_class = NULL;
 
 static GType          register_type( void );
@@ -63,26 +57,34 @@ 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 void           dump_hierarchy( const NAObject *object );
+static void           do_dump( const NAObject *object );
+
+static gchar         *most_derived_clipboard_id( const NAObject *object );
+
+static void           ref_hierarchy( const NAObject *object );
+
 static NAIDuplicable *iduplicable_new( const NAIDuplicable *object );
+static NAObject      *most_derived_new( const NAObject *object );
+
 static void           iduplicable_copy( NAIDuplicable *target, const NAIDuplicable *source );
+static void           copy_hierarchy( NAObject *target, const NAObject *source );
+
 static gboolean       iduplicable_are_equal( const NAIDuplicable *a, const NAIDuplicable *b );
-static gboolean       iduplicable_is_valid( const NAIDuplicable *object );
+static gboolean       are_equal_hierarchy( const NAObject *a, const NAObject *b );
+static gboolean       do_are_equal( const NAObject *a, const NAObject *b );
 
-static NAObject      *v_new( const NAObject *object );
-static void           v_copy( NAObject *target, const NAObject *source );
-static gchar         *v_get_clipboard_id( const NAObject *object );
-static gboolean       v_are_equal( const NAObject *a, const NAObject *b );
-static gboolean       v_is_valid( const NAObject *object );
+static gboolean       iduplicable_is_valid( const NAIDuplicable *object );
+static gboolean       is_valid_hierarchy( const NAObject *object );
+static gboolean       do_is_valid( 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 void           do_dump( const NAObject *object );
+
+static GSList        *get_hierarchy( const NAObject *object );
+static void           free_hierarchy( GSList *hierarchy );
 
 GType
 na_object_get_type( void )
@@ -134,7 +136,6 @@ class_init( NAObjectClass *klass )
 {
 	static const gchar *thisfn = "na_object_class_init";
 	GObjectClass *object_class;
-	GParamSpec *spec;
 
 	g_debug( "%s: klass=%p", thisfn, ( void * ) klass );
 
@@ -144,30 +145,16 @@ class_init( NAObjectClass *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;
-
-	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_clipboard_id = NULL;
+	klass->ref = NULL;
 	klass->new = NULL;
 	klass->copy = do_copy;
 	klass->are_equal = do_are_equal;
 	klass->is_valid = do_is_valid;
-	klass->dump = do_dump;
 }
 
 static void
@@ -177,8 +164,8 @@ iduplicable_iface_init( NAIDuplicableInterface *iface )
 
 	g_debug( "%s: iface=%p", thisfn, ( void * ) iface );
 
-	iface->copy = iduplicable_copy;
 	iface->new = iduplicable_new;
+	iface->copy = iduplicable_copy;
 	iface->are_equal = iduplicable_are_equal;
 	iface->is_valid = iduplicable_is_valid;
 }
@@ -186,11 +173,12 @@ iduplicable_iface_init( NAIDuplicableInterface *iface )
 static void
 instance_init( GTypeInstance *instance, gpointer klass )
 {
-	/*static const gchar *thisfn = "na_object_instance_init";*/
+	static const gchar *thisfn = "na_object_instance_init";
 	NAObject *self;
 
-	/*g_debug( "%s: instance=%p, klass=%p", thisfn, ( void * ) instance, ( void * ) klass );*/
-	g_assert( NA_IS_OBJECT( instance ));
+	g_debug( "%s: instance=%p (%s), klass=%p",
+			thisfn, ( void * ) instance, G_OBJECT_CLASS_NAME( klass ), ( void * ) klass );
+	g_return_if_fail( NA_IS_OBJECT( instance ));
 	self = NA_OBJECT( instance );
 
 	self->private = g_new0( NAObjectPrivate, 1 );
@@ -201,6 +189,11 @@ instance_init( GTypeInstance *instance, gpointer klass )
 static void
 instance_constructed( GObject *object )
 {
+	/*static const gchar *thisfn = "na_object_instance_constructed";*/
+
+	/*g_debug( "%s: object=%p", thisfn, ( void * ) object );*/
+	g_return_if_fail( NA_IS_OBJECT( object ));
+
 	na_iduplicable_init( NA_IDUPLICABLE( object ));
 
 	/* chain call to parent class */
@@ -210,109 +203,162 @@ instance_constructed( GObject *object )
 }
 
 static void
-instance_get_property( GObject *object, guint property_id, GValue *value, GParamSpec *spec )
+instance_dispose( GObject *object )
 {
+	static const gchar *thisfn = "na_object_instance_dispose";
 	NAObject *self;
 
-	g_assert( NA_IS_OBJECT( object ));
+	g_debug( "%s: object=%p", thisfn, ( void * ) object );
+	g_return_if_fail( NA_IS_OBJECT( object ));
 	self = NA_OBJECT( object );
 
-	switch( property_id ){
-		case PROP_NAOBJECT_ID:
-			g_value_set_string( value, self->private->id );
-			break;
+	if( !self->private->dispose_has_run ){
 
-		case PROP_NAOBJECT_LABEL:
-			g_value_set_string( value, self->private->label );
-			break;
+		self->private->dispose_has_run = TRUE;
 
-		default:
-			G_OBJECT_WARN_INVALID_PROPERTY_ID( object, property_id, spec );
-			break;
+		/* chain up to the parent class */
+		if( G_OBJECT_CLASS( st_parent_class )->dispose ){
+			G_OBJECT_CLASS( st_parent_class )->dispose( object );
+		}
 	}
 }
 
 static void
-instance_set_property( GObject *object, guint property_id, const GValue *value, GParamSpec *spec )
+instance_finalize( GObject *object )
 {
 	NAObject *self;
 
-	g_assert( NA_IS_OBJECT( object ));
+	g_return_if_fail( NA_IS_OBJECT( object ));
 	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;
+	g_free( self->private );
 
-		default:
-			G_OBJECT_WARN_INVALID_PROPERTY_ID( object, property_id, spec );
-			break;
+	/* chain call to parent class */
+	if( G_OBJECT_CLASS( st_parent_class )->finalize ){
+		G_OBJECT_CLASS( st_parent_class )->finalize( object );
 	}
 }
 
-static void
-instance_dispose( GObject *object )
+/**
+ * na_object_object_dump:
+ * @object: the #NAObject-derived object to be dumped.
+ *
+ * Dumps via g_debug the actual content of the object.
+ */
+void
+na_object_object_dump( const NAObject *object )
 {
-	NAObject *self;
+	g_return_if_fail( NA_IS_OBJECT( object ));
+	g_return_if_fail( !object->private->dispose_has_run );
 
-	g_assert( NA_IS_OBJECT( object ));
-	self = NA_OBJECT( object );
+	dump_hierarchy( object );
+}
 
-	if( !self->private->dispose_has_run ){
+static void
+dump_hierarchy( const NAObject *object )
+{
+	GSList *hierarchy, *ih;
 
-		self->private->dispose_has_run = TRUE;
+	hierarchy = get_hierarchy( object );
 
-		/* chain up to the parent class */
-		if( G_OBJECT_CLASS( st_parent_class )->dispose ){
-			G_OBJECT_CLASS( st_parent_class )->dispose( object );
+	for( ih = hierarchy ; ih ; ih = ih->next ){
+		if( NA_OBJECT_CLASS( ih->data )->dump ){
+			NA_OBJECT_CLASS( ih->data )->dump( object );
 		}
 	}
+
+	free_hierarchy( hierarchy );
 }
 
 static void
-instance_finalize( GObject *object )
+do_dump( const NAObject *object )
 {
-	NAObject *self;
+	static const char *thisfn = "na_object_do_dump";
 
-	g_assert( NA_IS_OBJECT( object ));
-	self = ( NAObject * ) object;
+	g_debug( "%s: object=%p", thisfn, ( void * ) object );
 
-	g_free( self->private->id );
-	g_free( self->private->label );
+	na_iduplicable_dump( NA_IDUPLICABLE( object ));
+}
 
-	g_free( self->private );
+/**
+ * na_object_object_get_clipboard_id:
+ * @object: the #NAObject-derived object for which we will get a id.
+ *
+ * Returns: a newly allocated string which contains an id for the
+ * #NAobject. This id is suitable for the internal clipboard.
+ *
+ * The returned string should be g_free() by the caller.
+ */
+gchar *
+na_object_object_get_clipboard_id( const NAObject *object )
+{
+	g_return_val_if_fail( NA_IS_OBJECT( object ), NULL );
+	g_return_val_if_fail( !object->private->dispose_has_run, NULL );
 
-	/* chain call to parent class */
-	if( G_OBJECT_CLASS( st_parent_class )->finalize ){
-		G_OBJECT_CLASS( st_parent_class )->finalize( object );
+	return( most_derived_clipboard_id( object ));
+}
+
+static gchar *
+most_derived_clipboard_id( const NAObject *object )
+{
+	gchar *clipboard_id;
+	GSList *hierarchy, *ih;
+	gboolean found;
+
+	found = FALSE;
+	clipboard_id = NULL;
+	hierarchy = g_slist_reverse( get_hierarchy( object ));
+
+	for( ih = hierarchy ; ih && !found ; ih = ih->next ){
+		if( NA_OBJECT_CLASS( ih->data )->get_clipboard_id ){
+			clipboard_id = NA_OBJECT_CLASS( ih->data )->get_clipboard_id( object );
+			found = TRUE;
+		}
 	}
+
+	free_hierarchy( hierarchy );
+
+	return( clipboard_id );
 }
 
 /**
- * na_object_dump:
- * @object: the #NAObject object to be dumped.
+ * TODO: get ride of this
+ * na_object_object_ref:
+ * @object: the #NAObject-derived object to be reffed.
  *
- * Dumps via g_debug the content of the object.
+ * Returns: a ref on the #NAobject.
+ *
+ * If the object has childs, then it should also have reffed them.
  */
-void
-na_object_dump( const NAObject *object )
+NAObject *
+na_object_object_ref( const NAObject *object )
+{
+	g_return_val_if_fail( NA_IS_OBJECT( object ), NULL );
+	g_return_val_if_fail( !object->private->dispose_has_run, NULL );
+
+	ref_hierarchy( object );
+
+	return( g_object_ref(( gpointer ) object ));
+}
+
+static void
+ref_hierarchy( const NAObject *object )
 {
-	if( object ){
-		g_assert( NA_IS_OBJECT( object ));
+	GSList *hierarchy, *ih;
+
+	hierarchy = get_hierarchy( object );
 
-		NA_OBJECT_GET_CLASS( object )->dump( object );
+	for( ih = hierarchy ; ih ; ih = ih->next ){
+		if( NA_OBJECT_CLASS( ih->data )->ref ){
+			NA_OBJECT_CLASS( ih->data )->ref( object );
+		}
 	}
+
+	free_hierarchy( hierarchy );
 }
 
 /**
- * na_object_duplicate:
+ * na_object_iduplicable_duplicate:
  * @object: the #NAObject object to be dumped.
  *
  * Exactly duplicates a #NAObject-derived object.
@@ -322,8 +368,8 @@ na_object_dump( const NAObject *object )
  *     na_object_duplicate( origin )
  *      +- na_iduplicable_duplicate( origin )
  *      |   +- dup = duplicate( origin )
- *      |   |   +- dup = v_get_new_object()	-> interface get_new_object
- *      |   |   +- v_copy( dup, origin )	-> interface copy
+ *      |   |   +- dup = v_new( object ) -> interface new()
+ *      |   |   +- v_copy( dup, origin ) -> interface copy()
  *      |   |
  *      |   +- set_origin( dup, origin )
  *      |   +- set_modified( dup, FALSE )
@@ -332,77 +378,112 @@ na_object_dump( const NAObject *object )
  *      +- na_object_check_edited_status
  */
 NAObject *
-na_object_duplicate( const NAObject *object )
+na_object_iduplicable_duplicate( const NAObject *object )
 {
 	NAIDuplicable *duplicate;
 
-	g_assert( NA_IS_OBJECT( object ));
+	g_return_val_if_fail( NA_IS_OBJECT( object ), NULL );
+	g_return_val_if_fail( NA_IS_IDUPLICABLE( object ), NULL );
+	g_return_val_if_fail( !object->private->dispose_has_run, NULL );
 
 	duplicate = na_iduplicable_duplicate( NA_IDUPLICABLE( object ));
 
-	na_object_check_edited_status( NA_OBJECT( duplicate ));
+	/*g_debug( "na_object_iduplicable_duplicate: object is %s at %p, duplicate is %s at %p",
+			G_OBJECT_TYPE_NAME( object ), ( void * ) object,
+			duplicate ? G_OBJECT_TYPE_NAME( duplicate ) : "", ( void * ) duplicate );*/
+
+	/*if( duplicate ){
+		na_iduplicable_check_edition_status( duplicate );
+	}*/
 
 	return( NA_OBJECT( duplicate ));
 }
 
+static NAIDuplicable *
+iduplicable_new( const NAIDuplicable *object )
+{
+	g_return_val_if_fail( NA_IS_OBJECT( object ), NULL );
+	g_return_val_if_fail( !NA_OBJECT( object )->private->dispose_has_run, NULL );
+
+	return( NA_IDUPLICABLE( most_derived_new( NA_OBJECT( object ))));
+}
+
+static NAObject *
+most_derived_new( const NAObject *object )
+{
+	NAObject *new_object;
+	GSList *hierarchy, *ih;
+	gboolean found;
+
+	found = FALSE;
+	new_object = NULL;
+	hierarchy = g_slist_reverse( get_hierarchy( object ));
+
+	for( ih = hierarchy ; ih && !found ; ih = ih->next ){
+		if( NA_OBJECT_CLASS( ih->data )->new ){
+			new_object = NA_OBJECT_CLASS( ih->data )->new( object );
+			found = TRUE;
+		}
+	}
+
+	free_hierarchy( hierarchy );
+
+	return( new_object );
+}
+
 /**
- * na_object_copy:
+ * na_object_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 )
+na_object_object_copy( NAObject *target, const NAObject *source )
 {
-	g_assert( NA_IS_OBJECT( target ));
-	g_assert( NA_IS_OBJECT( source ));
+	g_return_if_fail( NA_IS_OBJECT( target ));
+	g_return_if_fail( !target->private->dispose_has_run );
+	g_return_if_fail( NA_IS_OBJECT( source ));
+	g_return_if_fail( !source->private->dispose_has_run );
 
-	v_copy( target, source );
+	copy_hierarchy( target, source );
 }
 
-/**
- * na_object_get_clipboard_id:
- * @object: the #NAObject-derived object for which we will get a id.
- *
- * Returns: a newly allocated string which contains an id for the
- * #NAobject. This id is suitable for the internal clipboard.
- *
- * The returned string should be g_free() by the caller.
- */
-gchar *
-na_object_get_clipboard_id( const NAObject *object )
+static void
+iduplicable_copy( NAIDuplicable *target, const NAIDuplicable *source )
 {
-	g_assert( NA_IS_OBJECT( object ));
+	g_return_if_fail( NA_IS_OBJECT( target ));
+	g_return_if_fail( !NA_OBJECT( target )->private->dispose_has_run );
+	g_return_if_fail( NA_IS_OBJECT( source ));
+	g_return_if_fail( !NA_OBJECT( source )->private->dispose_has_run );
 
-	return( v_get_clipboard_id( object ));
+	copy_hierarchy( NA_OBJECT( target ), NA_OBJECT( source ));
 }
 
-/**
- * na_object_check_edited_status:
- * @object: the #NAObject object to be checked.
- *
- * Checks for the edition status of @object.
- *
- * Internally set some properties which may be requested later. This
- * two-steps check-request let us optimize some work in the UI.
- *
- * na_object_check_edited_status( object )
- *  +- na_iduplicable_check_edited_status( object )
- *      +- get_origin( object )
- *      +- modified_status = v_are_equal( origin, object )	-> interface are_equal
- *      +- valid_status = v_is_valid( object )				-> interface is_valid
- */
-void
-na_object_check_edited_status( const NAObject *object )
+static void
+copy_hierarchy( NAObject *target, const NAObject *source )
 {
-	g_assert( NA_IS_OBJECT( object ));
+	GSList *hierarchy, *ih;
+
+	hierarchy = get_hierarchy( source );
 
-	na_iduplicable_check_edited_status( NA_IDUPLICABLE( object ));
+	for( ih = hierarchy ; ih ; ih = ih->next ){
+		if( NA_OBJECT_CLASS( ih->data )->copy ){
+			NA_OBJECT_CLASS( ih->data )->copy( target, source );
+		}
+	}
+
+	free_hierarchy( hierarchy );
+}
+
+static void
+do_copy( NAObject *target, const NAObject *source )
+{
+	/* nothing to do here */
 }
 
 /**
- * na_object_are_equal:
+ * na_object_iduplicable_are_equal:
  * @a: a first #NAObject object.
  * @b: a second #NAObject object to be compared to the first one.
  *
@@ -415,32 +496,118 @@ na_object_check_edited_status( const NAObject *object )
  * Returns: %TRUE if @a and @b are identical, %FALSE else.
  */
 gboolean
-na_object_are_equal( const NAObject *a, const NAObject *b )
+na_object_iduplicable_are_equal( const NAObject *a, const NAObject *b )
 {
-	g_assert( NA_IS_OBJECT( a ));
-	g_assert( NA_IS_OBJECT( b ));
+	g_return_val_if_fail( NA_IS_OBJECT( a ), FALSE );
+	g_return_val_if_fail( !a->private->dispose_has_run, FALSE );
+	g_return_val_if_fail( NA_IS_OBJECT( b ), FALSE );
+	g_return_val_if_fail( !b->private->dispose_has_run, FALSE );
 
-	return( v_are_equal( a, b ));
+	return( are_equal_hierarchy( a, b ));
+}
+
+static gboolean
+iduplicable_are_equal( const NAIDuplicable *a, const NAIDuplicable *b )
+{
+	g_return_val_if_fail( NA_IS_OBJECT( a ), FALSE );
+	g_return_val_if_fail( !NA_OBJECT( a )->private->dispose_has_run, FALSE );
+	g_return_val_if_fail( NA_IS_OBJECT( b ), FALSE );
+	g_return_val_if_fail( !NA_OBJECT( b )->private->dispose_has_run, FALSE );
+
+	return( are_equal_hierarchy( NA_OBJECT( a ), NA_OBJECT( b )));
+}
+
+static gboolean
+are_equal_hierarchy( const NAObject *a, const NAObject *b )
+{
+	gboolean are_equal;
+	GSList *hierarchy, *ih;
+
+	are_equal = TRUE;
+	hierarchy = get_hierarchy( b );
+
+	for( ih = hierarchy ; ih && are_equal ; ih = ih->next ){
+		if( NA_OBJECT_CLASS( ih->data )->are_equal ){
+			are_equal = NA_OBJECT_CLASS( ih->data )->are_equal( a, b );
+		}
+	}
+
+	free_hierarchy( hierarchy );
+
+	return( are_equal );
+}
+
+static gboolean
+do_are_equal( const NAObject *a, const NAObject *b )
+{
+	/*g_debug( "na_object_do_are_equal: a=%s at %p, b=%s at %p",
+			G_OBJECT_TYPE_NAME( a ), ( void * ) a, G_OBJECT_TYPE_NAME( b ), ( void * ) b );*/
+
+	/* as there is no data in NAObject, they are considered here as
+	 * equal is both null or both not null
+	 */
+	return(( a && b ) || ( !a && !b ));
+}
+
+static gboolean
+iduplicable_is_valid( const NAIDuplicable *object )
+{
+	return( is_valid_hierarchy( NA_OBJECT( object )));
+}
+
+static gboolean
+is_valid_hierarchy( const NAObject *object )
+{
+	gboolean is_valid;
+	GSList *hierarchy, *ih;
+
+	is_valid = TRUE;
+	hierarchy = get_hierarchy( object );
+
+	for( ih = hierarchy ; ih && is_valid ; ih = ih->next ){
+		if( NA_OBJECT_CLASS( ih->data )->is_valid ){
+			is_valid = NA_OBJECT_CLASS( ih->data )->is_valid( object );
+		}
+	}
+
+	free_hierarchy( hierarchy );
+
+	return( is_valid );
+}
+
+static gboolean
+do_is_valid( const NAObject *object )
+{
+	/* as there is no data in NAObject, it is always valid */
+	return( object ? TRUE : FALSE );
 }
 
 /**
- * na_object_get_is_valid:
- * @object: the #NAObject object whose validity is to be checked.
+ * na_object_iduplicable_check_edition_status:
+ * @object: the #NAObject object to be checked.
  *
- * Checks for the validity of @object.
+ * Checks for the edition status of @object.
  *
- * Returns: %TRUE is @object is valid, %FALSE else.
+ * Internally set some properties which may be requested later. This
+ * two-steps check-request let us optimize some work in the UI.
+ *
+ * na_object_check_edition_status( object )
+ *  +- na_iduplicable_check_edition_status( object )
+ *      +- get_origin( object )
+ *      +- modified_status = v_are_equal( origin, object ) -> interface are_equal()
+ *      +- valid_status = v_is_valid( object )             -> interface is_valid()
  */
-gboolean
-na_object_is_valid( const NAObject *object )
+void
+na_object_iduplicable_check_edition_status( const NAObject *object )
 {
-	g_assert( NA_IS_OBJECT( object ));
+	g_return_if_fail( NA_IS_OBJECT( object ));
+	g_return_if_fail( !object->private->dispose_has_run );
 
-	return( v_is_valid( object ));
+	na_iduplicable_check_edition_status( NA_IDUPLICABLE( object ));
 }
 
 /**
- * na_object_get_modified_status:
+ * na_object_iduplicable_is_modified:
  * @object: the #NAObject object whose status is requested.
  *
  * Returns the current modification status of @object.
@@ -455,37 +622,33 @@ na_object_is_valid( const NAObject *object )
  * the original one, %FALSE else.
  */
 gboolean
-na_object_get_modified_status( const NAObject *object )
+na_object_iduplicable_is_modified( const NAObject *object )
 {
-	g_assert( NA_IS_OBJECT( object ));
+	g_return_val_if_fail( NA_IS_OBJECT( object ), FALSE );
+	g_return_val_if_fail( !object->private->dispose_has_run, FALSE );
 
 	return( na_iduplicable_is_modified( NA_IDUPLICABLE( 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.
+ * na_object_iduplicable_is_valid:
+ * @object: the #NAObject object whose validity is to be checked.
  *
- * This suppose also that the edition status of @object has previously
- * been checked via na_object_check_edited_status().
+ * Gets the validity status of @object.
  *
- * Returns: %TRUE is the provided object is valid, %FALSE else.
+ * Returns: %TRUE is @object is valid, %FALSE else.
  */
 gboolean
-na_object_get_valid_status( const NAObject *object )
+na_object_iduplicable_is_valid( const NAObject *object )
 {
-	g_assert( NA_IS_OBJECT( object ));
+	g_return_val_if_fail( NA_IS_OBJECT( object ), FALSE );
+	g_return_val_if_fail( !object->private->dispose_has_run, FALSE );
 
 	return( na_iduplicable_is_valid( NA_IDUPLICABLE( object )));
 }
 
 /**
- * na_object_get_origin:
+ * na_object_iduplicable_get_origin:
  * @object: the #NAObject object whose status is requested.
  *
  * Returns the original object which was at the origin of @object.
@@ -493,223 +656,56 @@ na_object_get_valid_status( const NAObject *object )
  * Returns: a #NAObject, or NULL.
  */
 NAObject *
-na_object_get_origin( const NAObject *object )
+na_object_iduplicable_get_origin( const NAObject *object )
 {
-	g_assert( NA_IS_OBJECT( object ));
+	g_return_val_if_fail( NA_IS_OBJECT( object ), NULL );
+	g_return_val_if_fail( !object->private->dispose_has_run, NULL );
 
 	return( NA_OBJECT( na_iduplicable_get_origin( NA_IDUPLICABLE( object ))));
 }
 
 /**
- * na_object_get_id:
- * @object: the #NAObject object whose internal identifiant is
- * requested.
- *
- * 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 )
-{
-	gchar *id;
-
-	g_assert( NA_IS_OBJECT( object ));
-
-	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.
- *
- * Returns the label of @object.
- *
- * 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 )
-{
-	gchar *label;
-
-	g_assert( NA_IS_OBJECT( object ));
-
-	g_object_get( G_OBJECT( object ), PROP_NAOBJECT_LABEL_STR, &label, NULL );
-
-	return( label );
-}
-
-/**
- * na_object_set_origin:
- * @object: the #NAObject object whose status is requested.
+ * na_object_iduplicable_set_origin:
+ * @object: the #NAObject object whose origin is to be set.
  * @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 )
+na_object_iduplicable_set_origin( NAObject *object, const NAObject *origin )
 {
-	g_assert( NA_IS_OBJECT( object ));
-	g_assert( NA_IS_OBJECT( origin ) || !origin );
+	g_return_if_fail( NA_IS_OBJECT( object ));
+	g_return_if_fail( !object->private->dispose_has_run );
+	g_return_if_fail( NA_IS_OBJECT( origin ) || !origin );
+	g_return_if_fail( !origin || !origin->private->dispose_has_run );
 
 	na_iduplicable_set_origin( NA_IDUPLICABLE( object ), NA_IDUPLICABLE( origin ));
 }
 
-/**
- * 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.
+/*
+ * returns the class hierarchy,
+ * from the topmost base class, to the most-derived 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 NAIDuplicable *
-iduplicable_new( const NAIDuplicable *object )
-{
-	return( NA_IDUPLICABLE( v_new( NA_OBJECT( object ))));
-}
-
-static void
-iduplicable_copy( NAIDuplicable *target, const NAIDuplicable *source )
-{
-	v_copy( NA_OBJECT( target ), NA_OBJECT( source ));
-}
-
-static gboolean
-iduplicable_are_equal( const NAIDuplicable *a, const NAIDuplicable *b )
-{
-	return( v_are_equal( NA_OBJECT( a ), NA_OBJECT( b )));
-}
-
-static gboolean
-iduplicable_is_valid( const NAIDuplicable *object )
-{
-	return( v_is_valid( NA_OBJECT( object )));
-}
-
-static NAObject *
-v_new( const NAObject *object )
-{
-	if( NA_OBJECT_GET_CLASS( object )->new ){
-		return( NA_OBJECT_GET_CLASS( object )->new( 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 gchar *
-v_get_clipboard_id( const NAObject *object )
-{
-	if( NA_OBJECT_GET_CLASS( object )->get_clipboard_id ){
-		return( NA_OBJECT_GET_CLASS( object )->get_clipboard_id( object ));
-	}
-
-	return( NULL );
-}
-
-static gboolean
-v_are_equal( const NAObject *a, const NAObject *b )
+static GSList *
+get_hierarchy( const NAObject *object )
 {
-	if( NA_OBJECT_GET_CLASS( a )->are_equal ){
-		return( NA_OBJECT_GET_CLASS( a )->are_equal( a, b ));
-	}
+	GSList *hierarchy;
+	GObjectClass *class;
 
-	return( FALSE );
-}
+	hierarchy = NULL;
+	class = G_OBJECT_GET_CLASS( object );
 
-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 ));
+	while( G_OBJECT_CLASS_TYPE( class ) != NA_OBJECT_TYPE ){
+		hierarchy = g_slist_prepend( hierarchy, class );
+		class = g_type_class_peek_parent( class );
 	}
+	hierarchy = g_slist_prepend( hierarchy, class );
 
-	return( TRUE );
+	return( hierarchy );
 }
 
 static void
-do_copy( NAObject *target, const NAObject *source )
-{
-	gchar *id, *label;
-
-	id = na_object_get_id( source );
-	na_object_set_id( target, id );
-	g_free( id );
-
-	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 )
+free_hierarchy( GSList *hierarchy )
 {
-	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 );
-}
-
-/*
- * from NAObject point of view, a valid object requires an id
- * (not null, not empty)
- */
-static gboolean
-do_is_valid( const NAObject *object )
-{
-	return( object->private->id && strlen( object->private->id ));
-}
-
-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, ( void * ) object );
-	g_debug( "%s:     id=%s", thisfn, object->private->id );
-	g_debug( "%s:  label=%s", thisfn, object->private->label );
-
-	na_iduplicable_dump( NA_IDUPLICABLE( object ));
+	g_slist_free( hierarchy );
 }
diff --git a/src/common/na-pivot.c b/src/common/na-pivot.c
index 223f226..6b390fe 100644
--- a/src/common/na-pivot.c
+++ b/src/common/na-pivot.c
@@ -35,11 +35,12 @@
 #include <string.h>
 #include <uuid/uuid.h>
 
-#include "na-action.h"
-#include "na-gconf.h"
-#include "na-pivot.h"
+#include "na-object-api.h"
+#include "na-object-item-class.h"
 #include "na-iio-provider.h"
-#include "na-ipivot-consumer.h"
+#include "na-gconf-provider.h"
+#include "na-iprefs.h"
+#include "na-pivot.h"
 #include "na-utils.h"
 
 /* private class data
@@ -56,25 +57,32 @@ struct NAPivotPrivate {
 	/* list of instances to be notified of an action modification
 	 * these are called 'consumers' of NAPivot
 	 */
-	GSList  *notified;
+	GSList  *consumers;
 
-	/* list of interface providers
+	/* list of NAIIOProvider interface providers
 	 * needs to be in the instance rather than in the class to be able
 	 * to pass NAPivot object to the IO provider, so that the later
 	 * is able to have access to the former (and its list of actions)
 	 */
 	GSList  *providers;
 
-	/* list of actions
+	/* configuration tree
+	 */
+	GSList  *tree;
+
+	/* whether to automatically reload the whole configuration tree
+	 * when a modification has been detected in one of the underlying
+	 * I/O storage subsystems
+	 * defaults to FALSE
 	 */
-	GSList  *actions;
 	gboolean automatic_reload;
 };
 
 enum {
 	ACTION_CHANGED,
-	DISPLAY_ORDER_CHANGE,
-	DISPLAY_ABOUT_CHANGE,
+	LEVEL_ZERO_CHANGED,
+	DISPLAY_ORDER_CHANGED,
+	DISPLAY_ABOUT_CHANGED,
 	LAST_SIGNAL
 };
 
@@ -87,12 +95,20 @@ static gint          st_timeout_usec = 100000;
 
 static GType    register_type( void );
 static void     class_init( NAPivotClass *klass );
+static void     iprefs_iface_init( NAIPrefsInterface *iface );
 static void     instance_init( GTypeInstance *instance, gpointer klass );
-static GSList  *register_interface_providers( const NAPivot *pivot );
 static void     instance_dispose( GObject *object );
 static void     instance_finalize( GObject *object );
 
+/* NAIPivotConsumer management */
 static void     free_consumers( GSList *list );
+
+/* NAIIOProvider management */
+static void     register_io_providers( NAPivot *pivot );
+
+/* NAGConf runtime preferences management */
+static void     read_runtime_preferences( NAPivot *pivot );
+
 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 );
@@ -130,10 +146,18 @@ register_type( void )
 		( GInstanceInitFunc ) instance_init
 	};
 
+	static const GInterfaceInfo iprefs_iface_info = {
+		( GInterfaceInitFunc ) iprefs_iface_init,
+		NULL,
+		NULL
+	};
+
 	g_debug( "%s", thisfn );
 
 	type = g_type_register_static( G_TYPE_OBJECT, "NAPivot", &info, 0 );
 
+	g_type_add_interface_static( type, NA_IPREFS_TYPE, &iprefs_iface_info );
+
 	return( type );
 }
 
@@ -169,7 +193,7 @@ class_init( NAPivotClass *klass )
 				1,
 				G_TYPE_POINTER
 	);
-	st_signals[ DISPLAY_ORDER_CHANGE ] = g_signal_new_class_handler(
+	st_signals[ DISPLAY_ORDER_CHANGED ] = g_signal_new_class_handler(
 				NA_IIO_PROVIDER_SIGNAL_DISPLAY_ORDER_CHANGED,
 				G_TYPE_FROM_CLASS( klass ),
 				G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
@@ -181,7 +205,7 @@ class_init( NAPivotClass *klass )
 				1,
 				G_TYPE_POINTER
 	);
-	st_signals[ DISPLAY_ABOUT_CHANGE ] = g_signal_new_class_handler(
+	st_signals[ DISPLAY_ABOUT_CHANGED ] = g_signal_new_class_handler(
 				NA_IIO_PROVIDER_SIGNAL_DISPLAY_ABOUT_CHANGED,
 				G_TYPE_FROM_CLASS( klass ),
 				G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
@@ -196,36 +220,30 @@ class_init( NAPivotClass *klass )
 }
 
 static void
+iprefs_iface_init( NAIPrefsInterface *iface )
+{
+	static const gchar *thisfn = "na_pivot_iprefs_iface_init";
+
+	g_debug( "%s: iface=%p", thisfn, ( void * ) iface );
+}
+
+static void
 instance_init( GTypeInstance *instance, gpointer klass )
 {
 	static const gchar *thisfn = "na_pivot_instance_init";
 	NAPivot *self;
 
 	g_debug( "%s: instance=%p, klass=%p", thisfn, ( void * ) instance, ( void * ) klass );
-
-	g_assert( NA_IS_PIVOT( instance ));
+	g_return_if_fail( NA_IS_PIVOT( instance ));
 	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( self );
-	self->private->automatic_reload = TRUE;
-}
-
-static GSList *
-register_interface_providers( const NAPivot *pivot )
-{
-	static const gchar *thisfn = "na_pivot_register_interface_providers";
-	GSList *list = NULL;
-
-	g_debug( "%s: pivot=%p", thisfn, ( void * ) pivot );
-
-	list = g_slist_prepend( list, na_gconf_new( G_OBJECT( pivot )));
-
-	return( list );
+	self->private->consumers = NULL;
+	self->private->providers = NULL;
+	self->private->tree = NULL;
+	self->private->automatic_reload = FALSE;
 }
 
 static void
@@ -235,23 +253,29 @@ instance_dispose( GObject *object )
 	NAPivot *self;
 
 	g_debug( "%s: object=%p", thisfn, ( void * ) object );
-
-	g_assert( NA_IS_PIVOT( object ));
+	g_return_if_fail( NA_IS_PIVOT( object ));
 	self = NA_PIVOT( object );
 
 	if( !self->private->dispose_has_run ){
 
 		self->private->dispose_has_run = TRUE;
 
-		/* release list of containers to be notified */
-		free_consumers( self->private->notified );
+		/* release list of NAIPivotConsumers */
+		free_consumers( self->private->consumers );
+		self->private->consumers = NULL;
+
+		/* release list of NAIIOProviders */
+		na_pivot_free_providers( self->private->providers );
+		self->private->providers = NULL;
 
-		/* release list of actions */
-		na_pivot_free_actions( self->private->actions );
-		self->private->actions = NULL;
+		/* release item tree */
+		na_pivot_free_items_tree( self->private->tree );
+		self->private->tree = NULL;
 
 		/* chain up to the parent class */
-		G_OBJECT_CLASS( st_parent_class )->dispose( object );
+		if( G_OBJECT_CLASS( st_parent_class )->dispose ){
+			G_OBJECT_CLASS( st_parent_class )->dispose( object );
+		}
 	}
 }
 
@@ -260,24 +284,15 @@ instance_finalize( GObject *object )
 {
 	static const gchar *thisfn = "na_pivot_instance_finalize";
 	NAPivot *self;
-	GSList *ip;
 
 	g_debug( "%s: object=%p", thisfn, ( void * ) object );
-
-	g_assert( NA_IS_PIVOT( object ));
-	self = ( NAPivot * ) object;
-
-	/* release the interface providers */
-	for( ip = self->private->providers ; ip ; ip = ip->next ){
-		g_object_unref( G_OBJECT( ip->data ));
-	}
-	g_slist_free( self->private->providers );
-	self->private->providers = NULL;
+	g_return_if_fail( NA_IS_PIVOT( object ));
+	self = NA_PIVOT( object );
 
 	g_free( self->private );
 
 	/* chain call to parent class */
-	if((( GObjectClass * ) st_parent_class )->finalize ){
+	if( G_OBJECT_CLASS( st_parent_class )->finalize ){
 		G_OBJECT_CLASS( st_parent_class )->finalize( object );
 	}
 }
@@ -293,14 +308,26 @@ instance_finalize( GObject *object )
  * message, without any parameter.
  */
 NAPivot *
-na_pivot_new( const GObject *target )
+na_pivot_new( const NAIPivotConsumer *target )
 {
-	NAPivot *pivot = g_object_new( NA_PIVOT_TYPE, NULL );
+	static const gchar *thisfn = "na_pivot_new";
+	NAPivot *pivot;
+
+	g_debug( "%s: target=%p", thisfn, ( void * ) target );
+	g_return_val_if_fail( NA_IS_IPIVOT_CONSUMER( target ) || !target, NULL );
+
+	pivot = g_object_new( NA_PIVOT_TYPE, NULL );
+
+	register_io_providers( pivot );
 
 	if( target ){
-		na_pivot_add_consumer( pivot, target );
+		na_pivot_register_consumer( pivot, target );
 	}
 
+	read_runtime_preferences( pivot );
+
+	pivot->private->tree = na_iio_provider_get_items_tree( pivot );
+
 	return( pivot );
 }
 
@@ -317,12 +344,12 @@ na_pivot_dump( const NAPivot *pivot )
 	GSList *it;
 	int i;
 
-	g_debug( "%s:  notified=%p (%d elts)", thisfn, ( void * ) pivot->private->notified, g_slist_length( pivot->private->notified ));
+	g_debug( "%s: consumers=%p (%d elts)", thisfn, ( void * ) pivot->private->consumers, g_slist_length( pivot->private->consumers ));
 	g_debug( "%s: providers=%p (%d elts)", thisfn, ( void * ) pivot->private->providers, g_slist_length( pivot->private->providers ));
-	g_debug( "%s:   actions=%p (%d elts)", thisfn, ( void * ) pivot->private->actions, g_slist_length( pivot->private->actions ));
+	g_debug( "%s:      tree=%p (%d elts)", thisfn, ( void * ) pivot->private->tree, g_slist_length( pivot->private->tree ));
 
-	for( it = pivot->private->actions, i = 0 ; it ; it = it->next ){
-		g_debug( "%s:   [%d]: %p", thisfn, i++, it->data );
+	for( it = pivot->private->tree, i = 0 ; it ; it = it->next ){
+		g_debug( "%s:     [%d]: %p", thisfn, i++, it->data );
 	}
 }
 
@@ -332,13 +359,12 @@ na_pivot_dump( const NAPivot *pivot )
  * @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.
+ * Returns: a newly allocated 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.
+ * list of providers registered for their own given interface.
  *
- * Returns: the list of providers of the required interface.
- * This list should be na_pivot_free_providers().
+ * The returned list should be release by calling na_pivot_free_providers().
  */
 GSList *
 na_pivot_get_providers( const NAPivot *pivot, GType type )
@@ -348,11 +374,12 @@ na_pivot_get_providers( const NAPivot *pivot, GType type )
 	GSList *ip;
 
 	g_debug( "%s: pivot=%p", thisfn, ( void * ) pivot );
-	g_assert( NA_IS_PIVOT( pivot ));
+	g_return_val_if_fail( NA_IS_PIVOT( pivot ), NULL );
+	g_return_val_if_fail( !pivot->private->dispose_has_run, NULL );
 
 	for( ip = pivot->private->providers ; ip ; ip = ip->next ){
 		if( G_TYPE_CHECK_INSTANCE_TYPE( G_OBJECT( ip->data ), type )){
-			list = g_slist_prepend( list, ip->data );
+			list = g_slist_prepend( list, g_object_ref( ip->data ));
 		}
 	}
 
@@ -368,43 +395,45 @@ na_pivot_get_providers( const NAPivot *pivot, GType type )
 void
 na_pivot_free_providers( GSList *providers )
 {
+	g_slist_foreach( providers, ( GFunc ) g_object_unref, NULL );
 	g_slist_free( providers );
 }
 
 /**
- * na_pivot_get_actions:
+ * na_pivot_get_items_tree:
  * @pivot: this #NAPivot instance.
  *
- * Returns the list of actions.
+ * Returns: the current configuration tree.
  *
- * 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 )
+na_pivot_get_items_tree( const NAPivot *pivot )
 {
-	g_assert( NA_IS_PIVOT( pivot ));
+	g_return_val_if_fail( NA_IS_PIVOT( pivot ), NULL );
+	g_return_val_if_fail( !pivot->private->dispose_has_run, NULL );
 
-	return( pivot->private->actions );
+	return( pivot->private->tree );
 }
 
 /**
- * na_pivot_reload_actions:
+ * na_pivot_reload_items_tree:
  * @pivot: this #NAPivot instance.
  *
- * Reloads the list of actions from I/O providers.
+ * Reloads the hierarchical list of items from I/O providers.
  */
 void
-na_pivot_reload_actions( NAPivot *pivot )
+na_pivot_reload_items_tree( NAPivot *pivot )
 {
-	g_assert( NA_IS_PIVOT( pivot ));
+	g_return_if_fail( NA_IS_PIVOT( pivot ));
+	g_return_if_fail( !pivot->private->dispose_has_run );
 
-	if( pivot->private->actions ){
-		na_pivot_free_actions( pivot->private->actions );
+	if( pivot->private->tree ){
+		na_pivot_free_items_tree( pivot->private->tree );
 	}
 
-	pivot->private->actions = na_iio_provider_read_actions( pivot );
+	pivot->private->tree = na_iio_provider_get_items_tree( pivot );
 }
 
 /**
@@ -416,7 +445,7 @@ na_pivot_reload_actions( NAPivot *pivot )
  * Returns: a #GSList of #NAAction actions.
  * The caller should na_pivot_free_actions() after usage.
  */
-GSList *
+/*GSList *
 na_pivot_get_duplicate_actions( const NAPivot *pivot )
 {
 	GSList *list = NULL;
@@ -429,60 +458,61 @@ na_pivot_get_duplicate_actions( const NAPivot *pivot )
 	}
 
 	return( g_slist_reverse( list ));
-}
+}*/
 
 /**
- * na_pivot_free_actions:
- * @list: a #GSList of #NAActions to be freed.
+ * na_pivot_free_items_tree:
+ * @list: a #GSList of #NAObjectItems to be released.
  *
- * Frees a list of actions.
+ * Frees a hierarchical tree of items.
  */
-void
-na_pivot_free_actions( GSList *actions )
+GSList *
+na_pivot_free_items_tree( GSList *tree )
 {
-	GSList *ia;
+	g_slist_foreach( tree, ( GFunc ) g_object_unref, NULL );
+	g_slist_free( tree );
 
-	for( ia = actions ; ia ; ia = ia->next ){
-		g_object_unref( NA_ACTION( ia->data ));
-	}
-
-	g_slist_free( actions );
+	return( NULL );
 }
 
 /**
- * na_pivot_add_action:
+ * na_pivot_add_item:
  * @pivot: this #NAPivot instance.
- * @action: the #NAAction to be added to the list.
+ * @item: the #NAObjectItem to be added to the list.
  *
- * Adds a new #NAAction to the list of actions.
+ * Adds a new item to the list.
  *
- * We take the provided pointer. The provided #NAAction should so not
+ * We take the provided pointer. The provided @item should so not
  * be g_object_unref() by the caller.
  */
 void
-na_pivot_add_action( NAPivot *pivot, const NAAction *action )
+na_pivot_add_item( NAPivot *pivot, const NAObject *item )
 {
-	g_assert( NA_IS_PIVOT( pivot ));
+	g_return_if_fail( NA_IS_PIVOT( pivot ));
+	g_return_if_fail( !pivot->private->dispose_has_run );
+	g_return_if_fail( NA_IS_OBJECT_ITEM( item ));
 
-	pivot->private->actions = g_slist_prepend( pivot->private->actions, ( gpointer ) action );
+	pivot->private->tree = g_slist_append( pivot->private->tree, ( gpointer ) item );
 }
 
 /**
- * na_pivot_remove_action:
+ * na_pivot_remove_item:
  * @pivot: this #NAPivot instance.
- * @action: the #NAAction to be removed to the list.
+ * @item: the #NAObjectItem to be removed from the list.
  *
- * Removes a #NAAction from the list of actions.
+ * Removes a #NAObjectItem from the hierarchical tree.
  *
- * Note that #NAPivot also g_object_unref() the removed #NAAction.
+ * Note that #NAPivot also g_object_unref() the removed #NAObjectItem.
  */
 void
-na_pivot_remove_action( NAPivot *pivot, NAAction *action )
+na_pivot_remove_item( NAPivot *pivot, NAObject *item )
 {
-	g_assert( NA_IS_PIVOT( pivot ));
+	g_return_if_fail( NA_IS_PIVOT( pivot ));
+	g_return_if_fail( !pivot->private->dispose_has_run );
+	g_return_if_fail( NA_IS_OBJECT_ITEM( item ));
 
-	pivot->private->actions = g_slist_remove( pivot->private->actions, ( gconstpointer ) action );
-	g_object_unref( action );
+	pivot->private->tree = g_slist_remove( pivot->private->tree, ( gconstpointer ) item );
+	g_object_unref( item );
 }
 
 /**
@@ -496,27 +526,29 @@ na_pivot_remove_action( NAPivot *pivot, NAAction *action )
  * The returned pointer is owned by #NAPivot, and should not be
  * g_free() nor g_object_unref() by the caller.
  */
-NAAction *
-na_pivot_get_action( const NAPivot *pivot, const gchar *uuid )
+NAObject *
+na_pivot_get_item( const NAPivot *pivot, const gchar *uuid )
 {
 	uuid_t uua, i_uub;
 	GSList *ia;
 
-	g_assert( NA_IS_PIVOT( pivot ));
+	g_return_val_if_fail( NA_IS_PIVOT( pivot ), NULL );
+	g_return_val_if_fail( !pivot->private->dispose_has_run, NULL );
+
 	if( !uuid || !strlen( uuid )){
 		return( NULL );
 	}
 
 	uuid_parse( uuid, uua );
 
-	for( ia = pivot->private->actions ; ia ; ia = ia->next ){
+	for( ia = pivot->private->tree ; ia ; ia = ia->next ){
 
-		gchar *i_uuid = na_action_get_uuid( NA_ACTION( ia->data ));
+		gchar *i_uuid = na_object_get_id( NA_OBJECT( ia->data ));
 		uuid_parse( i_uuid, i_uub );
 		g_free( i_uuid );
 
 		if( !uuid_compare( uua, i_uub )){
-			return( NA_ACTION( ia->data ));
+			return( NA_OBJECT( ia->data ));
 		}
 	}
 
@@ -524,30 +556,31 @@ na_pivot_get_action( const NAPivot *pivot, const gchar *uuid )
 }
 
 /**
- * na_pivot_write_action:
+ * na_pivot_write_item:
  * @pivot: this #NAPivot instance.
- * @action: a #NAAction action to be written by the storage subsystem.
+ * @item: a #NAObjectItem to be written by the storage subsystem.
  * @message: the I/O provider can allocate and store here an error
  * message.
  *
- * Writes an action.
+ * Writes an item (an action or a menu).
  *
  * Returns: the #NAIIOProvider return code.
  */
 guint
-na_pivot_write_action( const NAPivot *pivot, NAAction *action, gchar **message )
+na_pivot_write_item( const NAPivot *pivot, NAObject *item, gchar **message )
 {
-	g_assert( NA_IS_PIVOT( pivot ));
-	g_assert( NA_IS_ACTION( action ));
-	g_assert( message );
-	return( na_iio_provider_write_action( pivot, action, message ));
+	g_return_val_if_fail( NA_IS_PIVOT( pivot ), NA_IIO_PROVIDER_PROGRAM_ERROR );
+	g_return_val_if_fail( !pivot->private->dispose_has_run, NA_IIO_PROVIDER_PROGRAM_ERROR );
+	g_return_val_if_fail( NA_IS_OBJECT_ITEM( item ), NA_IIO_PROVIDER_PROGRAM_ERROR );
+	g_return_val_if_fail( message, NA_IIO_PROVIDER_PROGRAM_ERROR );
+
+	return( na_iio_provider_write_item( pivot, item, message ));
 }
 
 /**
- * na_pivot_delete_action:
+ * na_pivot_delete_item:
  * @pivot: this #NAPivot instance.
- * @action: a #NAAction action to be deleted from the storage
- * subsystem.
+ * @item: the #NAObjectItem to be deleted from the storage subsystem.
  * @message: the I/O provider can allocate and store here an error
  * message.
  *
@@ -556,32 +589,36 @@ na_pivot_write_action( const NAPivot *pivot, NAAction *action, gchar **message )
  * Returns: the #NAIIOProvider return code.
  */
 guint
-na_pivot_delete_action( const NAPivot *pivot, const NAAction *action, gchar **message )
+na_pivot_delete_item( const NAPivot *pivot, const NAObject *item, gchar **message )
 {
-	g_assert( NA_IS_PIVOT( pivot ));
-	g_assert( NA_IS_ACTION( action ));
-	g_assert( message );
-	return( na_iio_provider_delete_action( pivot, action, message ));
+	g_return_val_if_fail( NA_IS_PIVOT( pivot ), NA_IIO_PROVIDER_PROGRAM_ERROR );
+	g_return_val_if_fail( !pivot->private->dispose_has_run, NA_IIO_PROVIDER_PROGRAM_ERROR );
+	g_return_val_if_fail( NA_IS_OBJECT_ITEM( item ), NA_IIO_PROVIDER_PROGRAM_ERROR );
+	g_return_val_if_fail( message, NA_IIO_PROVIDER_PROGRAM_ERROR );
+
+	return( na_iio_provider_delete_item( pivot, item, message ));
 }
 
 /**
- * na_pivot_add_consumer:
+ * na_pivot_register_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.
+ * @consumer: a #NAIPivotConsumer which wishes be notified of any
+ * modification of an action or a menu in any of the underlying I/O
+ * storage subsystems.
  *
- * Registers a new consumer to be notified of an action modification.
+ * Registers a new consumer to be notified of configuration modification.
  */
 void
-na_pivot_add_consumer( NAPivot *pivot, const GObject *consumer )
+na_pivot_register_consumer( NAPivot *pivot, const NAIPivotConsumer *consumer )
 {
-	static const gchar *thisfn = "na_pivot_add_consumer";
+	static const gchar *thisfn = "na_pivot_register_consumer";
 
 	g_debug( "%s: pivot=%p, consumer=%p", thisfn, ( void * ) pivot, ( void * ) consumer );
-	g_assert( NA_IS_PIVOT( pivot ));
-	g_assert( G_IS_OBJECT( consumer ));
+	g_return_if_fail( NA_IS_PIVOT( pivot ));
+	g_return_if_fail( !pivot->private->dispose_has_run );
+	g_return_if_fail( NA_IS_IPIVOT_CONSUMER( consumer ));
 
-	pivot->private->notified = g_slist_prepend( pivot->private->notified, ( gpointer ) consumer );
+	pivot->private->consumers = g_slist_prepend( pivot->private->consumers, ( gpointer ) consumer );
 }
 
 /**
@@ -593,7 +630,8 @@ na_pivot_add_consumer( NAPivot *pivot, const GObject *consumer )
 gboolean
 na_pivot_get_automatic_reload( const NAPivot *pivot )
 {
-	g_assert( NA_IS_PIVOT( pivot ));
+	g_return_val_if_fail( NA_IS_PIVOT( pivot ), FALSE );
+	g_return_val_if_fail( !pivot->private->dispose_has_run, FALSE );
 
 	return( pivot->private->automatic_reload );
 }
@@ -615,7 +653,8 @@ na_pivot_get_automatic_reload( const NAPivot *pivot )
 void
 na_pivot_set_automatic_reload( NAPivot *pivot, gboolean reload )
 {
-	g_assert( NA_IS_PIVOT( pivot ));
+	g_return_if_fail( NA_IS_PIVOT( pivot ));
+	g_return_if_fail( !pivot->private->dispose_has_run );
 
 	pivot->private->automatic_reload = reload;
 }
@@ -623,12 +662,37 @@ na_pivot_set_automatic_reload( NAPivot *pivot, gboolean reload )
 static void
 free_consumers( GSList *consumers )
 {
-	GSList *ic;
+	/*g_slist_foreach( consumers, ( GFunc ) g_object_unref, NULL );*/
+	g_slist_free( consumers );
+}
+
+/*
+ * Note that each implementation of NAIIOProvider interface must have
+ * this same type of constructor, which accepts as parameter a pointer
+ * to this NAPivot object.
+ * This is required because NAIIOProviders will send all their
+ * notification messages to this NAPivot, letting this later redirect
+ * them to appropriate NAIPivotConsumers.
+ */
+static void
+register_io_providers( NAPivot *pivot )
+{
+	static const gchar *thisfn = "na_pivot_register_io_providers";
+	GSList *list = NULL;
 
-	for( ic = consumers ; ic ; ic = ic->next )
-		;
+	g_debug( "%s: pivot=%p", thisfn, ( void * ) pivot );
+	g_return_if_fail( NA_IS_PIVOT( pivot ));
+	g_return_if_fail( !pivot->private->dispose_has_run );
 
-	g_slist_free( consumers );
+	list = g_slist_prepend( list, na_gconf_provider_new( pivot ));
+
+	pivot->private->providers = list;
+}
+
+static void
+read_runtime_preferences( NAPivot *pivot )
+{
+	/*pivot->private->gconf = na_gconf_new();*/
 }
 
 /*
@@ -645,8 +709,9 @@ action_changed_handler( NAPivot *self, gpointer user_data  )
 	/*static const gchar *thisfn = "na_pivot_action_changed_handler";
 	g_debug( "%s: self=%p, data=%p", thisfn, self, user_data );*/
 
-	g_assert( NA_IS_PIVOT( self ));
-	g_assert( user_data );
+	g_return_if_fail( NA_IS_PIVOT( self ));
+	g_return_if_fail( !self->private->dispose_has_run );
+	g_return_if_fail( user_data );
 
 	if( self->private->dispose_has_run ){
 		return;
@@ -687,11 +752,11 @@ on_actions_changed_timeout( gpointer user_data )
 	}
 
 	if( pivot->private->automatic_reload ){
-		na_pivot_free_actions( pivot->private->actions );
-		pivot->private->actions = na_iio_provider_read_actions( pivot );
+		na_pivot_free_items_tree( pivot->private->tree );
+		pivot->private->tree = na_iio_provider_get_items_tree( pivot );
 	}
 
-	for( ic = pivot->private->notified ; ic ; ic = ic->next ){
+	for( ic = pivot->private->consumers ; ic ; ic = ic->next ){
 		na_ipivot_consumer_notify( NA_IPIVOT_CONSUMER( ic->data ));
 	}
 
@@ -759,7 +824,7 @@ on_display_order_change( NAPivot *self, gpointer user_data  )
 		return;
 	}
 
-	for( ic = self->private->notified ; ic ; ic = ic->next ){
+	for( ic = self->private->consumers ; ic ; ic = ic->next ){
 		na_ipivot_consumer_notify( NA_IPIVOT_CONSUMER( ic->data ));
 	}
 }
diff --git a/src/common/na-pivot.h b/src/common/na-pivot.h
index b4d07a9..33e825b 100644
--- a/src/common/na-pivot.h
+++ b/src/common/na-pivot.h
@@ -74,9 +74,8 @@
  *    subsystem.
  */
 
-#include <glib-object.h>
-
-#include "na-action-class.h"
+#include "na-object-class.h"
+#include "na-ipivot-consumer.h"
 
 G_BEGIN_DECLS
 
@@ -105,24 +104,25 @@ typedef struct {
 
 GType     na_pivot_get_type( void );
 
-NAPivot  *na_pivot_new( const GObject *notified );
+NAPivot  *na_pivot_new( const NAIPivotConsumer *notified );
 void      na_pivot_dump( const NAPivot *pivot );
 
 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_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 );
+GSList   *na_pivot_get_items_tree( const NAPivot *pivot );
+/*GSList   *na_pivot_get_duplicate_items_tree( const NAPivot *pivot );*/
+void      na_pivot_reload_items_tree( NAPivot *pivot );
+GSList   *na_pivot_free_items_tree( GSList *tree );
+
+void      na_pivot_add_item( NAPivot *pivot, const NAObject *item );
+void      na_pivot_remove_item( NAPivot *pivot, NAObject *item );
+NAObject *na_pivot_get_item( const NAPivot *pivot, const gchar *uuid );
 
-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 );
+guint     na_pivot_write_item( const NAPivot *pivot, NAObject *item, gchar **message );
+guint     na_pivot_delete_item( const NAPivot *pivot, const NAObject *item, gchar **message );
 
-void      na_pivot_add_consumer( NAPivot *pivot, const GObject *consumer );
+void      na_pivot_register_consumer( NAPivot *pivot, const NAIPivotConsumer *consumer );
 
 gboolean  na_pivot_get_automatic_reload( const NAPivot *pivot );
 void      na_pivot_set_automatic_reload( NAPivot *pivot, gboolean reload );
diff --git a/src/common/na-utils.c b/src/common/na-utils.c
index e3723cc..6480fd6 100644
--- a/src/common/na-utils.c
+++ b/src/common/na-utils.c
@@ -147,7 +147,8 @@ na_utils_remove_ascii_from_string_list( GSList *list, const gchar *text )
 }
 
 /**
- * Concatenates a string list to a semi-colon-separated text.
+ * Concatenates a string list to a semi-colon-separated text
+ * suitable for an entry in the user interface
  */
 gchar *
 na_utils_string_list_to_text( GSList *strlist )
@@ -172,7 +173,7 @@ na_utils_string_list_to_text( GSList *strlist )
 
 /**
  * Extracts a list of strings from a semi-colon-separated text
- * (entry text).
+ * (entry text in the user interface).
  */
 GSList *
 na_utils_text_to_string_list( const gchar *text )
@@ -323,17 +324,17 @@ na_utils_schema_to_boolean( const gchar *value, gboolean default_value )
 }
 
 /**
- * extract the key part (the last part) of a full path
+ * extract the last part of a full path
  * returns a newly allocated string which must be g_free() by the caller
  */
 gchar *
-na_utils_path_to_key( const gchar *path )
+na_utils_path_extract_last_dir( const gchar *path )
 {
 	gchar **split = g_strsplit( path, "/", -1 );
 	guint count = g_strv_length( split );
-	gchar *key = g_strdup( split[count-1] );
+	gchar *lastdir = g_strdup( split[count-1] );
 	g_strfreev( split );
-	return( key );
+	return( lastdir );
 }
 
 /**
diff --git a/src/common/na-utils.h b/src/common/na-utils.h
index 5902a0d..daeb19f 100644
--- a/src/common/na-utils.h
+++ b/src/common/na-utils.h
@@ -52,7 +52,7 @@ GSList  *na_utils_schema_to_gslist( const gchar *value );
 gchar   *na_utils_boolean_to_schema( gboolean b );
 gboolean na_utils_schema_to_boolean( const gchar *value, gboolean default_value );
 
-gchar   *na_utils_path_to_key( const gchar *path );
+gchar   *na_utils_path_extract_last_dir( const gchar *path );
 
 /*
  * Some functions for GString manipulations.
diff --git a/src/common/na-xml-writer.c b/src/common/na-xml-writer.c
index cc2f83d..968405b 100644
--- a/src/common/na-xml-writer.c
+++ b/src/common/na-xml-writer.c
@@ -35,8 +35,10 @@
 #include <gio/gio.h>
 #include <libxml/tree.h>
 
-#include "na-action-profile.h"
-#include "na-gconf-keys.h"
+#include "na-object-api.h"
+#include "na-obj-action.h"
+#include "na-obj-profile.h"
+#include "na-gconf-provider-keys.h"
 #include "na-utils.h"
 #include "na-xml-names.h"
 #include "na-xml-writer.h"
@@ -73,7 +75,7 @@ static void         instance_dispose( GObject *object );
 static void         instance_finalize( GObject *object );
 
 static NAXMLWriter *xml_writer_new( const gchar *uuid );
-static xmlDocPtr    create_xml_schema( NAXMLWriter *writer, gint format, const NAAction *action );
+static xmlDocPtr    create_xml_schema( NAXMLWriter *writer, gint format, const NAObjectAction *action );
 static void         create_schema_entry(
 								NAXMLWriter *writer,
 								gint format,
@@ -86,7 +88,7 @@ static void         create_schema_entry(
 								gboolean is_l10n_value,
 								const gchar *short_desc,
 								const gchar *long_desc );
-static xmlDocPtr    create_xml_dump( NAXMLWriter *writer, gint format, const NAAction *action );
+static xmlDocPtr    create_xml_dump( NAXMLWriter *writer, gint format, const NAObjectAction *action );
 static void         create_dump_entry(
 								NAXMLWriter *writer,
 								gint format,
@@ -269,7 +271,9 @@ xml_writer_new( const gchar *uuid )
 
 /**
  * na_xml_writer_export:
- * @action: the #NAAction to be exported.
+ * @action: the #NAObjectAction to be exported.
+ * Can be NULL when exporting schemas ; in this case, format must be
+ * FORMAT_GCONFSCHEMA.
  * @folder: the directoy where to write the output XML file.
  * If NULL, the output will be directed to stdout.
  * @format: the export format.
@@ -280,12 +284,13 @@ xml_writer_new( const gchar *uuid )
  * Returns: the written filename, or NULL if written to stdout.
  */
 gchar *
-na_xml_writer_export( const NAAction *action, const gchar *folder, gint format, gchar **msg )
+na_xml_writer_export( const NAObjectAction *action, const gchar *folder, gint format, gchar **msg )
 {
 	gchar *filename = NULL;
-	gboolean free_filename = FALSE;
 	gchar *xml_buffer;
 
+	g_assert( action || format == FORMAT_GCONFSCHEMA );
+
 	switch( format ){
 		case FORMAT_GCONFSCHEMAFILE_V1:
 		case FORMAT_GCONFSCHEMAFILE_V2:
@@ -298,9 +303,6 @@ na_xml_writer_export( const NAAction *action, const gchar *folder, gint format,
 		case FORMAT_GCONFENTRY:
 			if( folder ){
 				filename = na_xml_writer_get_output_fname( action, folder, format );
-			} else {
-				filename = g_strdup( "-" );
-				free_filename = TRUE;
 			}
 			break;
 
@@ -311,32 +313,28 @@ na_xml_writer_export( const NAAction *action, const gchar *folder, gint format,
 		case FORMAT_GCONFSCHEMA:
 			if( folder ){
 				filename = g_strdup( folder );
-			} else {
-				filename = g_strdup( "-" );
-				free_filename = TRUE;
 			}
 			break;
 	}
 
-	g_assert( filename );
+	g_assert( filename || folder == NULL );
 
 	xml_buffer = na_xml_writer_get_xml_buffer( action, format );
 
-	na_xml_writer_output_xml( xml_buffer, filename );
+	if( folder ){
+		na_xml_writer_output_xml( xml_buffer, filename );
+	} else {
+		g_print( "%s", xml_buffer );
+	}
 
 	g_free( xml_buffer );
 
-	if( free_filename ){
-		g_free( filename );
-		filename = NULL;
-	}
-
 	return( filename );
 }
 
 /**
  * na_xml_writer_get_output_fname:
- * @action: the #NAAction to be exported.
+ * @action: the #NAObjectAction to be exported.
  * @folder: the uri of the directoy where to write the output XML file.
  * @format: the export format.
  *
@@ -352,7 +350,7 @@ na_xml_writer_export( const NAAction *action, const gchar *folder, gint format,
  * between our test of inexistance and the actual write.
  */
 gchar *
-na_xml_writer_get_output_fname( const NAAction *action, const gchar *folder, gint format )
+na_xml_writer_get_output_fname( const NAObjectAction *action, const gchar *folder, gint format )
 {
 	gchar *uuid;
 	gchar *canonical_fname = NULL;
@@ -364,7 +362,7 @@ na_xml_writer_get_output_fname( const NAAction *action, const gchar *folder, gin
 	g_return_val_if_fail( folder, NULL );
 	g_return_val_if_fail( strlen( folder ), NULL );
 
-	uuid = na_action_get_uuid( action );
+	uuid = na_object_get_id( action );
 
 	switch( format ){
 		case FORMAT_GCONFSCHEMAFILE_V1:
@@ -410,7 +408,7 @@ na_xml_writer_get_output_fname( const NAAction *action, const gchar *folder, gin
 
 /**
  * na_xml_writer_get_xml_buffer:
- * @action: the #NAAction to be exported.
+ * @action: the #NAObjectAction to be exported.
  * @format: the export format.
  *
  * Returns: a buffer which contains the XML output.
@@ -418,7 +416,7 @@ na_xml_writer_get_output_fname( const NAAction *action, const gchar *folder, gin
  * The returned string should be g_free() by the caller.
  */
 gchar *
-na_xml_writer_get_xml_buffer( const NAAction *action, gint format )
+na_xml_writer_get_xml_buffer( const NAObjectAction *action, gint format )
 {
 	gchar *uuid;
 	NAXMLWriter *writer;
@@ -427,9 +425,9 @@ na_xml_writer_get_xml_buffer( const NAAction *action, gint format )
 	int textlen;
 	gchar *buffer;
 
-	g_return_val_if_fail( action, NULL );
+	g_assert( action || format == FORMAT_GCONFSCHEMA );
 
-	uuid = na_action_get_uuid( action );
+	uuid = action ? na_object_get_id( action ) : NULL;
 	writer = xml_writer_new( uuid );
 	g_free( uuid );
 
@@ -463,7 +461,7 @@ na_xml_writer_get_xml_buffer( const NAAction *action, gint format )
 
 /**
  * na_xml_writer_output_xml:
- * @action: the #NAAction to be exported.
+ * @action: the #NAObjectAction to be exported.
  * @filename: the uri of the output filename
  *
  * Exports an action to the given filename.
@@ -512,14 +510,14 @@ na_xml_writer_output_xml( const gchar *xml, const gchar *filename )
 }
 
 static xmlDocPtr
-create_xml_schema( NAXMLWriter *writer, gint format, const NAAction *action )
+create_xml_schema( NAXMLWriter *writer, gint format, const NAObjectAction *action )
 {
 	xmlDocPtr doc;
 	xmlNodePtr root_node, list_node;
 	gchar *version, *label, *tooltip, *icon, *text;
 	gboolean enabled;
 	GSList *profiles, *ip;
-	NAActionProfile *profile;
+	NAObjectProfile *profile;
 	gchar *profile_dir, *profile_label, *path, *parameters;
 	GSList *basenames, *mimetypes, *schemes;
 	gboolean match, isfile, isdir, multiple;
@@ -530,93 +528,93 @@ create_xml_schema( NAXMLWriter *writer, gint format, const NAAction *action )
 	list_node = xmlNewChild( root_node, NULL, BAD_CAST( NACT_GCONF_SCHEMA_LIST ), NULL );
 
 	/* version */
-	version = na_action_get_version( action );
+	version = na_object_action_get_version( action );
 	create_schema_entry( writer, format, NULL, ACTION_VERSION_ENTRY, version, doc, list_node, "string", FALSE, ACTION_VERSION_DESC_SHORT, ACTION_VERSION_DESC_LONG );
 	g_free( version );
 
 	/* label */
-	label = na_action_get_label( action );
-	create_schema_entry( writer, format, NULL, ACTION_LABEL_ENTRY, label, doc, list_node, "string", TRUE, ACTION_LABEL_DESC_SHORT, ACTION_LABEL_DESC_LONG );
+	label = na_object_get_label( action );
+	create_schema_entry( writer, format, NULL, OBJECT_ITEM_LABEL_ENTRY, label, doc, list_node, "string", TRUE, ACTION_LABEL_DESC_SHORT, ACTION_LABEL_DESC_LONG );
 	g_free( label );
 
 	/* tooltip */
-	tooltip = na_action_get_tooltip( action );
-	create_schema_entry( writer, format, NULL, ACTION_TOOLTIP_ENTRY, tooltip, doc, list_node, "string", TRUE, ACTION_TOOLTIP_DESC_SHORT, ACTION_TOOLTIP_DESC_LONG );
+	tooltip = na_object_get_tooltip( action );
+	create_schema_entry( writer, format, NULL, OBJECT_ITEM_TOOLTIP_ENTRY, tooltip, doc, list_node, "string", TRUE, ACTION_TOOLTIP_DESC_SHORT, ACTION_TOOLTIP_DESC_LONG );
 	g_free( tooltip );
 
 	/* icon name */
-	icon = na_action_get_icon( action );
-	create_schema_entry( writer, format, NULL, ACTION_ICON_ENTRY, icon, doc, list_node, "string", FALSE, ACTION_ICON_DESC_SHORT, ACTION_ICON_DESC_LONG );
+	icon = na_object_get_icon( action );
+	create_schema_entry( writer, format, NULL, OBJECT_ITEM_ICON_ENTRY, icon, doc, list_node, "string", FALSE, ACTION_ICON_DESC_SHORT, ACTION_ICON_DESC_LONG );
 	g_free( icon );
 
 	/* enabled */
-	enabled = na_action_is_enabled( action );
+	enabled = na_object_is_enabled( NA_OBJECT_ITEM( action ));
 	text = na_utils_boolean_to_schema( enabled );
-	create_schema_entry( writer, format, NULL, ACTION_ENABLED_ENTRY, text, doc, list_node, "bool", FALSE, ACTION_ENABLED_DESC_SHORT, ACTION_ENABLED_DESC_LONG );
+	create_schema_entry( writer, format, NULL, OBJECT_ITEM_ENABLED_ENTRY, text, doc, list_node, "bool", FALSE, ACTION_ENABLED_DESC_SHORT, ACTION_ENABLED_DESC_LONG );
 	g_free( text );
 
-	profiles = na_action_get_profiles( action );
+	profiles = na_object_get_items( action );
 
 	for( ip = profiles ; ip ; ip = ip->next ){
 
-		profile = NA_ACTION_PROFILE( ip->data );
-		profile_dir = na_action_profile_get_name( profile );
+		profile = NA_OBJECT_PROFILE( ip->data );
+		profile_dir = na_object_get_id( profile );
 
 		/* profile label */
-		profile_label = na_action_profile_get_label( profile );
+		profile_label = na_object_get_label( profile );
 		create_schema_entry( writer, format, profile_dir, ACTION_PROFILE_LABEL_ENTRY, profile_label, doc, list_node, "string", TRUE, ACTION_PROFILE_NAME_DESC_SHORT, ACTION_PROFILE_NAME_DESC_LONG );
 		g_free( profile_label );
 
 		/* path */
-		path = na_action_profile_get_path( profile );
+		path = na_object_profile_get_path( profile );
 		create_schema_entry( writer, format, profile_dir, ACTION_PATH_ENTRY, path, doc, list_node, "string", FALSE, ACTION_PATH_DESC_SHORT, ACTION_PATH_DESC_LONG );
 		g_free( path );
 
 		/* parameters */
-		parameters = na_action_profile_get_parameters( profile );
+		parameters = na_object_profile_get_parameters( profile );
 		create_schema_entry( writer, format, profile_dir, ACTION_PARAMETERS_ENTRY, parameters, doc, list_node, "string", FALSE, ACTION_PARAMETERS_DESC_SHORT, ACTION_PARAMETERS_DESC_LONG );
 		g_free( parameters );
 
 		/* basenames */
-		basenames = na_action_profile_get_basenames( profile );
+		basenames = na_object_profile_get_basenames( profile );
 		text = na_utils_gslist_to_schema( basenames );
 		create_schema_entry( writer, format, profile_dir, ACTION_BASENAMES_ENTRY, text, doc, list_node, "list", FALSE, ACTION_BASENAMES_DESC_SHORT, ACTION_BASENAMES_DESC_LONG );
 		g_free( text );
 		na_utils_free_string_list( basenames );
 
 		/* match_case */
-		match = na_action_profile_get_matchcase( profile );
+		match = na_object_profile_get_matchcase( profile );
 		text = na_utils_boolean_to_schema( match );
 		create_schema_entry( writer, format, profile_dir, ACTION_MATCHCASE_ENTRY, text, doc, list_node, "bool", FALSE, ACTION_MATCHCASE_DESC_SHORT, ACTION_MATCHCASE_DESC_LONG );
 		g_free( text );
 
 		/* mimetypes */
-		mimetypes = na_action_profile_get_mimetypes( profile );
+		mimetypes = na_object_profile_get_mimetypes( profile );
 		text = na_utils_gslist_to_schema( mimetypes );
 		create_schema_entry( writer, format, profile_dir, ACTION_MIMETYPES_ENTRY, text, doc, list_node, "list", FALSE, ACTION_MIMETYPES_DESC_SHORT, ACTION_MIMETYPES_DESC_LONG );
 		g_free( text );
 		na_utils_free_string_list( mimetypes );
 
 		/* is_file */
-		isfile = na_action_profile_get_is_file( profile );
+		isfile = na_object_profile_get_is_file( profile );
 		text = na_utils_boolean_to_schema( isfile );
 		create_schema_entry( writer, format, profile_dir, ACTION_ISFILE_ENTRY, text, doc, list_node, "bool", FALSE, ACTION_ISFILE_DESC_SHORT, ACTION_ISFILE_DESC_LONG );
 		g_free( text );
 
 		/* is_dir */
-		isdir = na_action_profile_get_is_dir( profile );
+		isdir = na_object_profile_get_is_dir( profile );
 		text = na_utils_boolean_to_schema( isdir );
 		create_schema_entry( writer, format, profile_dir, ACTION_ISDIR_ENTRY, text, doc, list_node, "bool", FALSE, ACTION_ISDIR_DESC_SHORT, ACTION_ISDIR_DESC_LONG );
 		g_free( text );
 
 		/* accept-multiple-files */
-		multiple = na_action_profile_get_multiple( profile );
+		multiple = na_object_profile_get_multiple( profile );
 		text = na_utils_boolean_to_schema( multiple );
 		create_schema_entry( writer, format, profile_dir, ACTION_MULTIPLE_ENTRY, text, doc, list_node, "bool", FALSE, ACTION_MULTIPLE_DESC_SHORT, ACTION_MULTIPLE_DESC_LONG );
 		g_free( text );
 
 		/* schemes */
-		schemes = na_action_profile_get_schemes( profile );
+		schemes = na_object_profile_get_schemes( profile );
 		text = na_utils_gslist_to_schema( schemes );
 		create_schema_entry( writer, format, profile_dir, ACTION_SCHEMES_ENTRY, text, doc, list_node, "list", FALSE, ACTION_SCHEMES_DESC_SHORT, ACTION_SCHEMES_DESC_LONG );
 		g_free( text );
@@ -625,6 +623,8 @@ create_xml_schema( NAXMLWriter *writer, gint format, const NAAction *action )
 		g_free( profile_dir );
 	}
 
+	na_object_free_items( profiles );
+
 	return( doc );
 }
 
@@ -648,7 +648,7 @@ create_schema_entry( NAXMLWriter *writer,
 
 	schema_node = xmlNewChild( list_node, NULL, BAD_CAST( NACT_GCONF_SCHEMA_ENTRY ), NULL );
 
-	content = BAD_CAST( g_build_path( "/", NA_GCONF_SCHEMA_PREFIX, path, NULL ));
+	content = BAD_CAST( g_build_path( "/", NAUTILUS_ACTIONS_GCONF_SCHEMASDIR, path, NULL ));
 	xmlNewChild( schema_node, NULL, BAD_CAST( NACT_GCONF_SCHEMA_KEY ), content );
 	xmlFree( content );
 
@@ -690,7 +690,7 @@ create_schema_entry( NAXMLWriter *writer,
 }
 
 static xmlDocPtr
-create_xml_dump( NAXMLWriter *writer, gint format, const NAAction *action )
+create_xml_dump( NAXMLWriter *writer, gint format, const NAObjectAction *action )
 {
 	xmlDocPtr doc;
 	xmlNodePtr root_node, list_node;
@@ -698,7 +698,7 @@ create_xml_dump( NAXMLWriter *writer, gint format, const NAAction *action )
 	gchar *version, *label, *tooltip, *icon, *text;
 	gboolean enabled;
 	GSList *profiles, *ip;
-	NAActionProfile *profile;
+	NAObjectProfile *profile;
 	gchar *profile_dir;
 	gchar *profile_label, *parameters;
 	GSList *basenames, *mimetypes, *schemes;
@@ -714,93 +714,93 @@ create_xml_dump( NAXMLWriter *writer, gint format, const NAAction *action )
 	g_free( path );
 
 	/* version */
-	version = na_action_get_version( action );
+	version = na_object_action_get_version( action );
 	create_dump_entry( writer, format, NULL, ACTION_VERSION_ENTRY, version, doc, list_node, "string" );
 	g_free( version );
 
 	/* label */
-	label = na_action_get_label( action );
-	create_dump_entry( writer, format, NULL, ACTION_LABEL_ENTRY, label, doc, list_node, "string" );
+	label = na_object_get_label( action );
+	create_dump_entry( writer, format, NULL, OBJECT_ITEM_LABEL_ENTRY, label, doc, list_node, "string" );
 	g_free( label );
 
 	/* tooltip */
-	tooltip = na_action_get_tooltip( action );
-	create_dump_entry( writer, format, NULL, ACTION_TOOLTIP_ENTRY, tooltip, doc, list_node, "string" );
+	tooltip = na_object_get_tooltip( action );
+	create_dump_entry( writer, format, NULL, OBJECT_ITEM_TOOLTIP_ENTRY, tooltip, doc, list_node, "string" );
 	g_free( tooltip );
 
 	/* icon name */
-	icon = na_action_get_icon( action );
-	create_dump_entry( writer, format, NULL, ACTION_ICON_ENTRY, icon, doc, list_node, "string" );
+	icon = na_object_get_icon( action );
+	create_dump_entry( writer, format, NULL, OBJECT_ITEM_ICON_ENTRY, icon, doc, list_node, "string" );
 	g_free( icon );
 
 	/* enabled */
-	enabled = na_action_is_enabled( action );
+	enabled = na_object_is_enabled( NA_OBJECT_ITEM( action ));
 	text = na_utils_boolean_to_schema( enabled );
-	create_dump_entry( writer, format, NULL, ACTION_ENABLED_ENTRY, text, doc, list_node, "bool" );
+	create_dump_entry( writer, format, NULL, OBJECT_ITEM_ENABLED_ENTRY, text, doc, list_node, "bool" );
 	g_free( text );
 
-	profiles = na_action_get_profiles( action );
+	profiles = na_object_get_items( action );
 
 	for( ip = profiles ; ip ; ip = ip->next ){
 
-		profile = NA_ACTION_PROFILE( ip->data );
-		profile_dir = na_action_profile_get_name( profile );
+		profile = NA_OBJECT_PROFILE( ip->data );
+		profile_dir = na_object_get_id( profile );
 
 		/* profile label */
-		profile_label = na_action_profile_get_label( profile );
+		profile_label = na_object_get_label( profile );
 		create_dump_entry( writer, format, profile_dir, ACTION_PROFILE_LABEL_ENTRY, profile_label, doc, list_node, "string" );
 		g_free( profile_label );
 
 		/* path */
-		path = na_action_profile_get_path( profile );
+		path = na_object_profile_get_path( profile );
 		create_dump_entry( writer, format, profile_dir, ACTION_PATH_ENTRY, path, doc, list_node, "string" );
 		g_free( path );
 
 		/* parameters */
-		parameters = na_action_profile_get_parameters( profile );
+		parameters = na_object_profile_get_parameters( profile );
 		create_dump_entry( writer, format, profile_dir, ACTION_PARAMETERS_ENTRY, parameters, doc, list_node, "string" );
 		g_free( parameters );
 
 		/* basenames */
-		basenames = na_action_profile_get_basenames( profile );
+		basenames = na_object_profile_get_basenames( profile );
 		text = na_utils_gslist_to_schema( basenames );
 		create_dump_entry( writer, format, profile_dir, ACTION_BASENAMES_ENTRY, text, doc, list_node, "list" );
 		g_free( text );
 		na_utils_free_string_list( basenames );
 
 		/* match_case */
-		match = na_action_profile_get_matchcase( profile );
+		match = na_object_profile_get_matchcase( profile );
 		text = na_utils_boolean_to_schema( match );
 		create_dump_entry( writer, format, profile_dir, ACTION_MATCHCASE_ENTRY, text, doc, list_node, "bool" );
 		g_free( text );
 
 		/* mimetypes */
-		mimetypes = na_action_profile_get_mimetypes( profile );
+		mimetypes = na_object_profile_get_mimetypes( profile );
 		text = na_utils_gslist_to_schema( mimetypes );
 		create_dump_entry( writer, format, profile_dir, ACTION_MIMETYPES_ENTRY, text, doc, list_node, "list" );
 		g_free( text );
 		na_utils_free_string_list( mimetypes );
 
 		/* is_file */
-		isfile = na_action_profile_get_is_file( profile );
+		isfile = na_object_profile_get_is_file( profile );
 		text = na_utils_boolean_to_schema( isfile );
 		create_dump_entry( writer, format, profile_dir, ACTION_ISFILE_ENTRY, text, doc, list_node, "bool" );
 		g_free( text );
 
 		/* is_dir */
-		isdir = na_action_profile_get_is_dir( profile );
+		isdir = na_object_profile_get_is_dir( profile );
 		text = na_utils_boolean_to_schema( isdir );
 		create_dump_entry( writer, format, profile_dir, ACTION_ISDIR_ENTRY, text, doc, list_node, "bool" );
 		g_free( text );
 
 		/* accept-multiple-files */
-		multiple = na_action_profile_get_multiple( profile );
+		multiple = na_object_profile_get_multiple( profile );
 		text = na_utils_boolean_to_schema( multiple );
 		create_dump_entry( writer, format, profile_dir, ACTION_MULTIPLE_ENTRY, text, doc, list_node, "bool" );
 		g_free( text );
 
 		/* schemes */
-		schemes = na_action_profile_get_schemes( profile );
+		schemes = na_object_profile_get_schemes( profile );
 		text = na_utils_gslist_to_schema( schemes );
 		create_dump_entry( writer, format, profile_dir, ACTION_SCHEMES_ENTRY, text, doc, list_node, "list" );
 		g_free( text );
@@ -809,6 +809,8 @@ create_xml_dump( NAXMLWriter *writer, gint format, const NAAction *action )
 		g_free( profile_dir );
 	}
 
+	na_object_free_items( profiles );
+
 	return( doc );
 }
 
@@ -866,11 +868,11 @@ create_gconf_schema( NAXMLWriter *writer )
 	list_node = xmlNewChild( root_node, NULL, BAD_CAST( NACT_GCONF_SCHEMA_LIST ), NULL );
 
 	create_gconf_schema_entry( writer, ACTION_VERSION_ENTRY       , doc, list_node, "string", ACTION_VERSION_DESC_SHORT     , ACTION_VERSION_DESC_LONG     , NAUTILUS_ACTIONS_CONFIG_VERSION, FALSE );
-	create_gconf_schema_entry( writer, ACTION_LABEL_ENTRY         , doc, list_node, "string", ACTION_LABEL_DESC_SHORT       , ACTION_LABEL_DESC_LONG       , "", TRUE );
-	create_gconf_schema_entry( writer, ACTION_TOOLTIP_ENTRY       , doc, list_node, "string", ACTION_TOOLTIP_DESC_SHORT     , ACTION_TOOLTIP_DESC_LONG     , "", TRUE );
-	create_gconf_schema_entry( writer, ACTION_ICON_ENTRY          , doc, list_node, "string", ACTION_ICON_DESC_SHORT        , ACTION_ICON_DESC_LONG        , "", FALSE );
-	create_gconf_schema_entry( writer, ACTION_ENABLED_ENTRY       , doc, list_node, "bool"  , ACTION_ENABLED_DESC_SHORT     , ACTION_ENABLED_DESC_LONG     , "true", FALSE );
-	create_gconf_schema_entry( writer, ACTION_PROFILE_LABEL_ENTRY , doc, list_node, "string", ACTION_PROFILE_NAME_DESC_SHORT, ACTION_PROFILE_NAME_DESC_LONG, NA_ACTION_PROFILE_DEFAULT_LABEL, TRUE );
+	create_gconf_schema_entry( writer, OBJECT_ITEM_LABEL_ENTRY    , doc, list_node, "string", ACTION_LABEL_DESC_SHORT       , ACTION_LABEL_DESC_LONG       , "", TRUE );
+	create_gconf_schema_entry( writer, OBJECT_ITEM_TOOLTIP_ENTRY  , doc, list_node, "string", ACTION_TOOLTIP_DESC_SHORT     , ACTION_TOOLTIP_DESC_LONG     , "", TRUE );
+	create_gconf_schema_entry( writer, OBJECT_ITEM_ICON_ENTRY     , doc, list_node, "string", ACTION_ICON_DESC_SHORT        , ACTION_ICON_DESC_LONG        , "", FALSE );
+	create_gconf_schema_entry( writer, OBJECT_ITEM_ENABLED_ENTRY  , doc, list_node, "bool"  , ACTION_ENABLED_DESC_SHORT     , ACTION_ENABLED_DESC_LONG     , "true", FALSE );
+	create_gconf_schema_entry( writer, ACTION_PROFILE_LABEL_ENTRY , doc, list_node, "string", ACTION_PROFILE_NAME_DESC_SHORT, ACTION_PROFILE_NAME_DESC_LONG, NA_OBJECT_PROFILE_DEFAULT_LABEL, TRUE );
 	create_gconf_schema_entry( writer, ACTION_PATH_ENTRY          , doc, list_node, "string", ACTION_PATH_DESC_SHORT        , ACTION_PATH_DESC_LONG        , "", FALSE );
 	create_gconf_schema_entry( writer, ACTION_PARAMETERS_ENTRY    , doc, list_node, "string", ACTION_PARAMETERS_DESC_SHORT  , ACTION_PARAMETERS_DESC_LONG  , "", FALSE );
 	create_gconf_schema_entry( writer, ACTION_BASENAMES_ENTRY     , doc, list_node, "list"  , ACTION_BASENAMES_DESC_SHORT   , ACTION_BASENAMES_DESC_LONG   , "[*]", FALSE );
@@ -897,7 +899,7 @@ create_gconf_schema_entry( NAXMLWriter *writer,
 
 	schema_node = xmlNewChild( list_node, NULL, BAD_CAST( NACT_GCONF_SCHEMA_ENTRY ), NULL );
 
-	content = BAD_CAST( g_build_path( "/", NA_GCONF_SCHEMA_PREFIX, NA_GCONF_CONFIG_PATH, entry, NULL ));
+	content = BAD_CAST( g_build_path( "/", NAUTILUS_ACTIONS_GCONF_SCHEMASDIR, NA_GCONF_CONFIG_PATH, entry, NULL ));
 	xmlNewChild( schema_node, NULL, BAD_CAST( NACT_GCONF_SCHEMA_KEY ), content );
 	xmlFree( content );
 
diff --git a/src/common/na-xml-writer.h b/src/common/na-xml-writer.h
index a7b9781..5b566aa 100644
--- a/src/common/na-xml-writer.h
+++ b/src/common/na-xml-writer.h
@@ -42,7 +42,7 @@
  * nautilus-actions-new utility.
  */
 
-#include "na-action.h"
+#include "na-obj-action-class.h"
 
 G_BEGIN_DECLS
 
@@ -71,11 +71,11 @@ typedef struct {
 
 GType  na_xml_writer_get_type( void );
 
-gchar *na_xml_writer_export( const NAAction *action, const gchar *folder, gint format, gchar **msg );
+gchar *na_xml_writer_export( const NAObjectAction *action, const gchar *folder, gint format, gchar **msg );
 
-gchar *na_xml_writer_get_output_fname( const NAAction *action, const gchar *folder, gint format );
+gchar *na_xml_writer_get_output_fname( const NAObjectAction *action, const gchar *folder, gint format );
 
-gchar *na_xml_writer_get_xml_buffer( const NAAction *action, gint format );
+gchar *na_xml_writer_get_xml_buffer( const NAObjectAction *action, gint format );
 
 void   na_xml_writer_output_xml( const gchar *xml, const gchar *filename );
 
diff --git a/src/nact/Makefile.am b/src/nact/Makefile.am
index 98f7d47..4a34da7 100644
--- a/src/nact/Makefile.am
+++ b/src/nact/Makefile.am
@@ -42,6 +42,12 @@ nautilus_actions_config_tool_SOURCES = \
 	base-application.c									\
 	base-application.h									\
 	base-application-class.h							\
+	base-assistant.c									\
+	base-assistant.h									\
+	base-dialog.c										\
+	base-dialog.h										\
+	base-iprefs.c										\
+	base-iprefs.h										\
 	base-window.c										\
 	base-window.h										\
 	base-window-class.h									\
@@ -49,35 +55,32 @@ nautilus_actions_config_tool_SOURCES = \
 	egg-tree-multi-dnd.h								\
 	nact-application.c									\
 	nact-application.h									\
-	nact-assistant.c									\
-	nact-assistant.h									\
 	nact-assistant-export.c								\
 	nact-assistant-export.h								\
 	nact-assistant-import.c								\
 	nact-assistant-import.h								\
-	nact-iaction-tab.c									\
-	nact-iaction-tab.h									\
+	nact-clipboard.c									\
+	nact-clipboard.h									\
 	nact-iactions-list.c								\
 	nact-iactions-list.h								\
+	nact-iaction-tab.c									\
+	nact-iaction-tab.h									\
 	nact-iadvanced-tab.c								\
 	nact-iadvanced-tab.h								\
 	nact-icommand-tab.c									\
 	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											\
+	nact-main-menubar.c									\
+	nact-main-menubar.h									\
+	nact-main-statusbar.c								\
+	nact-main-statusbar.h								\
+	nact-main-tab.h										\
 	nact-main-window.c									\
 	nact-main-window.h									\
 	nact-preferences-editor.c							\
 	nact-preferences-editor.h							\
-	nact-selection.c									\
-	nact-selection.h									\
-	nact-statusbar.c									\
-	nact-statusbar.h									\
 	nact-tree-model.c									\
 	nact-tree-model.h									\
 	nact-window.c										\
diff --git a/src/nact/base-application-class.h b/src/nact/base-application-class.h
index e42b2cd..161b5ce 100644
--- a/src/nact/base-application-class.h
+++ b/src/nact/base-application-class.h
@@ -65,7 +65,7 @@ typedef struct {
 	BaseApplicationClassPrivate *private;
 
 	/**
-	 * application_run:
+	 * run:
 	 * @appli: this #BaseApplication instance.
 	 *
 	 * Starts and runs the application.
@@ -78,10 +78,10 @@ typedef struct {
 	 * and running the main window. It blocks until the end of the
 	 * program.
 	 */
-	int       ( *application_run )                   ( BaseApplication *appli );
+	int       ( *run )                        ( BaseApplication *appli );
 
 	/**
-	 * application_initialize:
+	 * initialize:
 	 * @appli: this #BaseApplication instance.
 	 *
 	 * Initializes the program.
@@ -114,10 +114,10 @@ typedef struct {
 	 * application is correctly initialized if and only if all
 	 * individual initialization virtual functions have returned %TRUE.
 	 */
-	gboolean  ( *application_initialize )            ( BaseApplication *appli );
+	gboolean  ( *initialize )                 ( BaseApplication *appli );
 
 	/**
-	 * application_initialize_i18n:
+	 * initialize_i18n:
 	 * @appli: this #BaseApplication instance.
 	 *
 	 * Initializes the i18n context.
@@ -126,10 +126,10 @@ typedef struct {
 	 *
 	 * The base class implementation always returns %TRUE.
 	 */
-	gboolean  ( *application_initialize_i18n )       ( BaseApplication *appli );
+	gboolean  ( *initialize_i18n )            ( BaseApplication *appli );
 
 	/**
-	 * application_initialize_gtk:
+	 * initialize_gtk:
 	 * @appli: this #BaseApplication instance.
 	 *
 	 * Initializes the Gtk+ GUI interface.
@@ -149,10 +149,18 @@ typedef struct {
 	 * %APPLICATION_ERROR_GTK, and prepares a short #exit_message to be
 	 * written to stdout.
 	 */
-	gboolean  ( *application_initialize_gtk )        ( BaseApplication *appli );
+	gboolean  ( *initialize_gtk )             ( BaseApplication *appli );
 
 	/**
-	 * application_initialize_unique_app:
+	 * initialize_application_name:
+	 * @appli: this #BaseApplication instance.
+	 *
+	 * Initializes the name of the application.
+	 */
+	gboolean  ( *initialize_application_name )( BaseApplication *appli );
+
+	/**
+	 * initialize_unique_app:
 	 * @appli: this #BaseApplication instance.
 	 *
 	 * If relevant, checks if an instance of the application is already
@@ -176,10 +184,10 @@ typedef struct {
 	 * and prepares a short #exit_message to be displayed in a dialog
 	 * box.
 	 */
-	gboolean  ( *application_initialize_unique_app ) ( BaseApplication *appli );
+	gboolean  ( *initialize_unique_app )      ( BaseApplication *appli );
 
 	/**
-	 * application_initialize_ui:
+	 * initialize_ui:
 	 * @appli: this #BaseApplication instance.
 	 *
 	 * Loads and initializes the XML file which contains the description
@@ -196,10 +204,10 @@ typedef struct {
 	 * class for the XML filename. If not empty, it then loads it, and
 	 * initializes a corresponding GtkBuilder object.
 	 */
-	gboolean  ( *application_initialize_ui )         ( BaseApplication *appli );
+	gboolean  ( *initialize_ui )              ( BaseApplication *appli );
 
 	/**
-	 * application_initialize_default_icon:
+	 * initialize_default_icon:
 	 * @appli: this #BaseApplication instance.
 	 *
 	 * Initializes the default icon for the application.
@@ -209,10 +217,10 @@ typedef struct {
 	 *
 	 * The base class implementation always returns %TRUE.
 	 */
-	gboolean  ( *application_initialize_default_icon )( BaseApplication *appli );
+	gboolean  ( *initialize_default_icon )    ( BaseApplication *appli );
 
 	/**
-	 * application_initialize_application:
+	 * initialize_application:
 	 * @appli: this #BaseApplication instance.
 	 *
 	 * Initializes the derived-class application.
@@ -227,16 +235,16 @@ typedef struct {
 	 * The base class implementation asks the derived class to
 	 * allocates and provides the BaseWindow-derived object which will
 	 * be the main window of the application
-	 * (cf. application_get_main_window()). This step is mandatory.
+	 * (cf. get_main_window()). This step is mandatory.
 	 *
 	 * If failed, this function sets #exit_code to the value which is
 	 * pertinent depending of the missing information, and prepares a
 	 * short #exit_message to be displayed in a dialog box.
 	 */
-	gboolean  ( *application_initialize_application )( BaseApplication *appli );
+	gboolean  ( *initialize_application )     ( BaseApplication *appli );
 
 	/**
-	 * application_get_application_name:
+	 * get_application_name:
 	 * @appli: this #BaseApplication instance.
 	 *
 	 * Asks the derived class for the application name.
@@ -248,10 +256,10 @@ typedef struct {
 	 *
 	 * Returns: the application name, to be g_free() by the caller.
 	 */
-	gchar *   ( *application_get_application_name )  ( BaseApplication *appli );
+	gchar *   ( *get_application_name )       ( BaseApplication *appli );
 
 	/**
-	 * application_get_icon_name:
+	 * get_icon_name:
 	 * @appli: this #BaseApplication instance.
 	 *
 	 * Asks the derived class for the name of the default icon.
@@ -263,10 +271,10 @@ typedef struct {
 	 * Returns: the default icon name for the application, to be
 	 * g_free() by the caller.
 	 */
-	gchar *   ( *application_get_icon_name )         ( BaseApplication *appli );
+	gchar *   ( *get_icon_name )              ( BaseApplication *appli );
 
 	/**
-	 * application_get_unique_app_name:
+	 * get_unique_app_name:
 	 * @appli: this #BaseApplication instance.
 	 *
 	 * Asks the derived class for the UniqueApp name of this application.
@@ -283,10 +291,10 @@ typedef struct {
 	 * Returns: the UniqueApp name of the application, to be g_free()
 	 * by the caller.
 	 */
-	gchar *   ( *application_get_unique_app_name )   ( BaseApplication *appli );
+	gchar *   ( *get_unique_app_name )             ( BaseApplication *appli );
 
 	/**
-	 * application_get_ui_filename:
+	 * get_ui_filename:
 	 * @appli: this #BaseApplication instance.
 	 *
 	 * Asks the derived class for the filename of the XML definition of
@@ -300,17 +308,17 @@ typedef struct {
 	 * Returns: the filename of the XML definition, to be g_free() by
 	 * the caller.
 	 */
-	gchar *   ( *application_get_ui_filename )       ( BaseApplication *appli );
+	gchar *   ( *get_ui_filename )                 ( BaseApplication *appli );
 
 	/**
-	 * application_get_main_window:
+	 * get_main_window:
 	 * @appli: this #BaseApplication instance.
 	 *
 	 * Returns: a pointer to the #BaseWindow-derived main window of the
 	 * application. This pointer is owned by the @appli, and should not
 	 * be g_free() not g_object_unref() by the caller.
 	 */
-	GObject * ( *application_get_main_window )       ( BaseApplication *appli );
+	GObject * ( *get_main_window )            ( BaseApplication *appli );
 }
 	BaseApplicationClass;
 
diff --git a/src/nact/base-application.c b/src/nact/base-application.c
index c40c537..aa071b1 100644
--- a/src/nact/base-application.c
+++ b/src/nact/base-application.c
@@ -64,15 +64,15 @@ struct BaseApplicationPrivate {
 /* instance properties
  */
 enum {
-	PROP_APPLICATION_ARGC_ID = 1,
-	PROP_APPLICATION_ARGV_ID,
-	PROP_APPLICATION_IS_GTK_INITIALIZED_ID,
-	PROP_APPLICATION_UNIQUE_APP_HANDLE_ID,
-	PROP_APPLICATION_EXIT_CODE_ID,
-	PROP_APPLICATION_EXIT_MESSAGE1_ID,
-	PROP_APPLICATION_EXIT_MESSAGE2_ID,
-	PROP_APPLICATION_UI_XML_ID,
-	PROP_APPLICATION_MAIN_WINDOW_ID
+	BASE_APPLICATION_PROP_ARGC_ID = 1,
+	BASE_APPLICATION_PROP_ARGV_ID,
+	BASE_APPLICATION_PROP_IS_GTK_INITIALIZED_ID,
+	BASE_APPLICATION_PROP_UNIQUE_APP_HANDLE_ID,
+	BASE_APPLICATION_PROP_EXIT_CODE_ID,
+	BASE_APPLICATION_PROP_EXIT_MESSAGE1_ID,
+	BASE_APPLICATION_PROP_EXIT_MESSAGE2_ID,
+	BASE_APPLICATION_PROP_UI_XML_ID,
+	BASE_APPLICATION_PROP_MAIN_WINDOW_ID
 };
 
 static GObjectClass *st_parent_class = NULL;
@@ -88,19 +88,21 @@ static void           instance_finalize( GObject *application );
 static gboolean       v_initialize( BaseApplication *application );
 static gboolean       v_initialize_i18n( BaseApplication *application );
 static gboolean       v_initialize_gtk( BaseApplication *application );
+static gboolean       v_initialize_application_name( BaseApplication *application );
 static gboolean       v_initialize_unique_app( BaseApplication *application );
 static gboolean       v_initialize_ui( BaseApplication *application );
 static gboolean       v_initialize_default_icon( BaseApplication *application );
 static gboolean       v_initialize_application( BaseApplication *application );
 
-static int            do_application_run( BaseApplication *application );
-static gboolean       do_application_initialize( BaseApplication *application );
-static gboolean       do_application_initialize_i18n( BaseApplication *application );
-static gboolean       do_application_initialize_gtk( BaseApplication *application );
-static gboolean       do_application_initialize_unique_app( BaseApplication *application );
-static gboolean       do_application_initialize_ui( BaseApplication *application );
-static gboolean       do_application_initialize_default_icon( BaseApplication *application );
-static gboolean       do_application_initialize_application( BaseApplication *application );
+static int            application_do_run( BaseApplication *application );
+static gboolean       application_do_initialize( BaseApplication *application );
+static gboolean       application_do_initialize_i18n( BaseApplication *application );
+static gboolean       application_do_initialize_gtk( BaseApplication *application );
+static gboolean       application_do_initialize_application_name( BaseApplication *application );
+static gboolean       application_do_initialize_unique_app( BaseApplication *application );
+static gboolean       application_do_initialize_ui( BaseApplication *application );
+static gboolean       application_do_initialize_default_icon( BaseApplication *application );
+static gboolean       application_do_initialize_application( BaseApplication *application );
 
 static gboolean       check_for_unique_app( BaseApplication *application );
 /*static UniqueResponse on_unique_message_received( UniqueApp *app, UniqueCommand command, UniqueMessageData *message, guint time, gpointer user_data );*/
@@ -109,7 +111,7 @@ static GtkWidget     *recursive_search_for_child( BaseApplication *application,
 static GtkWidget     *search_for_child_widget( GtkContainer *container, const gchar *name );
 
 static void           display_error_message( BaseApplication *application );
-static void           set_get_dialog_error( BaseApplication *application, const gchar *dialog );
+static void           set_get_toplevel_error( BaseApplication *application, const gchar *name );
 static void           set_initialize_i18n_error( BaseApplication *application );
 static void           set_initialize_gtk_error( BaseApplication *application );
 static void           set_initialize_unique_app_error( BaseApplication *application );
@@ -175,83 +177,84 @@ class_init( BaseApplicationClass *klass )
 	object_class->set_property = instance_set_property;
 
 	spec = g_param_spec_int(
-			PROP_APPLICATION_ARGC,
+			BASE_APPLICATION_PROP_ARGC,
 			"Command-line arguments count",
 			"Command-line arguments count", 0, 65535, 0,
 			G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE );
-	g_object_class_install_property( object_class, PROP_APPLICATION_ARGC_ID, spec );
+	g_object_class_install_property( object_class, BASE_APPLICATION_PROP_ARGC_ID, spec );
 
 	spec = g_param_spec_pointer(
-			PROP_APPLICATION_ARGV,
-			"Command-line arguments",
+			BASE_APPLICATION_PROP_ARGV,
 			"Command-line arguments",
+			"A pointer to command-line arguments",
 			G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE );
-	g_object_class_install_property( object_class, PROP_APPLICATION_ARGV_ID, spec );
+	g_object_class_install_property( object_class, BASE_APPLICATION_PROP_ARGV_ID, spec );
 
 	spec = g_param_spec_boolean(
-			PROP_APPLICATION_IS_GTK_INITIALIZED,
+			BASE_APPLICATION_PROP_IS_GTK_INITIALIZED,
 			"Gtk+ initialization flag",
 			"Has Gtk+ be initialized ?", FALSE,
 			G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE );
-	g_object_class_install_property( object_class, PROP_APPLICATION_IS_GTK_INITIALIZED_ID, spec );
+	g_object_class_install_property( object_class, BASE_APPLICATION_PROP_IS_GTK_INITIALIZED_ID, spec );
 
 	spec = g_param_spec_pointer(
-			PROP_APPLICATION_UNIQUE_APP_HANDLE,
-			"UniqueApp object pointer",
+			BASE_APPLICATION_PROP_UNIQUE_APP_HANDLE,
 			"UniqueApp object pointer",
+			"A reference to the UniqueApp object if any",
 			G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE );
-	g_object_class_install_property( object_class, PROP_APPLICATION_UNIQUE_APP_HANDLE_ID, spec );
+	g_object_class_install_property( object_class, BASE_APPLICATION_PROP_UNIQUE_APP_HANDLE_ID, spec );
 
 	spec = g_param_spec_int(
-			PROP_APPLICATION_EXIT_CODE,
+			BASE_APPLICATION_PROP_EXIT_CODE,
 			"Exit code",
 			"Exit code of the application", 0, 65535, 0,
 			G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE );
-	g_object_class_install_property( object_class, PROP_APPLICATION_EXIT_CODE_ID, spec );
+	g_object_class_install_property( object_class, BASE_APPLICATION_PROP_EXIT_CODE_ID, spec );
 
 	spec = g_param_spec_string(
-			PROP_APPLICATION_EXIT_MESSAGE1,
+			BASE_APPLICATION_PROP_EXIT_MESSAGE1,
 			"Error message",
 			"First line of the error message displayed when exit_code not nul", "",
 			G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE );
-	g_object_class_install_property( object_class, PROP_APPLICATION_EXIT_MESSAGE1_ID, spec );
+	g_object_class_install_property( object_class, BASE_APPLICATION_PROP_EXIT_MESSAGE1_ID, spec );
 
 	spec = g_param_spec_string(
-			PROP_APPLICATION_EXIT_MESSAGE2,
+			BASE_APPLICATION_PROP_EXIT_MESSAGE2,
 			"Error message",
 			"Second line of the error message displayed when exit_code not nul", "",
 			G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE );
-	g_object_class_install_property( object_class, PROP_APPLICATION_EXIT_MESSAGE2_ID, spec );
+	g_object_class_install_property( object_class, BASE_APPLICATION_PROP_EXIT_MESSAGE2_ID, spec );
 
 	spec = g_param_spec_pointer(
-			PROP_APPLICATION_UI_XML,
+			BASE_APPLICATION_PROP_UI_XML,
 			"UI object pointer",
-			"UI definition object pointer",
+			"A reference to the UI definition from GtkBuilder",
 			G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE );
-	g_object_class_install_property( object_class, PROP_APPLICATION_UI_XML_ID, spec );
+	g_object_class_install_property( object_class, BASE_APPLICATION_PROP_UI_XML_ID, spec );
 
 	spec = g_param_spec_pointer(
-			PROP_APPLICATION_MAIN_WINDOW,
-			"Main BaseWindow object",
+			BASE_APPLICATION_PROP_MAIN_WINDOW,
 			"Main BaseWindow object",
+			"A reference to the main BaseWindow object",
 			G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE );
-	g_object_class_install_property( object_class, PROP_APPLICATION_MAIN_WINDOW_ID, spec );
+	g_object_class_install_property( object_class, BASE_APPLICATION_PROP_MAIN_WINDOW_ID, spec );
 
 	klass->private = g_new0( BaseApplicationClassPrivate, 1 );
 
-	klass->application_run = do_application_run;
-	klass->application_initialize = do_application_initialize;
-	klass->application_initialize_i18n = do_application_initialize_i18n;
-	klass->application_initialize_gtk = do_application_initialize_gtk;
-	klass->application_initialize_unique_app = do_application_initialize_unique_app;
-	klass->application_initialize_ui = do_application_initialize_ui;
-	klass->application_initialize_default_icon = do_application_initialize_default_icon;
-	klass->application_initialize_application = do_application_initialize_application;
-	klass->application_get_application_name = NULL;
-	klass->application_get_icon_name = NULL;
-	klass->application_get_unique_app_name = NULL;
-	klass->application_get_ui_filename = NULL;
-	klass->application_get_main_window = NULL;
+	klass->run = application_do_run;
+	klass->initialize = application_do_initialize;
+	klass->initialize_i18n = application_do_initialize_i18n;
+	klass->initialize_gtk = application_do_initialize_gtk;
+	klass->initialize_application_name = application_do_initialize_application_name;
+	klass->initialize_unique_app = application_do_initialize_unique_app;
+	klass->initialize_ui = application_do_initialize_ui;
+	klass->initialize_default_icon = application_do_initialize_default_icon;
+	klass->initialize_application = application_do_initialize_application;
+	klass->get_application_name = NULL;
+	klass->get_icon_name = NULL;
+	klass->get_unique_app_name = NULL;
+	klass->get_ui_filename = NULL;
+	klass->get_main_window = NULL;
 }
 
 static void
@@ -262,7 +265,7 @@ instance_init( GTypeInstance *instance, gpointer klass )
 
 	g_debug( "%s: instance=%p, klass=%p", thisfn, ( void * ) instance, ( void * ) klass );
 
-	g_assert( BASE_IS_APPLICATION( instance ));
+	g_return_if_fail( BASE_IS_APPLICATION( instance ));
 	self = BASE_APPLICATION( instance );
 
 	self->private = g_new0( BaseApplicationPrivate, 1 );
@@ -276,43 +279,43 @@ instance_get_property( GObject *object, guint property_id, GValue *value, GParam
 {
 	BaseApplication *self;
 
-	g_assert( BASE_IS_APPLICATION( object ));
+	g_return_if_fail( BASE_IS_APPLICATION( object ));
 	self = BASE_APPLICATION( object );
 
 	switch( property_id ){
-		case PROP_APPLICATION_ARGC_ID:
+		case BASE_APPLICATION_PROP_ARGC_ID:
 			g_value_set_int( value, self->private->argc );
 			break;
 
-		case PROP_APPLICATION_ARGV_ID:
+		case BASE_APPLICATION_PROP_ARGV_ID:
 			g_value_set_pointer( value, self->private->argv );
 			break;
 
-		case PROP_APPLICATION_IS_GTK_INITIALIZED_ID:
+		case BASE_APPLICATION_PROP_IS_GTK_INITIALIZED_ID:
 			g_value_set_boolean( value, self->private->is_gtk_initialized );
 			break;
 
-		case PROP_APPLICATION_UNIQUE_APP_HANDLE_ID:
+		case BASE_APPLICATION_PROP_UNIQUE_APP_HANDLE_ID:
 			g_value_set_pointer( value, self->private->unique_app_handle );
 			break;
 
-		case PROP_APPLICATION_EXIT_CODE_ID:
+		case BASE_APPLICATION_PROP_EXIT_CODE_ID:
 			g_value_set_int( value, self->private->exit_code );
 			break;
 
-		case PROP_APPLICATION_EXIT_MESSAGE1_ID:
+		case BASE_APPLICATION_PROP_EXIT_MESSAGE1_ID:
 			g_value_set_string( value, self->private->exit_message1 );
 			break;
 
-		case PROP_APPLICATION_EXIT_MESSAGE2_ID:
+		case BASE_APPLICATION_PROP_EXIT_MESSAGE2_ID:
 			g_value_set_string( value, self->private->exit_message2 );
 			break;
 
-		case PROP_APPLICATION_UI_XML_ID:
+		case BASE_APPLICATION_PROP_UI_XML_ID:
 			g_value_set_pointer( value, self->private->ui_xml );
 			break;
 
-		case PROP_APPLICATION_MAIN_WINDOW_ID:
+		case BASE_APPLICATION_PROP_MAIN_WINDOW_ID:
 			g_value_set_pointer( value, self->private->main_window );
 			break;
 
@@ -327,45 +330,45 @@ instance_set_property( GObject *object, guint property_id, const GValue *value,
 {
 	BaseApplication *self;
 
-	g_assert( BASE_IS_APPLICATION( object ));
+	g_return_if_fail( BASE_IS_APPLICATION( object ));
 	self = BASE_APPLICATION( object );
 
 	switch( property_id ){
-		case PROP_APPLICATION_ARGC_ID:
+		case BASE_APPLICATION_PROP_ARGC_ID:
 			self->private->argc = g_value_get_int( value );
 			break;
 
-		case PROP_APPLICATION_ARGV_ID:
+		case BASE_APPLICATION_PROP_ARGV_ID:
 			self->private->argv = g_value_get_pointer( value );
 			break;
 
-		case PROP_APPLICATION_IS_GTK_INITIALIZED_ID:
+		case BASE_APPLICATION_PROP_IS_GTK_INITIALIZED_ID:
 			self->private->is_gtk_initialized = g_value_get_boolean( value );
 			break;
 
-		case PROP_APPLICATION_UNIQUE_APP_HANDLE_ID:
+		case BASE_APPLICATION_PROP_UNIQUE_APP_HANDLE_ID:
 			self->private->unique_app_handle = g_value_get_pointer( value );
 			break;
 
-		case PROP_APPLICATION_EXIT_CODE_ID:
+		case BASE_APPLICATION_PROP_EXIT_CODE_ID:
 			self->private->exit_code = g_value_get_int( value );
 			break;
 
-		case PROP_APPLICATION_EXIT_MESSAGE1_ID:
+		case BASE_APPLICATION_PROP_EXIT_MESSAGE1_ID:
 			g_free( self->private->exit_message1 );
 			self->private->exit_message1 = g_value_dup_string( value );
 			break;
 
-		case PROP_APPLICATION_EXIT_MESSAGE2_ID:
+		case BASE_APPLICATION_PROP_EXIT_MESSAGE2_ID:
 			g_free( self->private->exit_message2 );
 			self->private->exit_message2 = g_value_dup_string( value );
 			break;
 
-		case PROP_APPLICATION_UI_XML_ID:
+		case BASE_APPLICATION_PROP_UI_XML_ID:
 			self->private->ui_xml = g_value_get_pointer( value );
 			break;
 
-		case PROP_APPLICATION_MAIN_WINDOW_ID:
+		case BASE_APPLICATION_PROP_MAIN_WINDOW_ID:
 			self->private->main_window = g_value_get_pointer( value );
 			break;
 
@@ -382,7 +385,7 @@ instance_dispose( GObject *application )
 	BaseApplication *self;
 
 	g_debug( "%s: application=%p", thisfn, ( void * ) application );
-	g_assert( BASE_IS_APPLICATION( application ));
+	g_return_if_fail( BASE_IS_APPLICATION( application ));
 	self = BASE_APPLICATION( application );
 
 	if( !self->private->dispose_has_run ){
@@ -398,7 +401,9 @@ instance_dispose( GObject *application )
 		}
 
 		/* chain up to the parent class */
-		G_OBJECT_CLASS( st_parent_class )->dispose( application );
+		if( G_OBJECT_CLASS( st_parent_class )->dispose ){
+			G_OBJECT_CLASS( st_parent_class )->dispose( application );
+		}
 	}
 }
 
@@ -409,7 +414,7 @@ instance_finalize( GObject *application )
 	BaseApplication *self;
 
 	g_debug( "%s: application=%p", thisfn, ( void * ) application );
-	g_assert( BASE_IS_APPLICATION( application ));
+	g_return_if_fail( BASE_IS_APPLICATION( application ));
 	self = ( BaseApplication * ) application;
 
 	g_free( self->private->exit_message1 );
@@ -418,7 +423,7 @@ instance_finalize( GObject *application )
 	g_free( self->private );
 
 	/* chain call to parent class */
-	if( st_parent_class->finalize ){
+	if( G_OBJECT_CLASS( st_parent_class )->finalize ){
 		G_OBJECT_CLASS( st_parent_class )->finalize( application );
 	}
 }
@@ -445,9 +450,9 @@ base_application_run( BaseApplication *application )
 
 	g_debug( "%s: application=%p", thisfn, ( void * ) application );
 
-	g_assert( BASE_IS_APPLICATION( application ));
+	g_return_val_if_fail( BASE_IS_APPLICATION( application ), -1 );
 
-	return( BASE_APPLICATION_GET_CLASS( application )->application_run( application ));
+	return( BASE_APPLICATION_GET_CLASS( application )->run( application ));
 }
 
 /**
@@ -469,10 +474,10 @@ base_application_get_application_name( BaseApplication *application )
 
 	gchar *name = NULL;
 
-	g_assert( BASE_IS_APPLICATION( application ));
+	g_return_val_if_fail( BASE_IS_APPLICATION( application ), NULL );
 
-	if( BASE_APPLICATION_GET_CLASS( application )->application_get_application_name ){
-		name = BASE_APPLICATION_GET_CLASS( application )->application_get_application_name( application );
+	if( BASE_APPLICATION_GET_CLASS( application )->get_application_name ){
+		name = BASE_APPLICATION_GET_CLASS( application )->get_application_name( application );
 
 	} else {
 		name = g_strdup( "" );
@@ -499,10 +504,10 @@ base_application_get_icon_name( BaseApplication *application )
 
 	gchar *name = NULL;
 
-	g_assert( BASE_IS_APPLICATION( application ));
+	g_return_val_if_fail( BASE_IS_APPLICATION( application ), NULL );
 
-	if( BASE_APPLICATION_GET_CLASS( application )->application_get_icon_name ){
-		name = BASE_APPLICATION_GET_CLASS( application )->application_get_icon_name( application );
+	if( BASE_APPLICATION_GET_CLASS( application )->get_icon_name ){
+		name = BASE_APPLICATION_GET_CLASS( application )->get_icon_name( application );
 
 	} else {
 		name = g_strdup( "" );
@@ -529,10 +534,10 @@ base_application_get_unique_app_name( BaseApplication *application )
 
 	gchar *name = NULL;
 
-	g_assert( BASE_IS_APPLICATION( application ));
+	g_return_val_if_fail( BASE_IS_APPLICATION( application ), NULL );
 
-	if( BASE_APPLICATION_GET_CLASS( application )->application_get_unique_app_name ){
-		name = BASE_APPLICATION_GET_CLASS( application )->application_get_unique_app_name( application );
+	if( BASE_APPLICATION_GET_CLASS( application )->get_unique_app_name ){
+		name = BASE_APPLICATION_GET_CLASS( application )->get_unique_app_name( application );
 
 	} else {
 		name = g_strdup( "" );
@@ -560,10 +565,10 @@ base_application_get_ui_filename( BaseApplication *application )
 
 	gchar *name = NULL;
 
-	g_assert( BASE_IS_APPLICATION( application ));
+	g_return_val_if_fail( BASE_IS_APPLICATION( application ), NULL );
 
-	if( BASE_APPLICATION_GET_CLASS( application )->application_get_ui_filename ){
-		name = BASE_APPLICATION_GET_CLASS( application )->application_get_ui_filename( application );
+	if( BASE_APPLICATION_GET_CLASS( application )->get_ui_filename ){
+		name = BASE_APPLICATION_GET_CLASS( application )->get_ui_filename( application );
 
 	} else {
 		name = g_strdup( "" );
@@ -592,20 +597,20 @@ base_application_get_main_window( BaseApplication *application )
 	/*static const gchar *thisfn = "base_application_get_main_window";
 	g_debug( "%s: application=%p", thisfn, application );*/
 
-	g_assert( BASE_IS_APPLICATION( application ));
+	g_return_val_if_fail( BASE_IS_APPLICATION( application ), NULL );
 
 	if( !application->private->main_window &&
-		BASE_APPLICATION_GET_CLASS( application )->application_get_main_window ){
-			application->private->main_window = BASE_WINDOW( BASE_APPLICATION_GET_CLASS( application )->application_get_main_window( application ));
+		BASE_APPLICATION_GET_CLASS( application )->get_main_window ){
+			application->private->main_window = BASE_WINDOW( BASE_APPLICATION_GET_CLASS( application )->get_main_window( application ));
 	}
 
 	return( application->private->main_window );
 }
 
 /**
- * base_application_get_dialog:
+ * base_application_get_toplevel:
  * @application: this #BaseApplication instance.
- * @name: the name of the searched toplevel dialog.
+ * @name: the name of the searched toplevel window.
  *
  * This function provides a pointer to the toplevel dialog associated
  * with the specified #BaseWindow.
@@ -615,21 +620,26 @@ base_application_get_main_window( BaseApplication *application )
  * g_free() nor g_object_unref() by the caller.
  */
 GtkWindow *
-base_application_get_dialog( BaseApplication *application, const gchar *name )
+base_application_get_toplevel( BaseApplication *application, const gchar *name )
 {
 	/*static const gchar *thisfn = "base_application_get_dialog";
 	g_debug( "%s: application=%p, name=%s", thisfn, application, name );*/
+	GtkWindow *toplevel;
 
-	GtkWindow *dialog = GTK_WINDOW( gtk_builder_get_object( application->private->ui_xml, name ));
+	g_return_val_if_fail( BASE_IS_APPLICATION( application ), NULL );
+	g_return_val_if_fail( name, NULL );
+	g_return_val_if_fail( strlen( name ), NULL );
 
-	if( !dialog ){
-		set_get_dialog_error( application, name );
+	toplevel = GTK_WINDOW( gtk_builder_get_object( application->private->ui_xml, name ));
+
+	if( !toplevel ){
+		set_get_toplevel_error( application, name );
 
 	} else {
-		g_assert( GTK_IS_WINDOW( dialog ));
+		g_assert( GTK_IS_WINDOW( toplevel ));
 	}
 
-	return( dialog );
+	return( toplevel );
 }
 
 /**
@@ -650,8 +660,14 @@ base_application_get_widget( BaseApplication *application, BaseWindow *window, c
 {
 	/*static const gchar *thisfn = "base_application_get_widget";
 	g_debug( "%s: application=%p, name=%s", thisfn, application, name );*/
+	GtkWindow *toplevel;
+
+	g_return_val_if_fail( BASE_IS_APPLICATION( application ), NULL );
+	g_return_val_if_fail( BASE_IS_WINDOW( window ), NULL );
+	g_return_val_if_fail( name, NULL );
+	g_return_val_if_fail( strlen( name ), NULL );
 
-	GtkWindow *toplevel = base_window_get_toplevel_dialog( window );
+	toplevel = base_window_get_toplevel_window( window );
 
 	return( base_application_search_for_widget( application, toplevel, name ));
 }
@@ -725,9 +741,8 @@ v_initialize( BaseApplication *application )
 	static const gchar *thisfn = "base_application_v_initialize";
 
 	g_debug( "%s: application=%p", thisfn, ( void * ) application );
-	g_assert( BASE_IS_APPLICATION( application ));
 
-	return( BASE_APPLICATION_GET_CLASS( application )->application_initialize( application ));
+	return( BASE_APPLICATION_GET_CLASS( application )->initialize( application ));
 }
 
 static gboolean
@@ -737,9 +752,8 @@ v_initialize_i18n( BaseApplication *application )
 	gboolean ok;
 
 	g_debug( "%s: application=%p", thisfn, ( void * ) application );
-	g_assert( BASE_IS_APPLICATION( application ));
 
-	ok = BASE_APPLICATION_GET_CLASS( application )->application_initialize_i18n( application );
+	ok = BASE_APPLICATION_GET_CLASS( application )->initialize_i18n( application );
 
 	if( !ok ){
 		set_initialize_i18n_error( application );
@@ -755,9 +769,8 @@ v_initialize_gtk( BaseApplication *application )
 	gboolean ok;
 
 	g_debug( "%s: application=%p", thisfn, ( void * ) application );
-	g_assert( BASE_IS_APPLICATION( application ));
 
-	ok = BASE_APPLICATION_GET_CLASS( application )->application_initialize_gtk( application );
+	ok = BASE_APPLICATION_GET_CLASS( application )->initialize_gtk( application );
 
 	if( ok ){
 		application->private->is_gtk_initialized = TRUE;
@@ -770,15 +783,27 @@ v_initialize_gtk( BaseApplication *application )
 }
 
 static gboolean
+v_initialize_application_name( BaseApplication *application )
+{
+	static const gchar *thisfn = "base_application_v_initialize_application_name";
+	gboolean ok;
+
+	g_debug( "%s: application=%p", thisfn, ( void * ) application );
+
+	ok = BASE_APPLICATION_GET_CLASS( application )->initialize_application_name( application );
+
+	return( ok );
+}
+
+static gboolean
 v_initialize_unique_app( BaseApplication *application )
 {
 	static const gchar *thisfn = "base_application_v_initialize_unique_app";
 	gboolean ok;
 
 	g_debug( "%s: application=%p", thisfn, ( void * ) application );
-	g_assert( BASE_IS_APPLICATION( application ));
 
-	ok = BASE_APPLICATION_GET_CLASS( application )->application_initialize_unique_app( application );
+	ok = BASE_APPLICATION_GET_CLASS( application )->initialize_unique_app( application );
 
 	if( !ok ){
 		set_initialize_unique_app_error( application );
@@ -793,9 +818,8 @@ v_initialize_ui( BaseApplication *application )
 	static const gchar *thisfn = "base_application_v_initialize_ui";
 
 	g_debug( "%s: application=%p", thisfn, ( void * ) application );
-	g_assert( BASE_IS_APPLICATION( application ));
 
-	return( BASE_APPLICATION_GET_CLASS( application )->application_initialize_ui( application ));
+	return( BASE_APPLICATION_GET_CLASS( application )->initialize_ui( application ));
 }
 
 static gboolean
@@ -805,9 +829,8 @@ v_initialize_default_icon( BaseApplication *application )
 	gboolean ok;
 
 	g_debug( "%s: application=%p", thisfn, ( void * ) application );
-	g_assert( BASE_IS_APPLICATION( application ));
 
-	ok = BASE_APPLICATION_GET_CLASS( application )->application_initialize_default_icon( application );
+	ok = BASE_APPLICATION_GET_CLASS( application )->initialize_default_icon( application );
 
 	if( !ok ){
 		set_initialize_default_icon_error( application );
@@ -823,9 +846,8 @@ v_initialize_application( BaseApplication *application )
 	gboolean ok;
 
 	g_debug( "%s: application=%p", thisfn, ( void * ) application );
-	g_assert( BASE_IS_APPLICATION( application ));
 
-	ok = BASE_APPLICATION_GET_CLASS( application )->application_initialize_application( application );
+	ok = BASE_APPLICATION_GET_CLASS( application )->initialize_application( application );
 
 	if( !ok ){
 		set_initialize_application_error( application );
@@ -835,29 +857,30 @@ v_initialize_application( BaseApplication *application )
 }
 
 static int
-do_application_run( BaseApplication *application )
+application_do_run( BaseApplication *application )
 {
-	static const gchar *thisfn = "base_application_do_application_run";
+	static const gchar *thisfn = "base_application_do_run";
 	GtkWindow *wnd;
 
 	g_debug( "%s: application=%p", thisfn, ( void * ) application );
 
 	if( v_initialize( application )){
 
-		g_assert( application->private->main_window );
-		g_assert( BASE_IS_WINDOW( application->private->main_window ));
+		g_return_val_if_fail( application->private->main_window, -1 );
+		g_return_val_if_fail( BASE_IS_WINDOW( application->private->main_window ), -1 );
 
-		base_window_init( application->private->main_window );
+		if( base_window_init( application->private->main_window )){
 
-		wnd = base_window_get_toplevel_dialog( application->private->main_window );
-		g_assert( wnd );
-		g_assert( GTK_IS_WINDOW( wnd ));
+			wnd = base_window_get_toplevel_window( application->private->main_window );
+			g_assert( wnd );
+			g_assert( GTK_IS_WINDOW( wnd ));
 
-		if( application->private->unique_app_handle ){
-			unique_app_watch_window( application->private->unique_app_handle, wnd );
-		}
+			if( application->private->unique_app_handle ){
+				unique_app_watch_window( application->private->unique_app_handle, wnd );
+			}
 
-		base_window_run( application->private->main_window );
+			base_window_run( application->private->main_window );
+		}
 	}
 
 	display_error_message( application );
@@ -866,11 +889,16 @@ do_application_run( BaseApplication *application )
 }
 
 static gboolean
-do_application_initialize( BaseApplication *application )
+application_do_initialize( BaseApplication *application )
 {
+	static const gchar *thisfn = "base_application_do_initialize";
+
+	g_debug( "%s: application=%p", thisfn, ( void * ) application );
+
 	return(
 			v_initialize_i18n( application ) &&
 			v_initialize_gtk( application ) &&
+			v_initialize_application_name( application ) &&
 			v_initialize_unique_app( application ) &&
 			v_initialize_ui( application ) &&
 			v_initialize_default_icon( application ) &&
@@ -879,8 +907,12 @@ do_application_initialize( BaseApplication *application )
 }
 
 static gboolean
-do_application_initialize_i18n( BaseApplication *application )
+application_do_initialize_i18n( BaseApplication *application )
 {
+	static const gchar *thisfn = "base_application_do_initialize_i18n";
+
+	g_debug( "%s: application=%p", thisfn, ( void * ) application );
+
 #ifdef ENABLE_NLS
 	bindtextdomain( GETTEXT_PACKAGE, GNOMELOCALEDIR );
 # ifdef HAVE_BIND_TEXTDOMAIN_CODESET
@@ -892,29 +924,52 @@ do_application_initialize_i18n( BaseApplication *application )
 }
 
 static gboolean
-do_application_initialize_gtk( BaseApplication *application )
+application_do_initialize_gtk( BaseApplication *application )
 {
+	static const gchar *thisfn = "base_application_do_initialize_gtk";
 	int argc;
 	gpointer argv;
 	gboolean ret;
 
-	g_object_get( G_OBJECT( application ), PROP_APPLICATION_ARGC, &argc, PROP_APPLICATION_ARGV, &argv, NULL );
+	g_debug( "%s: application=%p", thisfn, ( void * ) application );
+
+	g_object_get( G_OBJECT( application ), BASE_APPLICATION_PROP_ARGC, &argc, BASE_APPLICATION_PROP_ARGV, &argv, NULL );
 
 	ret = gtk_init_check( &argc, ( char *** ) &argv );
 
 	if( ret ){
-		g_object_set( G_OBJECT( application ), PROP_APPLICATION_ARGC, argc, PROP_APPLICATION_ARGV, argv, NULL );
+		g_object_set( G_OBJECT( application ), BASE_APPLICATION_PROP_ARGC, argc, BASE_APPLICATION_PROP_ARGV, argv, NULL );
 	}
 
 	return( ret );
 }
 
 static gboolean
-do_application_initialize_unique_app( BaseApplication *application )
+application_do_initialize_application_name( BaseApplication *application )
+{
+	static const gchar *thisfn = "base_application_do_initialize_application_name";
+	gchar *name;
+
+	g_debug( "%s: application=%p", thisfn, ( void * ) application );
+
+	name = base_application_get_application_name( application );
+	if( name && g_utf8_strlen( name, -1 )){
+		g_set_application_name( name );
+	}
+	g_free( name );
+
+	return( TRUE );
+}
+
+static gboolean
+application_do_initialize_unique_app( BaseApplication *application )
 {
+	static const gchar *thisfn = "base_application_do_initialize_unique_app";
 	gboolean ret = TRUE;
 	gchar *name;
 
+	g_debug( "%s: application=%p", thisfn, ( void * ) application );
+
 	name = base_application_get_unique_app_name( application );
 
 	if( name && strlen( name )){
@@ -927,13 +982,16 @@ do_application_initialize_unique_app( BaseApplication *application )
 }
 
 static gboolean
-do_application_initialize_ui( BaseApplication *application )
+application_do_initialize_ui( BaseApplication *application )
 {
+	static const gchar *thisfn = "base_application_do_initialize_ui";
 	gboolean ret = TRUE;
 	GError *error = NULL;
 	gchar *name;
 	guint retint;
 
+	g_debug( "%s: application=%p", thisfn, ( void * ) application );
+
 	name = base_application_get_ui_filename( application );
 
 	if( !name || !strlen( name )){
@@ -955,10 +1013,13 @@ do_application_initialize_ui( BaseApplication *application )
 }
 
 static gboolean
-do_application_initialize_default_icon( BaseApplication *application )
+application_do_initialize_default_icon( BaseApplication *application )
 {
+	static const gchar *thisfn = "base_application_do_initialize_default_icon";
 	gchar *name;
 
+	g_debug( "%s: application=%p", thisfn, ( void * ) application );
+
 	name = base_application_get_icon_name( application );
 
 	if( name && strlen( name )){
@@ -971,10 +1032,13 @@ do_application_initialize_default_icon( BaseApplication *application )
 }
 
 static gboolean
-do_application_initialize_application( BaseApplication *application )
+application_do_initialize_application( BaseApplication *application )
 {
+	static const gchar *thisfn = "base_application_do_initialize_application";
 	BaseWindow *window;
 
+	g_debug( "%s: application=%p", thisfn, ( void * ) application );
+
 	window = base_application_get_main_window( application );
 
 	return( window != NULL );
@@ -983,8 +1047,10 @@ do_application_initialize_application( BaseApplication *application )
 static gboolean
 check_for_unique_app( BaseApplication *application )
 {
+	static const gchar *thisfn = "base_application_check_for_unique_app";
 	gboolean is_first = TRUE;
 
+	g_debug( "%s: application=%p", thisfn, ( void * ) application );
 	g_assert( BASE_IS_APPLICATION( application ));
 
 	if( unique_app_is_running( application->private->unique_app_handle )){
@@ -1115,17 +1181,17 @@ display_error_message( BaseApplication *application )
 }
 
 static void
-set_get_dialog_error( BaseApplication *application, const gchar *dialog )
+set_get_toplevel_error( BaseApplication *application, const gchar *toplevel_name )
 {
 	gchar *fname, *msg;
 
-	application->private->exit_code = APPLICATION_ERROR_DIALOG_LOAD;
+	application->private->exit_code = BASE_APPLICATION_ERROR_TOPLEVEL_LOAD;
 
 	fname = base_application_get_ui_filename( application );
 
 	msg = g_strdup_printf(
 			/* i18n: unable to load <dialog_name> dialog from XML definition in <filename> */
-			_( "Unable to load %s dialog from XML definition in %s." ), dialog, fname );
+			_( "Unable to load %s dialog from XML definition in %s." ), toplevel_name, fname );
 
 	base_application_error_dlg( application, GTK_MESSAGE_ERROR, msg, NULL );
 
@@ -1136,7 +1202,7 @@ set_get_dialog_error( BaseApplication *application, const gchar *dialog )
 static void
 set_initialize_i18n_error( BaseApplication *application )
 {
-	application->private->exit_code = APPLICATION_ERROR_I18N;
+	application->private->exit_code = BASE_APPLICATION_ERROR_I18N;
 
 	application->private->exit_message1 =
 		g_strdup( _( "Unable to initialize the internationalization environment." ));
@@ -1145,7 +1211,7 @@ set_initialize_i18n_error( BaseApplication *application )
 static void
 set_initialize_gtk_error( BaseApplication *application )
 {
-	application->private->exit_code = APPLICATION_ERROR_GTK;
+	application->private->exit_code = BASE_APPLICATION_ERROR_GTK;
 
 	application->private->exit_message1 =
 		g_strdup( _( "Unable to initialize the Gtk+ user interface." ));
@@ -1154,7 +1220,7 @@ set_initialize_gtk_error( BaseApplication *application )
 static void
 set_initialize_unique_app_error( BaseApplication *application )
 {
-	application->private->exit_code = APPLICATION_ERROR_UNIQUE_APP;
+	application->private->exit_code = BASE_APPLICATION_ERROR_UNIQUE_APP;
 
 	application->private->exit_message1 =
 		g_strdup( _( "Another instance of the application is already running." ));
@@ -1163,7 +1229,7 @@ set_initialize_unique_app_error( BaseApplication *application )
 static void
 set_initialize_ui_get_fname_error( BaseApplication *application )
 {
-	application->private->exit_code = APPLICATION_ERROR_UI_FNAME;
+	application->private->exit_code = BASE_APPLICATION_ERROR_UI_FNAME;
 
 	application->private->exit_message1 =
 		g_strdup( _( "No filename provided for the UI XML definition." ));
@@ -1172,7 +1238,7 @@ set_initialize_ui_get_fname_error( BaseApplication *application )
 static void
 set_initialize_ui_add_xml_error( BaseApplication *application, const gchar *filename, GError *error )
 {
-	application->private->exit_code = APPLICATION_ERROR_UI_LOAD;
+	application->private->exit_code = BASE_APPLICATION_ERROR_UI_LOAD;
 
 	application->private->exit_message1 =
 		/* i18n: Unable to load the XML definition from <filename> */
@@ -1186,7 +1252,7 @@ set_initialize_ui_add_xml_error( BaseApplication *application, const gchar *file
 static void
 set_initialize_default_icon_error( BaseApplication *application )
 {
-	application->private->exit_code = APPLICATION_ERROR_DEFAULT_ICON;
+	application->private->exit_code = BASE_APPLICATION_ERROR_DEFAULT_ICON;
 
 	application->private->exit_message1 =
 		g_strdup( _( "Unable to set the default icon for the application." ));
@@ -1195,7 +1261,7 @@ set_initialize_default_icon_error( BaseApplication *application )
 static void
 set_initialize_application_error( BaseApplication *application )
 {
-	application->private->exit_code = APPLICATION_ERROR_MAIN_WINDOW;
+	application->private->exit_code = BASE_APPLICATION_ERROR_MAIN_WINDOW;
 
 	application->private->exit_message1 =
 		g_strdup( _( "Unable to get the main window of the application." ));
diff --git a/src/nact/base-application.h b/src/nact/base-application.h
index 7a7f892..dafcdba 100644
--- a/src/nact/base-application.h
+++ b/src/nact/base-application.h
@@ -45,70 +45,71 @@
 G_BEGIN_DECLS
 
 enum {
-	APPLICATION_ERROR_I18N = 1,		/* i18n initialization error */
-	APPLICATION_ERROR_GTK,			/* gtk+ initialization error */
-	APPLICATION_ERROR_MAIN_WINDOW,	/* unable to obtain the main window */
-	APPLICATION_ERROR_UNIQUE_APP,	/* another instance is running */
-	APPLICATION_ERROR_UI_FNAME,		/* empty XML filename */
-	APPLICATION_ERROR_UI_LOAD,		/* unable to load the XML definition of the UI */
-	APPLICATION_ERROR_DIALOG_LOAD,	/* unable to load a dialog from the XML definition */
-	APPLICATION_ERROR_DEFAULT_ICON	/* unable to set default icon */
+	BASE_APPLICATION_ERROR_I18N = 1,		/* i18n initialization error */
+	BASE_APPLICATION_ERROR_GTK,				/* gtk+ initialization error */
+	BASE_APPLICATION_ERROR_MAIN_WINDOW,		/* unable to obtain the main window */
+	BASE_APPLICATION_ERROR_UNIQUE_APP,		/* another instance is running */
+	BASE_APPLICATION_ERROR_UI_FNAME,		/* empty XML filename */
+	BASE_APPLICATION_ERROR_UI_LOAD,			/* unable to load the XML definition of the UI */
+	BASE_APPLICATION_ERROR_TOPLEVEL_LOAD,	/* unable to load a toplevel from the XML definition */
+	BASE_APPLICATION_ERROR_DEFAULT_ICON		/* unable to set default icon */
 };
 
 /**
- * @PROP_APPLICATION_ARGC: count of arguments in command-line.
- * @PROP_APPLICATION_ARGV: list of command-line arguments
+ * @BASE_APPLICATION_PROP_ARGC: count of arguments in command-line.
+ * @BASE_APPLICATION_PROP_ARGV: list of command-line arguments
  *
  * These two variables must be provided before running the
  * initialization process ; they are required in order to correctly
  * initialize the Gtk+ user interface.
  */
-#define PROP_APPLICATION_ARGC				"base-application-argc"
-#define PROP_APPLICATION_ARGV				"base-application-argv"
+#define BASE_APPLICATION_PROP_ARGC					"base-application-argc"
+#define BASE_APPLICATION_PROP_ARGV					"base-application-argv"
 
 /**
- * @PROP_APPLICATION_IS_GTK_INITIALIZED: set to %TRUE after successfully
- * returning from the application_initialize_gtk() virtual function.
+ * @BASE_APPLICATION_PROP_IS_GTK_INITIALIZED: set to %TRUE after
+ * successfully returning from the application_initialize_gtk() virtual
+ * function.
  *
  * While this flag is not %TRUE, error messages are printed to
  * stdout. When %TRUE, error messages are displayed with a dialog
  * box.
  */
-#define PROP_APPLICATION_IS_GTK_INITIALIZED	"base-application-is-gtk-initialized"
+#define BASE_APPLICATION_PROP_IS_GTK_INITIALIZED	"base-application-is-gtk-initialized"
 
 /**
- * @PROP_APPLICATION_UNIQUE_APP_HANDLE: the UniqueApp object allocated
+ * @BASE_APPLICATION_PROP_UNIQUE_APP_HANDLE: the UniqueApp object allocated
  * if the derived-class has provided a UniqueApp name (see
  * #application_get_unique_app_name). Rather for internal use.
  */
-#define PROP_APPLICATION_UNIQUE_APP_HANDLE	"base-application-unique-app-handle"
+#define BASE_APPLICATION_PROP_UNIQUE_APP_HANDLE		"base-application-unique-app-handle"
 
 /**
- * @PROP_APPLICATION_EXIT_CODE: the code which will be returned by the
+ * @BASE_APPLICATION_PROP_EXIT_CODE: the code which will be returned by the
  * program to the operating system.
- * @PROP_APPLICATION_EXIT_MESSAGE1:
- * @PROP_APPLICATION_EXIT_MESSAGE2: the message which will be displayed
- * at program terminaison if @PROP_APPLICATION_EXIT_CODE is not zero.
+ * @BASE_APPLICATION_PROP_EXIT_MESSAGE1:
+ * @BASE_APPLICATION_PROP_EXIT_MESSAGE2: the message which will be displayed
+ * at program terminaison if @BASE_APPLICATION_PROP_EXIT_CODE is not zero.
  * When in graphical mode, the first line is displayed as bold.
  *
- * See @PROP_APPLICATION_IS_GTK_INITIALIZED for how the
- * @PROP_APPLICATION_EXIT_MESSAGE is actually displayed.
+ * See @BASE_APPLICATION_PROP_IS_GTK_INITIALIZED for how the
+ * @BASE_APPLICATION_PROP_EXIT_MESSAGE is actually displayed.
  */
-#define PROP_APPLICATION_EXIT_CODE			"base-application-exit-code"
-#define PROP_APPLICATION_EXIT_MESSAGE1		"base-application-exit-message1"
-#define PROP_APPLICATION_EXIT_MESSAGE2		"base-application-exit-message2"
+#define BASE_APPLICATION_PROP_EXIT_CODE				"base-application-exit-code"
+#define BASE_APPLICATION_PROP_EXIT_MESSAGE1			"base-application-exit-message1"
+#define BASE_APPLICATION_PROP_EXIT_MESSAGE2			"base-application-exit-message2"
 
 /**
- * @PROP_APPLICATION_UI_XML: the GtkBuilder object allocated to handle
+ * @BASE_APPLICATION_PROP_UI_XML: the GtkBuilder object allocated to handle
  * the user interface XML definition. Rather for internal use.
  */
-#define PROP_APPLICATION_UI_XML				"base-application-ui-xml"
+#define BASE_APPLICATION_PROP_UI_XML				"base-application-ui-xml"
 
 /**
- * @PROP_APPLICATION_MAIN_WINDOW: as its name says: a pointer to the
+ * @BASE_APPLICATION_PROP_MAIN_WINDOW: as its name says: a pointer to the
  * #BaseWindow-derived main window of the application.
  */
-#define PROP_APPLICATION_MAIN_WINDOW		"base-application-main-window"
+#define BASE_APPLICATION_PROP_MAIN_WINDOW			"base-application-main-window"
 
 int         base_application_run( BaseApplication *application );
 gchar      *base_application_get_application_name( BaseApplication *application );
@@ -117,7 +118,7 @@ gchar      *base_application_get_unique_app_name( BaseApplication *application )
 gchar      *base_application_get_ui_filename( BaseApplication *application );
 BaseWindow *base_application_get_main_window( BaseApplication *application );
 
-GtkWindow  *base_application_get_dialog( BaseApplication *application, const gchar *name );
+GtkWindow  *base_application_get_toplevel( BaseApplication *application, const gchar *name );
 GtkWidget  *base_application_get_widget( BaseApplication *application, BaseWindow *window, const gchar *name );
 GtkWidget  *base_application_search_for_widget( BaseApplication *application, GtkWindow *window, const gchar *name );
 
diff --git a/src/nact/base-assistant.c b/src/nact/base-assistant.c
new file mode 100644
index 0000000..3ed7663
--- /dev/null
+++ b/src/nact/base-assistant.c
@@ -0,0 +1,617 @@
+/*
+ * 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 <gdk/gdkkeysyms.h>
+#include <glib.h>
+#include <glib/gi18n.h>
+
+#include "base-application.h"
+#include "base-assistant.h"
+
+/* private class data
+ */
+struct BaseAssistantClassPrivate {
+	void *empty;						/* so that gcc -pedantic is happy */
+};
+
+/* private instance data
+ */
+struct BaseAssistantPrivate {
+	gboolean dispose_has_run;
+	gboolean cancel_on_escape;
+	gboolean warn_on_escape;
+	gboolean warn_on_cancel;
+	gboolean apply_has_run;
+	gboolean escape_key_pressed;
+};
+
+/* instance properties
+ */
+enum {
+	BASE_ASSISTANT_PROP_CANCEL_ON_ESCAPE_ID = 1,
+	BASE_ASSISTANT_PROP_WARN_ON_ESCAPE_ID,
+	BASE_ASSISTANT_PROP_WARN_ON_CANCEL_ID
+};
+
+static BaseWindowClass *st_parent_class = NULL;
+
+static GType      register_type( void );
+static void       class_init( BaseAssistantClass *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 *application );
+static void       instance_finalize( GObject *application );
+
+static GtkWindow *base_get_window( BaseWindow *window, const gchar *name );
+
+static void       v_assistant_apply( GtkAssistant *assistant, BaseAssistant *window );
+static void       v_assistant_cancel( GtkAssistant *assistant, BaseAssistant *window );
+static void       v_assistant_close( GtkAssistant *assistant, BaseAssistant *window );
+static void       v_assistant_prepare( GtkAssistant *assistant, GtkWidget *page, BaseAssistant *window );
+
+static void       on_apply_message( GtkAssistant *assistant, BaseAssistant *window );
+static void       on_cancel_message( GtkAssistant *assistant, BaseAssistant *window );
+static void       on_close_message( GtkAssistant *assistant, BaseAssistant *window );
+static void       on_prepare_message( GtkAssistant *assistant, GtkWidget *page, BaseAssistant *window );
+
+static void       on_initial_load( BaseAssistant *window, gpointer user_data );
+static void       on_runtime_init( BaseAssistant *window, gpointer user_data );
+static gboolean   on_key_pressed_event( GtkWidget *widget, GdkEventKey *event, BaseAssistant *assistant );
+static void       assistant_do_apply( BaseAssistant *window, GtkAssistant *assistant );
+static void       assistant_do_cancel( BaseAssistant *window, GtkAssistant *assistant );
+static void       assistant_do_close( BaseAssistant *window, GtkAssistant *assistant );
+static void       assistant_do_prepare( BaseAssistant *window, GtkAssistant *assistant, GtkWidget *page );
+
+GType
+base_assistant_get_type( void )
+{
+	static GType window_type = 0;
+
+	if( !window_type ){
+		window_type = register_type();
+	}
+
+	return( window_type );
+}
+
+static GType
+register_type( void )
+{
+	static const gchar *thisfn = "base_assistant_register_type";
+	GType type;
+
+	static GTypeInfo info = {
+		sizeof( BaseAssistantClass ),
+		( GBaseInitFunc ) NULL,
+		( GBaseFinalizeFunc ) NULL,
+		( GClassInitFunc ) class_init,
+		NULL,
+		NULL,
+		sizeof( BaseAssistant ),
+		0,
+		( GInstanceInitFunc ) instance_init
+	};
+
+	g_debug( "%s", thisfn );
+
+	type = g_type_register_static( BASE_WINDOW_TYPE, "BaseAssistant", &info, 0 );
+
+	return( type );
+}
+
+static void
+class_init( BaseAssistantClass *klass )
+{
+	static const gchar *thisfn = "base_assistant_class_init";
+	GObjectClass *object_class;
+	GParamSpec *spec;
+	BaseWindowClass *base_class;
+
+	g_debug( "%s: klass=%p", thisfn, ( void * ) klass );
+
+	st_parent_class = g_type_class_peek_parent( klass );
+
+	object_class = G_OBJECT_CLASS( klass );
+	object_class->dispose = instance_dispose;
+	object_class->finalize = instance_finalize;
+	object_class->get_property = instance_get_property;
+	object_class->set_property = instance_set_property;
+
+	spec = g_param_spec_boolean(
+			BASE_ASSISTANT_PROP_CANCEL_ON_ESCAPE,
+			"Cancel on Escape",
+			"Does the assistant should 'Cancel' when the user hits Escape ?", FALSE,
+			G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE );
+	g_object_class_install_property( object_class, BASE_ASSISTANT_PROP_CANCEL_ON_ESCAPE_ID, spec );
+
+	spec = g_param_spec_boolean(
+			BASE_ASSISTANT_PROP_WARN_ON_ESCAPE,
+			"Warn on Escape",
+			"Does the user should confirm when exiting the assistant via Escape ?", FALSE,
+			G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE );
+	g_object_class_install_property( object_class, BASE_ASSISTANT_PROP_WARN_ON_ESCAPE_ID, spec );
+
+	spec = g_param_spec_boolean(
+			BASE_ASSISTANT_PROP_WARN_ON_CANCEL,
+			"Warn on cancel",
+			"Does the user should confirm when exiting the assistant via Cancel ?", FALSE,
+			G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE );
+	g_object_class_install_property( object_class, BASE_ASSISTANT_PROP_WARN_ON_CANCEL_ID, spec );
+
+	klass->private = g_new0( BaseAssistantClassPrivate, 1 );
+
+	base_class = BASE_WINDOW_CLASS( klass );
+	base_class->get_window = base_get_window;
+
+	klass->apply = assistant_do_apply;
+	klass->cancel = assistant_do_cancel;
+	klass->close = assistant_do_close;
+	klass->prepare = assistant_do_prepare;
+}
+
+static void
+instance_init( GTypeInstance *instance, gpointer klass )
+{
+	static const gchar *thisfn = "base_assistant_instance_init";
+	BaseAssistant *self;
+
+	g_debug( "%s: instance=%p, klass=%p", thisfn, ( void * ) instance, ( void * ) klass );
+
+	g_assert( BASE_IS_ASSISTANT( instance ));
+	self = BASE_ASSISTANT( instance );
+
+	self->private = g_new0( BaseAssistantPrivate, 1 );
+
+	self->private->dispose_has_run = FALSE;
+	self->private->cancel_on_escape = FALSE;
+	self->private->warn_on_escape = FALSE;
+	self->private->warn_on_cancel = FALSE;
+	self->private->apply_has_run = FALSE;
+	self->private->escape_key_pressed = FALSE;
+
+	base_window_signal_connect(
+			BASE_WINDOW( instance ),
+			G_OBJECT( instance ),
+			BASE_WINDOW_SIGNAL_INITIAL_LOAD,
+			G_CALLBACK( on_initial_load ));
+
+	base_window_signal_connect(
+			BASE_WINDOW( instance ),
+			G_OBJECT( instance ),
+			BASE_WINDOW_SIGNAL_RUNTIME_INIT,
+			G_CALLBACK( on_runtime_init ));
+}
+
+static void
+instance_get_property( GObject *object, guint property_id, GValue *value, GParamSpec *spec )
+{
+	BaseAssistant *self;
+
+	g_assert( BASE_IS_ASSISTANT( object ));
+	self = BASE_ASSISTANT( object );
+
+	switch( property_id ){
+		case BASE_ASSISTANT_PROP_CANCEL_ON_ESCAPE_ID:
+			g_value_set_boolean( value, self->private->cancel_on_escape );
+			break;
+
+		case BASE_ASSISTANT_PROP_WARN_ON_ESCAPE_ID:
+			g_value_set_boolean( value, self->private->warn_on_escape );
+			break;
+
+		case BASE_ASSISTANT_PROP_WARN_ON_CANCEL_ID:
+			g_value_set_boolean( value, self->private->warn_on_cancel );
+			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 )
+{
+	BaseAssistant *self;
+
+	g_assert( BASE_IS_ASSISTANT( object ));
+	self = BASE_ASSISTANT( object );
+
+	switch( property_id ){
+		case BASE_ASSISTANT_PROP_CANCEL_ON_ESCAPE_ID:
+			self->private->cancel_on_escape = g_value_get_boolean( value );
+			break;
+
+		case BASE_ASSISTANT_PROP_WARN_ON_ESCAPE_ID:
+			self->private->warn_on_escape = g_value_get_boolean( value );
+			break;
+
+		case BASE_ASSISTANT_PROP_WARN_ON_CANCEL_ID:
+			self->private->warn_on_cancel = g_value_get_boolean( value );
+			break;
+
+		default:
+			G_OBJECT_WARN_INVALID_PROPERTY_ID( object, property_id, spec );
+			break;
+	}
+}
+
+static void
+instance_dispose( GObject *window )
+{
+	static const gchar *thisfn = "base_assistant_instance_dispose";
+	BaseAssistant *self;
+
+	g_debug( "%s: window=%p", thisfn, ( void * ) window );
+	g_assert( BASE_IS_ASSISTANT( window ));
+	self = BASE_ASSISTANT( window );
+
+	if( !self->private->dispose_has_run ){
+
+		self->private->dispose_has_run = TRUE;
+
+		/* chain up to the parent class */
+		if( G_OBJECT_CLASS( st_parent_class )->dispose ){
+			G_OBJECT_CLASS( st_parent_class )->dispose( window );
+		}
+	}
+}
+
+static void
+instance_finalize( GObject *window )
+{
+	static const gchar *thisfn = "base_assistant_instance_finalize";
+	BaseAssistant *self;
+
+	g_debug( "%s: window=%p", thisfn, ( void * ) window );
+	g_assert( BASE_IS_ASSISTANT( window ));
+	self = ( BaseAssistant * ) window;
+
+	g_free( self->private );
+
+	/* chain call to parent class */
+	if( G_OBJECT_CLASS( st_parent_class )->finalize ){
+		G_OBJECT_CLASS( st_parent_class )->finalize( window );
+	}
+}
+
+/*
+ * cf. http://bugzilla.gnome.org/show_bug.cgi?id=589746 against Gtk+ 2.16
+ * a GtkFileChooserWidget embedded in a GtkAssistant is not displayed
+ * when run more than once
+ *
+ * as a work-around, reload the XML ui each time we run an assistant !
+ */
+static GtkWindow *
+base_get_window( BaseWindow *window, const gchar *name )
+{
+	GtkBuilder *builder;
+	BaseApplication *appli;
+	gchar *fname;
+	GtkWindow *dialog;
+
+	builder = gtk_builder_new();
+
+	appli = base_window_get_application( window );
+
+	fname = base_application_get_ui_filename( appli );
+
+	gtk_builder_add_from_file( builder, fname, NULL );
+
+	g_free( fname );
+
+	dialog = GTK_WINDOW( gtk_builder_get_object( builder, name ));
+
+	return( dialog );
+}
+
+/**
+ * base_assistant_set_cancel_on_esc:
+ * @window: this #BaseAssistant instance.
+ * @cancel: whether hitting 'Escape' key triggers the 'Cancel' action.
+ *
+ * Set 'cancel on escape' property.
+ */
+void
+base_assistant_set_cancel_on_esc( BaseAssistant *window, gboolean cancel )
+{
+	g_assert( BASE_IS_ASSISTANT( window ));
+
+	g_object_set( G_OBJECT( window ), BASE_ASSISTANT_PROP_CANCEL_ON_ESCAPE, cancel, NULL );
+}
+
+/**
+ * base_assistant_set_warn_on_esc:
+ * @window: this #BaseAssistant instance.
+ * @warn: whether the 'Cancel' action, when triggered by 'Escape' key,
+ * should emit a warning.
+ *
+ * Set 'warn on escape' property.
+ */
+void
+base_assistant_set_warn_on_esc( BaseAssistant *window, gboolean warn )
+{
+	g_assert( BASE_IS_ASSISTANT( window ));
+
+	g_object_set( G_OBJECT( window ), BASE_ASSISTANT_PROP_WARN_ON_ESCAPE, warn, NULL );
+}
+
+/**
+ * base_assistant_set_warn_on_cancel:
+ * @window: this #BaseAssistant instance.
+ * @warn: whether the 'Cancel' action should emit a warning.
+ *
+ * Set 'warn on close' property.
+ */
+void
+base_assistant_set_warn_on_cancel( BaseAssistant *window, gboolean warn )
+{
+	g_assert( BASE_IS_ASSISTANT( window ));
+
+	g_object_set( G_OBJECT( window ), BASE_ASSISTANT_PROP_WARN_ON_CANCEL, warn, NULL );
+}
+
+static void
+v_assistant_apply( GtkAssistant *assistant, BaseAssistant *window )
+{
+	g_assert( BASE_IS_ASSISTANT( window ));
+
+	if( BASE_ASSISTANT_GET_CLASS( window )->apply ){
+		BASE_ASSISTANT_GET_CLASS( window )->apply( window, assistant );
+
+	} else {
+		assistant_do_apply( window, assistant );
+	}
+
+	window->private->apply_has_run = TRUE;
+}
+
+static void
+v_assistant_cancel( GtkAssistant *assistant, BaseAssistant *window )
+{
+	g_assert( BASE_IS_ASSISTANT( window ));
+
+	if( BASE_ASSISTANT_GET_CLASS( window )->cancel ){
+		BASE_ASSISTANT_GET_CLASS( window )->cancel( window, assistant );
+
+	} else {
+		assistant_do_cancel( window, assistant );
+	}
+}
+
+static void
+v_assistant_close( GtkAssistant *assistant, BaseAssistant *window )
+{
+	g_assert( BASE_IS_ASSISTANT( window ));
+
+	if( BASE_ASSISTANT_GET_CLASS( window )->close ){
+		BASE_ASSISTANT_GET_CLASS( window )->close( window, assistant );
+
+	} else {
+		assistant_do_close( window, assistant );
+	}
+}
+
+static void
+v_assistant_prepare( GtkAssistant *assistant, GtkWidget *page, BaseAssistant *window )
+{
+	g_assert( BASE_IS_ASSISTANT( window ));
+
+	if( BASE_ASSISTANT_GET_CLASS( window )->prepare ){
+		BASE_ASSISTANT_GET_CLASS( window )->prepare( window, assistant, page );
+
+	} else {
+		assistant_do_prepare( window, assistant, page );
+	}
+}
+
+/*
+ * starting with Gtk+ 2.18, this work-around will become useless
+ * so message handlers could safely be the v_xxx functions
+ */
+static void
+on_apply_message( GtkAssistant *assistant, BaseAssistant *window )
+{
+	if( !window->private->apply_has_run ){
+		v_assistant_apply( assistant, window );
+	}
+}
+
+static void
+on_cancel_message( GtkAssistant *assistant, BaseAssistant *window )
+{
+	v_assistant_cancel( assistant, window );
+}
+
+static void
+on_close_message( GtkAssistant *assistant, BaseAssistant *window )
+{
+	v_assistant_close( assistant, window );
+}
+
+static void
+on_prepare_message( GtkAssistant *assistant, GtkWidget *page, BaseAssistant *window )
+{
+	static const gchar *thisfn = "base_assistant_on_prepare_message";
+	GtkAssistantPageType type;
+
+	g_debug( "%s: assistant=%p, page=%p, window=%p",
+			thisfn, ( void * ) assistant, ( void * ) page, ( void * ) window );
+
+	type = gtk_assistant_get_page_type( assistant, page );
+
+	switch( type ){
+		case GTK_ASSISTANT_PAGE_SUMMARY:
+			if( !window->private->apply_has_run ){
+				v_assistant_apply( assistant, window );
+			}
+			break;
+
+		default:
+			break;
+	}
+
+	v_assistant_prepare( assistant, page, window );
+}
+
+static void
+on_initial_load( BaseAssistant *window, gpointer user_data )
+{
+	static const gchar *thisfn = "base_assistant_on_initial_load";
+
+	g_debug( "%s: window=%p, user_data=%p", thisfn, ( void * ) window, ( void * ) user_data );
+	g_assert( BASE_IS_ASSISTANT( window ));
+
+	base_assistant_set_cancel_on_esc( window, FALSE );
+	base_assistant_set_warn_on_esc( window, FALSE );
+	base_assistant_set_warn_on_cancel( window, FALSE );
+}
+
+static void
+on_runtime_init( BaseAssistant *window, gpointer user_data )
+{
+	static const gchar *thisfn = "base_assistant_on_runtime_init";
+	GtkWindow *toplevel;
+
+	g_debug( "%s: window=%p, user_data=%p", thisfn, ( void * ) window, ( void * ) user_data );
+	g_assert( BASE_IS_ASSISTANT( window ));
+
+	toplevel = base_window_get_toplevel_window( BASE_WINDOW( window ));
+	g_assert( GTK_IS_ASSISTANT( toplevel ));
+
+	base_window_signal_connect(
+			BASE_WINDOW( window ),
+			G_OBJECT( toplevel ),
+			"key-press-event",
+			G_CALLBACK( on_key_pressed_event ));
+
+	base_window_signal_connect(
+			BASE_WINDOW( window ),
+			G_OBJECT( toplevel ),
+			"apply",
+			G_CALLBACK( on_apply_message ));
+
+	base_window_signal_connect(
+			BASE_WINDOW( window ),
+			G_OBJECT( toplevel ),
+			"cancel",
+			G_CALLBACK( on_cancel_message ));
+
+	base_window_signal_connect(
+			BASE_WINDOW( window ),
+			G_OBJECT( toplevel ),
+			"close",
+			G_CALLBACK( on_close_message ));
+
+	base_window_signal_connect(
+			BASE_WINDOW( window ),
+			G_OBJECT( toplevel ),
+			"prepare",
+			G_CALLBACK( on_prepare_message ));
+}
+
+static gboolean
+on_key_pressed_event( GtkWidget *widget, GdkEventKey *event, BaseAssistant *assistant )
+{
+	/*static const gchar *thisfn = "base_assistant_on_key_pressed_event";
+	g_debug( "%s: widget=%p, event=%p, user_data=%p", thisfn, widget, event, user_data );*/
+	gboolean stop = FALSE;
+	GtkWindow *toplevel;
+
+	if( event->keyval == GDK_Escape &&
+		assistant->private->cancel_on_escape ){
+
+			assistant->private->escape_key_pressed = TRUE;
+			toplevel = base_window_get_toplevel_window( BASE_WINDOW( assistant ));
+			g_signal_emit_by_name( toplevel, "cancel", toplevel );
+			stop = TRUE;
+	}
+
+	return( stop );
+}
+
+static void
+assistant_do_apply( BaseAssistant *window, GtkAssistant *assistant )
+{
+	static const gchar *thisfn = "base_assistant_assistant_do_apply";
+
+	g_debug( "%s: window=%p, assistant=%p", thisfn, ( void * ) window, ( void * ) assistant );
+}
+
+/*
+ * the 'Cancel' button is clicked
+ */
+static void
+assistant_do_cancel( BaseAssistant *window, GtkAssistant *assistant )
+{
+	static const gchar *thisfn = "base_assistant_assistant_do_cancel";
+	gboolean ok = TRUE;
+	gchar *first;
+
+	g_debug( "%s: window=%p, assistant=%p", thisfn, ( void * ) window, ( void * ) assistant );
+
+	if( window->private->warn_on_cancel ||
+		( window->private->warn_on_escape && window->private->escape_key_pressed )){
+
+			first = g_strdup( _( "Are you sure you want to quit this assistant ?" ));
+			ok = base_window_yesno_dlg( BASE_WINDOW( window ), GTK_MESSAGE_QUESTION, first, NULL );
+			g_free( first );
+	}
+
+	window->private->escape_key_pressed = FALSE;
+
+	if( ok ){
+		assistant_do_close( window, assistant );
+	}
+}
+
+static void
+assistant_do_close( BaseAssistant *window, GtkAssistant *assistant )
+{
+	static const gchar *thisfn = "base_assistant_assistant_do_close";
+
+	g_debug( "%s: window=%p, assistant=%p", thisfn, ( void * ) window, ( void * ) assistant );
+
+	g_object_unref( window );
+}
+
+static void
+assistant_do_prepare( BaseAssistant *window, GtkAssistant *assistant, GtkWidget *page )
+{
+	static const gchar *thisfn = "base_assistant_assistant_do_prepare";
+
+	g_debug( "%s: window=%p, assistant=%p, page=%p",
+			thisfn, ( void * ) window, ( void * ) assistant, ( void * ) page );
+}
diff --git a/src/nact/base-assistant.h b/src/nact/base-assistant.h
new file mode 100644
index 0000000..818d1fd
--- /dev/null
+++ b/src/nact/base-assistant.h
@@ -0,0 +1,139 @@
+/*
+ * 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 __BASE_ASSISTANT_H__
+#define __BASE_ASSISTANT_H__
+
+/**
+ * SECTION: base_assistant
+ * @short_description: #BaseAssistant class definition.
+ * @include: nact/base-assistant.h
+ *
+ * This class is derived from BaseWindow class, and serves as a base
+ * class for all Nautilus Actions assistants.
+ *
+ * Note: as a work-around to #589745 (Apply message in GtkAssistant),
+ * we may trigger "on_assistant_apply" function from the
+ * "on_prepare_message" handler.
+ * The provided patch has been applied on 2009-08-07, and released in
+ * Gtk+ 2.17.7. So, this work-around will can be safely removed when
+ * minimal Gtk+ version will be 2.18 or later.
+ */
+
+#include "base-window.h"
+
+G_BEGIN_DECLS
+
+#define BASE_ASSISTANT_TYPE					( base_assistant_get_type())
+#define BASE_ASSISTANT( object )			( G_TYPE_CHECK_INSTANCE_CAST( object, BASE_ASSISTANT_TYPE, BaseAssistant ))
+#define BASE_ASSISTANT_CLASS( klass )		( G_TYPE_CHECK_CLASS_CAST( klass, BASE_ASSISTANT_TYPE, BaseAssistantClass ))
+#define BASE_IS_ASSISTANT( object )			( G_TYPE_CHECK_INSTANCE_TYPE( object, BASE_ASSISTANT_TYPE ))
+#define BASE_IS_ASSISTANT_CLASS( klass )	( G_TYPE_CHECK_CLASS_TYPE(( klass ), BASE_ASSISTANT_TYPE ))
+#define BASE_ASSISTANT_GET_CLASS( object )	( G_TYPE_INSTANCE_GET_CLASS(( object ), BASE_ASSISTANT_TYPE, BaseAssistantClass ))
+
+typedef struct BaseAssistantPrivate BaseAssistantPrivate;
+
+typedef struct {
+	BaseWindow            parent;
+	BaseAssistantPrivate *private;
+}
+	BaseAssistant;
+
+typedef struct BaseAssistantClassPrivate BaseAssistantClassPrivate;
+
+typedef struct {
+	BaseWindowClass            parent;
+	BaseAssistantClassPrivate *private;
+
+	/**
+	 * apply:
+	 * @window: this #BaseAssistance instance.
+	 */
+	void ( *apply )  ( BaseAssistant *window, GtkAssistant *assistant );
+
+	/**
+	 * cancel:
+	 * @window: this #BaseAssistance instance.
+	 */
+	void ( *cancel ) ( BaseAssistant *window, GtkAssistant *assistant );
+
+	/**
+	 * close:
+	 * @window: this #BaseAssistance instance.
+	 */
+	void ( *close )  ( BaseAssistant *window, GtkAssistant *assistant );
+
+	/**
+	 * prepare:
+	 * @window: this #BaseAssistance instance.
+	 */
+	void ( *prepare )( BaseAssistant *window, GtkAssistant *assistant, GtkWidget *page );
+}
+	BaseAssistantClass;
+
+/**
+ * %BASE_ASSISTANT_PROP_CANCEL_ON_ESCAPE:
+ *
+ * Does the assistant cancel its execution when the user hits the
+ * 'Escape' key ?
+ *
+ * Defaults to %FALSE.
+ */
+#define BASE_ASSISTANT_PROP_CANCEL_ON_ESCAPE	"base-assistant-cancel-on-escape"
+
+/**
+ * %BASE_ASSISTANT_PROP_WARN_ON_ESCAPE:
+ *
+ * Does the user be warned when he/she quits the assistant by hitting
+ * the 'Escape' key ? This is only used when previous property
+ * %BASE_ASSISTANT_PROP_CANCEL_ON_ESCAPE is set to %TRUE.
+ *
+ * Defaults to %FALSE.
+ */
+#define BASE_ASSISTANT_PROP_WARN_ON_ESCAPE		"base-assistant-warn-on-escape"
+
+/**
+ * %BASE_ASSISTANT_PROP_WARN_ON_CANCEL:
+ *
+ * Does the user be warned when he/she cancels the assistant ?
+ *
+ * Defaults to %FALSE.
+ */
+#define BASE_ASSISTANT_PROP_WARN_ON_CANCEL		"base-assistant-warn-on-cancel"
+
+GType base_assistant_get_type( void );
+
+void  base_assistant_set_cancel_on_esc( BaseAssistant *window, gboolean cancel );
+void  base_assistant_set_warn_on_esc( BaseAssistant *window, gboolean warn_esc );
+void  base_assistant_set_warn_on_cancel( BaseAssistant *window, gboolean warn_cancel );
+
+G_END_DECLS
+
+#endif /* __BASE_ASSISTANT_H__ */
diff --git a/src/nact/base-dialog.c b/src/nact/base-dialog.c
new file mode 100644
index 0000000..66c6e31
--- /dev/null
+++ b/src/nact/base-dialog.c
@@ -0,0 +1,164 @@
+/*
+ * 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 "base-dialog.h"
+
+/* private class data
+ */
+struct BaseDialogClassPrivate {
+	void *empty;						/* so that gcc -pedantic is happy */
+};
+
+/* private instance data
+ */
+struct BaseDialogPrivate {
+	gboolean dispose_has_run;
+};
+
+static BaseWindowClass *st_parent_class = NULL;
+
+static GType      register_type( void );
+static void       class_init( BaseDialogClass *klass );
+static void       instance_init( GTypeInstance *instance, gpointer klass );
+static void       instance_dispose( GObject *application );
+static void       instance_finalize( GObject *application );
+
+GType
+base_dialog_get_type( void )
+{
+	static GType dialog_type = 0;
+
+	if( !dialog_type ){
+		dialog_type = register_type();
+	}
+
+	return( dialog_type );
+}
+
+static GType
+register_type( void )
+{
+	static const gchar *thisfn = "base_dialog_register_type";
+	GType type;
+
+	static GTypeInfo info = {
+		sizeof( BaseDialogClass ),
+		( GBaseInitFunc ) NULL,
+		( GBaseFinalizeFunc ) NULL,
+		( GClassInitFunc ) class_init,
+		NULL,
+		NULL,
+		sizeof( BaseDialog ),
+		0,
+		( GInstanceInitFunc ) instance_init
+	};
+
+	g_debug( "%s", thisfn );
+
+	type = g_type_register_static( BASE_WINDOW_TYPE, "BaseDialog", &info, 0 );
+
+	return( type );
+}
+
+static void
+class_init( BaseDialogClass *klass )
+{
+	static const gchar *thisfn = "base_dialog_class_init";
+	GObjectClass *object_class;
+
+	g_debug( "%s: klass=%p", thisfn, ( void * ) klass );
+
+	st_parent_class = g_type_class_peek_parent( klass );
+
+	object_class = G_OBJECT_CLASS( klass );
+	object_class->dispose = instance_dispose;
+	object_class->finalize = instance_finalize;
+
+	klass->private = g_new0( BaseDialogClassPrivate, 1 );
+}
+
+static void
+instance_init( GTypeInstance *instance, gpointer klass )
+{
+	static const gchar *thisfn = "base_dialog_instance_init";
+	BaseDialog *self;
+
+	g_debug( "%s: instance=%p, klass=%p", thisfn, ( void * ) instance, ( void * ) klass );
+
+	g_assert( BASE_IS_DIALOG( instance ));
+	self = BASE_DIALOG( instance );
+
+	self->private = g_new0( BaseDialogPrivate, 1 );
+
+	self->private->dispose_has_run = FALSE;
+}
+
+static void
+instance_dispose( GObject *window )
+{
+	static const gchar *thisfn = "base_dialog_instance_dispose";
+	BaseDialog *self;
+
+	g_debug( "%s: window=%p", thisfn, ( void * ) window );
+	g_assert( BASE_IS_DIALOG( window ));
+	self = BASE_DIALOG( window );
+
+	if( !self->private->dispose_has_run ){
+
+		self->private->dispose_has_run = TRUE;
+
+		/* chain up to the parent class */
+		if( G_OBJECT_CLASS( st_parent_class )->dispose ){
+			G_OBJECT_CLASS( st_parent_class )->dispose( window );
+		}
+	}
+}
+
+static void
+instance_finalize( GObject *window )
+{
+	static const gchar *thisfn = "base_dialog_instance_finalize";
+	BaseDialog *self;
+
+	g_debug( "%s: window=%p", thisfn, ( void * ) window );
+	g_assert( BASE_IS_DIALOG( window ));
+	self = ( BaseDialog * ) window;
+
+	g_free( self->private );
+
+	/* chain call to parent class */
+	if( G_OBJECT_CLASS( st_parent_class )->finalize ){
+		G_OBJECT_CLASS( st_parent_class )->finalize( window );
+	}
+}
diff --git a/src/common/na-gconf.h b/src/nact/base-dialog.h
similarity index 51%
copy from src/common/na-gconf.h
copy to src/nact/base-dialog.h
index 0a96487..be843cc 100644
--- a/src/common/na-gconf.h
+++ b/src/nact/base-dialog.h
@@ -28,49 +28,47 @@
  *   ... and many others (see AUTHORS)
  */
 
-#ifndef __NA_GCONF_H__
-#define __NA_GCONF_H__
+#ifndef __BASE_DIALOG_H__
+#define __BASE_DIALOG_H__
 
 /**
- * SECTION: na_gconf
- * @short_description: #NAGConf class definition.
- * @include: common/na-gconf.h
+ * SECTION: base_dialog
+ * @short_description: #BaseDialog class definition.
+ * @include: base/base-dialog.h
  *
- * This class manages the GConf I/O storage subsystem.
- * It should only be used through the NAIIOProvider interface.
+ * This class is derived from BaseWindow class, and serves as a base
+ * class for all Nautilus Actions dialogs.
  */
 
-#include <glib-object.h>
+#include "base-window.h"
 
 G_BEGIN_DECLS
 
-#define NA_GCONF_TYPE					( na_gconf_get_type())
-#define NA_GCONF( object )				( G_TYPE_CHECK_INSTANCE_CAST( object, NA_GCONF_TYPE, NAGConf ))
-#define NA_GCONF_CLASS( klass )			( G_TYPE_CHECK_CLASS_CAST( klass, NA_GCONF_TYPE, NAGConfClass ))
-#define NA_IS_GCONF( object )			( G_TYPE_CHECK_INSTANCE_TYPE( object, NA_GCONF_TYPE ))
-#define NA_IS_GCONF_CLASS( klass )		( G_TYPE_CHECK_CLASS_TYPE(( klass ), NA_GCONF_TYPE ))
-#define NA_GCONF_GET_CLASS( object )	( G_TYPE_INSTANCE_GET_CLASS(( object ), NA_GCONF_TYPE, NAGConfClass ))
+#define BASE_DIALOG_TYPE				( base_dialog_get_type())
+#define BASE_DIALOG( object )			( G_TYPE_CHECK_INSTANCE_CAST( object, BASE_DIALOG_TYPE, BaseDialog ))
+#define BASE_DIALOG_CLASS( klass )		( G_TYPE_CHECK_CLASS_CAST( klass, BASE_DIALOG_TYPE, BaseDialogClass ))
+#define BASE_IS_DIALOG( object )		( G_TYPE_CHECK_INSTANCE_TYPE( object, BASE_DIALOG_TYPE ))
+#define BASE_IS_DIALOG_CLASS( klass )	( G_TYPE_CHECK_CLASS_TYPE(( klass ), BASE_DIALOG_TYPE ))
+#define BASE_DIALOG_GET_CLASS( object )	( G_TYPE_INSTANCE_GET_CLASS(( object ), BASE_DIALOG_TYPE, BaseDialogClass ))
 
-typedef struct NAGConfPrivate NAGConfPrivate;
+typedef struct BaseDialogPrivate BaseDialogPrivate;
 
 typedef struct {
-	GObject         parent;
-	NAGConfPrivate *private;
+	BaseWindow         parent;
+	BaseDialogPrivate *private;
 }
-	NAGConf;
+	BaseDialog;
 
-typedef struct NAGConfClassPrivate NAGConfClassPrivate;
+typedef struct BaseDialogClassPrivate BaseDialogClassPrivate;
 
 typedef struct {
-	GObjectClass         parent;
-	NAGConfClassPrivate *private;
+	BaseWindowClass         parent;
+	BaseDialogClassPrivate *private;
 }
-	NAGConfClass;
+	BaseDialogClass;
 
-GType    na_gconf_get_type( void );
-
-NAGConf *na_gconf_new( const GObject *notified );
+GType base_dialog_get_type( void );
 
 G_END_DECLS
 
-#endif /* __NA_GCONF_H__ */
+#endif /* __BASE_DIALOG_H__ */
diff --git a/src/nact/nact-iprefs.c b/src/nact/base-iprefs.c
similarity index 51%
rename from src/nact/nact-iprefs.c
rename to src/nact/base-iprefs.c
index a4043a0..8835284 100644
--- a/src/nact/nact-iprefs.c
+++ b/src/nact/base-iprefs.c
@@ -33,43 +33,39 @@
 #include <config.h>
 #endif
 
-#include <gconf/gconf.h>
-#include <gconf/gconf-client.h>
-
+#include <common/na-gconf-utils.h>
 #include <common/na-iprefs.h>
 
-#include "nact-iprefs.h"
+#include "base-iprefs.h"
 
 /* private interface data
  */
-struct NactIPrefsInterfacePrivate {
+struct BaseIPrefsInterfacePrivate {
 	GConfClient *client;
 };
 
-/* key to read/write the last visited folder when browsing for a file
- */
-#define IPREFS_ICONDITION_FOLDER_URI			"iconditions-folder-uri"
-#define IPREFS_IMPORT_ACTIONS_FOLDER_URI		"import-folder-uri"
-#define IPREFS_EXPORT_ACTIONS_FOLDER_URI		"export-folder-uri"
-
 static GType    register_type( void );
-static void     interface_base_init( NactIPrefsInterface *klass );
-static void     interface_base_finalize( NactIPrefsInterface *klass );
+static void     interface_base_init( BaseIPrefsInterface *klass );
+static void     interface_base_finalize( BaseIPrefsInterface *klass );
 
-static gchar   *v_get_iprefs_window_id( NactWindow *window );
+static gchar   *v_iprefs_get_window_id( BaseWindow *window );
 
-static GSList  *read_key_listint( NactWindow *window, const gchar *key );
-static void     write_key_listint( NactWindow *window, const gchar *key, GSList *list );
-static void     listint_to_position( NactWindow *window, GSList *list, gint *x, gint *y, gint *width, gint *height );
-static GSList  *position_to_listint( NactWindow *window, gint x, gint y, gint width, gint height );
-static void     free_listint( GSList *list );
-static gchar   *read_key_str( NactWindow *window, const gchar *key );
-static void     save_key_str( NactWindow *window, const gchar *key, const gchar *text );
-static gint     read_key_int( NactWindow *window, const gchar *name );
-static void     write_key_int( NactWindow *window, const gchar *name, gint value );
+static gboolean read_bool( BaseWindow *window, const gchar *name );
+static gint     read_int( BaseWindow *window, const gchar *name );
+static GSList  *read_int_list( BaseWindow *window, const gchar *key );
+static gchar   *read_str( BaseWindow *window, const gchar *key );
+
+static void     write_bool( BaseWindow *window, const gchar *name, gboolean value );
+static void     write_int( BaseWindow *window, const gchar *name, gint value );
+static void     write_int_list( BaseWindow *window, const gchar *key, GSList *list );
+static void     write_str( BaseWindow *window, const gchar *key, const gchar *text );
+
+static void     int_list_to_position( BaseWindow *window, GSList *list, gint *x, gint *y, gint *width, gint *height );
+static GSList  *position_to_int_list( BaseWindow *window, gint x, gint y, gint width, gint height );
+static void     free_int_list( GSList *list );
 
 GType
-nact_iprefs_get_type( void )
+base_iprefs_get_type( void )
 {
 	static GType iface_type = 0;
 
@@ -83,11 +79,11 @@ nact_iprefs_get_type( void )
 static GType
 register_type( void )
 {
-	static const gchar *thisfn = "nact_iprefs_register_type";
+	static const gchar *thisfn = "base_iprefs_register_type";
 	GType type;
 
 	static const GTypeInfo info = {
-		sizeof( NactIPrefsInterface ),
+		sizeof( BaseIPrefsInterface ),
 		( GBaseInitFunc ) interface_base_init,
 		( GBaseFinalizeFunc ) interface_base_finalize,
 		NULL,
@@ -100,7 +96,7 @@ register_type( void )
 
 	g_debug( "%s", thisfn );
 
-	type = g_type_register_static( G_TYPE_INTERFACE, "NactIPrefs", &info, 0 );
+	type = g_type_register_static( G_TYPE_INTERFACE, "BaseIPrefs", &info, 0 );
 
 	g_type_interface_add_prerequisite( type, G_TYPE_OBJECT );
 
@@ -108,28 +104,28 @@ register_type( void )
 }
 
 static void
-interface_base_init( NactIPrefsInterface *klass )
+interface_base_init( BaseIPrefsInterface *klass )
 {
-	static const gchar *thisfn = "nact_iprefs_interface_base_init";
+	static const gchar *thisfn = "base_iprefs_interface_base_init";
 	static gboolean initialized = FALSE;
 
 	if( !initialized ){
 		g_debug( "%s: klass=%p", thisfn, ( void * ) klass );
 
-		klass->private = g_new0( NactIPrefsInterfacePrivate, 1 );
+		klass->private = g_new0( BaseIPrefsInterfacePrivate, 1 );
 
 		klass->private->client = gconf_client_get_default();
 
-		klass->get_iprefs_window_id = NULL;
+		klass->iprefs_get_window_id = NULL;
 
 		initialized = TRUE;
 	}
 }
 
 static void
-interface_base_finalize( NactIPrefsInterface *klass )
+interface_base_finalize( BaseIPrefsInterface *klass )
 {
-	static const gchar *thisfn = "nact_iprefs_interface_base_finalize";
+	static const gchar *thisfn = "base_iprefs_interface_base_finalize";
 	static gboolean finalized = FALSE ;
 
 	if( !finalized ){
@@ -142,45 +138,46 @@ interface_base_finalize( NactIPrefsInterface *klass )
 }
 
 /**
- * Position the specified window on the screen.
+ * base_iprefs_position_window:
+ * @window: this #BaseWindow-derived window.
  *
- * @window: this NactWindow-derived window.
+ * Position the specified window on the screen.
  *
  * A window position is stored as a list of integers "x,y,width,height".
  */
 void
-nact_iprefs_position_window( NactWindow *window )
+base_iprefs_position_window( BaseWindow *window )
 {
 	GtkWindow *toplevel;
-	gchar *key = v_get_iprefs_window_id( window );
+	gchar *key = v_iprefs_get_window_id( window );
 
 	if( key ){
-		toplevel = base_window_get_toplevel_dialog( BASE_WINDOW( window ));
-		nact_iprefs_position_named_window( window, toplevel, key );
+		toplevel = base_window_get_toplevel_window( BASE_WINDOW( window ));
+		base_iprefs_position_named_window( window, toplevel, key );
 		g_free( key );
 	}
 }
 
 /**
- * Position the specified window on the screen.
- *
- * @window: this NactWindow-derived window.
- *
+ * base_iprefs_position_named_window:
+ * @window: this #BaseWindow-derived window.
  * @name: the name of the window
+ *
+ * Position the specified window on the screen.
  */
 void
-nact_iprefs_position_named_window( NactWindow *window, GtkWindow *toplevel, const gchar *key )
+base_iprefs_position_named_window( BaseWindow *window, GtkWindow *toplevel, const gchar *key )
 {
-	static const gchar *thisfn = "nact_iprefs_position_named_window";
+	static const gchar *thisfn = "base_iprefs_position_named_window";
 	GSList *list;
 	gint x=0, y=0, width=0, height=0;
 
-	list = read_key_listint( window, key );
+	list = read_int_list( window, key );
 	if( list ){
 
-		listint_to_position( window, list, &x, &y, &width, &height );
+		int_list_to_position( window, list, &x, &y, &width, &height );
 		g_debug( "%s: key=%s, x=%d, y=%d, width=%d, height=%d", thisfn, key, x, y, width, height );
-		free_listint( list );
+		free_int_list( list );
 
 		gtk_window_move( toplevel, x, y );
 		gtk_window_resize( toplevel, width, height );
@@ -190,19 +187,19 @@ nact_iprefs_position_named_window( NactWindow *window, GtkWindow *toplevel, cons
 /**
  * Save the position of the specified window.
  *
- * @window: this NactWindow-derived window.
+ * @window: this BaseWindow-derived window.
  *
  * @code: the IPrefs identifiant of the window
  */
 void
-nact_iprefs_save_window_position( NactWindow *window )
+base_iprefs_save_window_position( BaseWindow *window )
 {
 	GtkWindow *toplevel;
-	gchar *key = v_get_iprefs_window_id( window );
+	gchar *key = v_iprefs_get_window_id( window );
 
 	if( key ){
-		toplevel = base_window_get_toplevel_dialog( BASE_WINDOW( window ));
-		nact_iprefs_save_named_window_position( window, toplevel, key );
+		toplevel = base_window_get_toplevel_window( BASE_WINDOW( window ));
+		base_iprefs_save_named_window_position( window, toplevel, key );
 		g_free( key );
 	}
 }
@@ -210,14 +207,14 @@ nact_iprefs_save_window_position( NactWindow *window )
 /**
  * Save the position of the specified window.
  *
- * @window: this NactWindow-derived window.
+ * @window: this BaseWindow-derived window.
  *
  * @key: the name of the window
  */
 void
-nact_iprefs_save_named_window_position( NactWindow *window, GtkWindow *toplevel, const gchar *key )
+base_iprefs_save_named_window_position( BaseWindow *window, GtkWindow *toplevel, const gchar *key )
 {
-	static const gchar *thisfn = "nact_iprefs_save_named_window_position";
+	static const gchar *thisfn = "base_iprefs_save_named_window_position";
 	gint x, y, width, height;
 	GSList *list;
 
@@ -226,109 +223,128 @@ nact_iprefs_save_named_window_position( NactWindow *window, GtkWindow *toplevel,
 		gtk_window_get_size( toplevel, &width, &height );
 		g_debug( "%s: key=%s, x=%d, y=%d, width=%d, height=%d", thisfn, key, x, y, width, height );
 
-		list = position_to_listint( window, x, y, width, height );
-		write_key_listint( window, key, list );
-		free_listint( list );
+		list = position_to_int_list( window, x, y, width, height );
+		write_int_list( window, key, list );
+		free_int_list( list );
 	}
 }
 
 /**
- * Save the last visited folder when browsing for command in
- * IConditions interface.
+ * Get/set a named boolean.
  *
- * @window: this NactWindow-derived window.
- *
- * Returns the last visited folder if any, or NULL.
- * The returned string must be g_free by the caller.
+ * @window: this BaseWindow-derived window.
  */
-gchar *
-nact_iprefs_get_iconditions_folder_uri( NactWindow *window )
+gboolean
+base_iprefs_get_bool( BaseWindow *window, const gchar *name )
 {
-	return( read_key_str( window, IPREFS_ICONDITION_FOLDER_URI ));
+	return( read_bool( window, name ));
 }
 
 void
-nact_iprefs_save_iconditions_folder_uri( NactWindow *window, const gchar *uri )
+base_iprefs_set_bool( BaseWindow *window, const gchar *name, gboolean value )
 {
-	save_key_str( window, IPREFS_ICONDITION_FOLDER_URI, uri );
+	write_bool( window, name, value );
 }
 
 /**
- * Save the last visited folder when importing an action.
- *
- * @window: this NactWindow-derived window.
+ * Get/set a named integer.
  *
- * Returns the last visited folder if any, or NULL.
- * The returned string must be g_free by the caller.
+ * @window: this BaseWindow-derived window.
  */
-gchar *
-nact_iprefs_get_import_folder_uri( NactWindow *window )
+gint
+base_iprefs_get_int( BaseWindow *window, const gchar *name )
 {
-	return( read_key_str( window, IPREFS_IMPORT_ACTIONS_FOLDER_URI ));
+	return( read_int( window, name ));
 }
 
 void
-nact_iprefs_save_import_folder_uri( NactWindow *window, const gchar *uri )
+base_iprefs_set_int( BaseWindow *window, const gchar *name, gint value )
 {
-	save_key_str( window, IPREFS_IMPORT_ACTIONS_FOLDER_URI, uri );
+	write_int( window, name, value );
 }
 
 /**
- * Save the last visited folder when exporting an action.
+ * base_iprefs_get_string:
+ * @window: this #BaseWindow-derived window.
+ * @name: entry of the string value.
  *
- * @window: this NactWindow-derived window.
- *
- * Returns the last visited folder if any, or NULL.
- * The returned string must be g_free by the caller.
+ * Returns the required string if any, or NULL.
+ * The returned string must be g_free() by the caller.
  */
 gchar *
-nact_iprefs_get_export_folder_uri( NactWindow *window )
+base_iprefs_get_string( BaseWindow *window, const gchar *name )
 {
-	return( read_key_str( window, IPREFS_EXPORT_ACTIONS_FOLDER_URI ));
+	return( read_str( window, name ));
 }
 
+/**
+ * base_iprefs_set_string:
+ * @window: this #BaseWindow-derived window.
+ * @name: entry of the string value.
+ * @string: value to save.
+ *
+ * Save the required string.
+ */
 void
-nact_iprefs_save_export_folder_uri( NactWindow *window, const gchar *uri )
+base_iprefs_set_string( BaseWindow *window, const gchar *name, const gchar *string )
 {
-	save_key_str( window, IPREFS_EXPORT_ACTIONS_FOLDER_URI, uri );
+	write_str( window, name, string );
 }
 
-/**
- * Get/set a named integer.
- *
- * @window: this NactWindow-derived window.
- */
-gint
-nact_iprefs_get_int( NactWindow *window, const gchar *name )
+static gchar *
+v_iprefs_get_window_id( BaseWindow *window )
 {
-	return( read_key_int( window, name ));
+	g_assert( BASE_IS_IPREFS( window ));
+
+	if( BASE_IPREFS_GET_INTERFACE( window )->iprefs_get_window_id ){
+		return( BASE_IPREFS_GET_INTERFACE( window )->iprefs_get_window_id( window ));
+	}
+
+	return( NULL );
 }
 
-void
-nact_iprefs_set_int( NactWindow *window, const gchar *name, gint value )
+static gboolean
+read_bool( BaseWindow *window, const gchar *name )
 {
-	write_key_int( window, name, value );
+	gchar *path;
+	gint value;
+
+	path = g_strdup_printf( "%s/%s", NA_GCONF_PREFS_PATH, name );
+
+	value = na_gconf_utils_read_bool( BASE_IPREFS_GET_INTERFACE( window )->private->client, path, TRUE, FALSE );
+
+	g_free( path );
+	return( value );
 }
 
-static gchar *
-v_get_iprefs_window_id( NactWindow *window )
+static gint
+read_int( BaseWindow *window, const gchar *name )
 {
-	g_assert( NACT_IS_IPREFS( window ));
+	static const gchar *thisfn = "base_iprefs_read_key_int";
+	GError *error = NULL;
+	gchar *path;
+	gint value;
 
-	if( NACT_IPREFS_GET_INTERFACE( window )->get_iprefs_window_id ){
-		return( NACT_IPREFS_GET_INTERFACE( window )->get_iprefs_window_id( window ));
+	path = g_strdup_printf( "%s/%s", NA_GCONF_PREFS_PATH, name );
+
+	value = gconf_client_get_int( BASE_IPREFS_GET_INTERFACE( window )->private->client, path, &error );
+
+	if( error ){
+		g_warning( "%s: name=%s, %s", thisfn, name, error->message );
+		g_error_free( error );
 	}
 
-	return( NULL );
+	g_free( path );
+	return( value );
 }
 
 /*
- * returns a list of GConfValue
+ * returns a list of int
  */
 static GSList *
-read_key_listint( NactWindow *window, const gchar *key )
+read_int_list( BaseWindow *window, const gchar *key )
 {
-	static const gchar *thisfn = "nact_iprefs_read_key_listint";
+	static const gchar *thisfn = "base_iprefs_read_int_list";
 	GError *error = NULL;
 	gchar *path;
 	GSList *list;
@@ -336,10 +352,10 @@ read_key_listint( NactWindow *window, const gchar *key )
 	path = g_strdup_printf( "%s/%s", NA_GCONF_PREFS_PATH, key );
 
 	list = gconf_client_get_list(
-			NACT_IPREFS_GET_INTERFACE( window )->private->client, path, GCONF_VALUE_INT, &error );
+			BASE_IPREFS_GET_INTERFACE( window )->private->client, path, GCONF_VALUE_INT, &error );
 
 	if( error ){
-		g_warning( "%s: %s", thisfn, error->message );
+		g_warning( "%s: path=%s, error=%s", thisfn, path, error->message );
 		g_error_free( error );
 		list = NULL;
 	}
@@ -348,17 +364,70 @@ read_key_listint( NactWindow *window, const gchar *key )
 	return( list );
 }
 
+static gchar *
+read_str( BaseWindow *window, const gchar *key )
+{
+	static const gchar *thisfn = "base_iprefs_read_str";
+	GError *error = NULL;
+	gchar *path;
+	gchar *text;
+
+	path = g_strdup_printf( "%s/%s", NA_GCONF_PREFS_PATH, key );
+
+	text = gconf_client_get_string( BASE_IPREFS_GET_INTERFACE( window )->private->client, path, &error );
+
+	if( error ){
+		g_warning( "%s: key=%s, %s", thisfn, key, error->message );
+		g_error_free( error );
+		text = NULL;
+	}
+
+	g_free( path );
+	return( text );
+}
+
+static void
+write_bool( BaseWindow *window, const gchar *name, gboolean value )
+{
+	gchar *path;
+
+	path = g_strdup_printf( "%s/%s", NA_GCONF_PREFS_PATH, name );
+
+	na_gconf_utils_write_bool( BASE_IPREFS_GET_INTERFACE( window )->private->client, path, value, NULL );
+
+	g_free( path );
+}
+
+static void
+write_int( BaseWindow *window, const gchar *name, gint value )
+{
+	static const gchar *thisfn = "base_iprefs_write_int";
+	GError *error = NULL;
+	gchar *path;
+
+	path = g_strdup_printf( "%s/%s", NA_GCONF_PREFS_PATH, name );
+
+	gconf_client_set_int( BASE_IPREFS_GET_INTERFACE( window )->private->client, path, value, &error );
+
+	if( error ){
+		g_warning( "%s: name=%s, %s", thisfn, name, error->message );
+		g_error_free( error );
+	}
+
+	g_free( path );
+}
+
 static void
-write_key_listint( NactWindow *window, const gchar *key, GSList *list )
+write_int_list( BaseWindow *window, const gchar *key, GSList *list )
 {
-	static const gchar *thisfn = "nact_iprefs_write_key_listint";
+	static const gchar *thisfn = "base_iprefs_write_int_list";
 	GError *error = NULL;
 	gchar *path;
 
 	path = g_strdup_printf( "%s/%s", NA_GCONF_PREFS_PATH, key );
 
 	gconf_client_set_list(
-			NACT_IPREFS_GET_INTERFACE( window )->private->client, path, GCONF_VALUE_INT, list, &error );
+			BASE_IPREFS_GET_INTERFACE( window )->private->client, path, GCONF_VALUE_INT, list, &error );
 
 	if( error ){
 		g_warning( "%s: %s", thisfn, error->message );
@@ -369,11 +438,30 @@ write_key_listint( NactWindow *window, const gchar *key, GSList *list )
 	g_free( path );
 }
 
+static void
+write_str( BaseWindow *window, const gchar *key, const gchar *text )
+{
+	static const gchar *thisfn = "base_iprefs_write_str";
+	GError *error = NULL;
+	gchar *path;
+
+	path = g_strdup_printf( "%s/%s", NA_GCONF_PREFS_PATH, key );
+
+	gconf_client_set_string( BASE_IPREFS_GET_INTERFACE( window )->private->client, path, text, &error );
+
+	if( error ){
+		g_warning( "%s: key=%s, %s", thisfn, key, error->message );
+		g_error_free( error );
+	}
+
+	g_free( path );
+}
+
 /*
  * extract the position of the window from the list of GConfValue
  */
 static void
-listint_to_position( NactWindow *window, GSList *list, gint *x, gint *y, gint *width, gint *height )
+int_list_to_position( BaseWindow *window, GSList *list, gint *x, gint *y, gint *width, gint *height )
 {
 	GSList *il;
 	int i;
@@ -402,7 +490,7 @@ listint_to_position( NactWindow *window, GSList *list, gint *x, gint *y, gint *w
 }
 
 static GSList *
-position_to_listint( NactWindow *window, gint x, gint y, gint width, gint height )
+position_to_int_list( BaseWindow *window, gint x, gint y, gint width, gint height )
 {
 	GSList *list = NULL;
 
@@ -418,7 +506,7 @@ position_to_listint( NactWindow *window, gint x, gint y, gint width, gint height
  * free the list of int
  */
 static void
-free_listint( GSList *list )
+free_int_list( GSList *list )
 {
 	/*GSList *il;
 	for( il = list ; il ; il = il->next ){
@@ -427,84 +515,3 @@ free_listint( GSList *list )
 	}*/
 	g_slist_free( list );
 }
-
-static gchar *
-read_key_str( NactWindow *window, const gchar *key )
-{
-	static const gchar *thisfn = "nact_iprefs_read_key_str";
-	GError *error = NULL;
-	gchar *path;
-	gchar *text;
-
-	path = g_strdup_printf( "%s/%s", NA_GCONF_PREFS_PATH, key );
-
-	text = gconf_client_get_string( NACT_IPREFS_GET_INTERFACE( window )->private->client, path, &error );
-
-	if( error ){
-		g_warning( "%s: key=%s, %s", thisfn, key, error->message );
-		g_error_free( error );
-		text = NULL;
-	}
-
-	g_free( path );
-	return( text );
-}
-
-static void
-save_key_str( NactWindow *window, const gchar *key, const gchar *text )
-{
-	static const gchar *thisfn = "nact_iprefs_save_key_str";
-	GError *error = NULL;
-	gchar *path;
-
-	path = g_strdup_printf( "%s/%s", NA_GCONF_PREFS_PATH, key );
-
-	gconf_client_set_string( NACT_IPREFS_GET_INTERFACE( window )->private->client, path, text, &error );
-
-	if( error ){
-		g_warning( "%s: key=%s, %s", thisfn, key, error->message );
-		g_error_free( error );
-	}
-
-	g_free( path );
-}
-
-static gint
-read_key_int( NactWindow *window, const gchar *name )
-{
-	static const gchar *thisfn = "nact_iprefs_read_key_int";
-	GError *error = NULL;
-	gchar *path;
-	gint value;
-
-	path = g_strdup_printf( "%s/%s", NA_GCONF_PREFS_PATH, name );
-
-	value = gconf_client_get_int( NACT_IPREFS_GET_INTERFACE( window )->private->client, path, &error );
-
-	if( error ){
-		g_warning( "%s: name=%s, %s", thisfn, name, error->message );
-		g_error_free( error );
-	}
-
-	g_free( path );
-	return( value );
-}
-
-static void
-write_key_int( NactWindow *window, const gchar *name, gint value )
-{
-	static const gchar *thisfn = "nact_iprefs_write_key_int";
-	GError *error = NULL;
-	gchar *path;
-
-	path = g_strdup_printf( "%s/%s", NA_GCONF_PREFS_PATH, name );
-
-	gconf_client_set_int( NACT_IPREFS_GET_INTERFACE( window )->private->client, path, value, &error );
-
-	if( error ){
-		g_warning( "%s: name=%s, %s", thisfn, name, error->message );
-		g_error_free( error );
-	}
-
-	g_free( path );
-}
diff --git a/src/nact/base-iprefs.h b/src/nact/base-iprefs.h
new file mode 100644
index 0000000..0e9758e
--- /dev/null
+++ b/src/nact/base-iprefs.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 __BASE_IPREFS_H__
+#define __BASE_IPREFS_H__
+
+/*
+ * BaseIPrefs interface definition.
+ *
+ * This interface may be implemented by all dialogs which wish take
+ * benefit of preferences management.
+ */
+
+#include "base-window.h"
+
+G_BEGIN_DECLS
+
+#define BASE_IPREFS_TYPE						( base_iprefs_get_type())
+#define BASE_IPREFS( object )					( G_TYPE_CHECK_INSTANCE_CAST( object, BASE_IPREFS_TYPE, BaseIPrefs ))
+#define BASE_IS_IPREFS( object )				( G_TYPE_CHECK_INSTANCE_TYPE( object, BASE_IPREFS_TYPE ))
+#define BASE_IPREFS_GET_INTERFACE( instance )	( G_TYPE_INSTANCE_GET_INTERFACE(( instance ), BASE_IPREFS_TYPE, BaseIPrefsInterface ))
+
+typedef struct BaseIPrefs BaseIPrefs;
+
+typedef struct BaseIPrefsInterfacePrivate BaseIPrefsInterfacePrivate;
+
+typedef struct {
+	GTypeInterface              parent;
+	BaseIPrefsInterfacePrivate *private;
+
+	/* api */
+	gchar * ( *iprefs_get_window_id )( BaseWindow *window );
+}
+	BaseIPrefsInterface;
+
+GType    base_iprefs_get_type( void );
+
+void     base_iprefs_position_window( BaseWindow *window );
+void     base_iprefs_position_named_window( BaseWindow *window, GtkWindow *toplevel, const gchar *name );
+
+void     base_iprefs_save_window_position( BaseWindow *window );
+void     base_iprefs_save_named_window_position( BaseWindow *window, GtkWindow *toplevel, const gchar *name );
+
+gboolean base_iprefs_get_bool( BaseWindow *window, const gchar *key );
+void     base_iprefs_set_bool( BaseWindow *window, const gchar *key, gboolean value );
+
+gint     base_iprefs_get_int( BaseWindow *window, const gchar *key );
+void     base_iprefs_set_int( BaseWindow *window, const gchar *key, gint value );
+
+gchar   *base_iprefs_get_string( BaseWindow *window, const gchar *name );
+void     base_iprefs_set_string( BaseWindow *window, const gchar *name, const gchar *string );
+
+G_END_DECLS
+
+#endif /* __BASE_IPREFS_H__ */
diff --git a/src/nact/base-window-class.h b/src/nact/base-window-class.h
index 8443b00..f9d56a4 100644
--- a/src/nact/base-window-class.h
+++ b/src/nact/base-window-class.h
@@ -66,19 +66,92 @@ typedef struct {
 	GObjectClass            parent;
 	BaseWindowClassPrivate *private;
 
-	/* virtual functions */
-	void              ( *init )                 ( BaseWindow *window );
-	void              ( *run )                  ( BaseWindow *window );
-	void              ( *initial_load_toplevel )( BaseWindow *window );
-	void              ( *runtime_init_toplevel )( BaseWindow *window );
-	void              ( *all_widgets_showed )   ( BaseWindow *window );
+	/**
+	 * initial_load_toplevel:
+	 * @window: this #BaseWindow instance.
+	 */
+	void              ( *initial_load_toplevel )( BaseWindow *window, gpointer user_data );
+
+	/**
+	 * runtime_init_toplevel:
+	 * @window: this #BaseWindow instance.
+	 */
+	void              ( *runtime_init_toplevel )( BaseWindow *window, gpointer user_data );
+
+	/**
+	 * all_widgets_showed:
+	 * @window: this #BaseWindow instance.
+	 */
+	void              ( *all_widgets_showed )   ( BaseWindow *window, gpointer user_data );
+
+	/**
+	 * dialog_response:
+	 * @window: this #BaseWindow instance.
+	 */
 	gboolean          ( *dialog_response )      ( GtkDialog *dialog, gint code, BaseWindow *window );
+
+	/**
+	 * delete_event:
+	 * @window: this #BaseWindow instance.
+	 *
+	 * The #BaseWindow class connects to the "delete-event" signal,
+	 * and transforms it into a virtual function. The derived class
+	 * can so implement the virtual function, without having to take
+	 * care of the signal itself.
+	 */
 	gboolean          ( *delete_event )         ( BaseWindow *window, GtkWindow *toplevel, GdkEvent *event );
+
+	/**
+	 * get_application:
+	 * @window: this #BaseWindow instance.
+	 */
 	BaseApplication * ( *get_application )      ( BaseWindow *window );
+
+	/**
+	 * window_get_toplevel_name:
+	 * @window: this #BaseWindow instance.
+	 *
+	 * Pure virtual function.
+	 */
 	gchar *           ( *get_toplevel_name )    ( BaseWindow *window );
-	GtkWindow *       ( *get_toplevel_dialog )  ( BaseWindow *window );
-	GtkWindow *       ( *get_dialog )           ( BaseWindow *window, const gchar *name );
+
+	/**
+	 * get_toplevel_window:
+	 * @window: this #BaseWindow instance.
+	 *
+	 * Returns the toplevel #GtkWindow associated with this #BaseWindow
+	 * instance.
+	 */
+	GtkWindow *       ( *get_toplevel_window )  ( BaseWindow *window );
+
+	/**
+	 * get_window:
+	 * @window: this #BaseWindow instance.
+	 *
+	 * Returns the named GtkWindow.
+	 */
+	GtkWindow *       ( *get_window )           ( BaseWindow *window, const gchar *name );
+
+	/**
+	 * get_widget:
+	 * @window: this #BaseWindow instance.
+	 *
+	 * Returns the named #GtkWidget searched as a descendant of the
+	 * #GtkWindow toplevel associated to this #Basewindow instance.
+	 */
 	GtkWidget *       ( *get_widget )           ( BaseWindow *window, const gchar *name );
+
+	/**
+	 * get_iprefs_window_id:
+	 * @window: this #BaseWindow instance.
+	 *
+	 * Asks the derived class for the string which must be used to
+	 * store last size and position of the window in GConf preferences.
+	 *
+	 * This delegates to #BaseWindow-derived classes the NactIPrefs
+	 * interface virtual function.
+	 */
+	gchar *           ( *get_iprefs_window_id ) ( BaseWindow *window );
 }
 	BaseWindowClass;
 
diff --git a/src/nact/base-window.c b/src/nact/base-window.c
index 2ee4c74..508022c 100644
--- a/src/nact/base-window.c
+++ b/src/nact/base-window.c
@@ -38,6 +38,7 @@
 #include <string.h>
 
 #include "base-application.h"
+#include "base-iprefs.h"
 #include "base-window.h"
 
 /* private class data
@@ -53,47 +54,77 @@ struct BaseWindowPrivate {
 	BaseWindow      *parent;
 	BaseApplication *application;
 	gchar           *toplevel_name;
-	GtkWindow       *toplevel_dialog;
+	GtkWindow       *toplevel_window;
 	gboolean         initialized;
+	GSList          *signals;
+	gboolean         save_window_position;
 };
 
+/* connected signal, to be disconnected at NactWindow dispose
+ */
+typedef struct {
+	gpointer instance;
+	gulong   handler_id;
+}
+	BaseWindowRecordedSignal;
+
 /* instance properties
  */
 enum {
-	PROP_WINDOW_PARENT = 1,
-	PROP_WINDOW_APPLICATION,
-	PROP_WINDOW_TOPLEVEL_NAME,
-	PROP_WINDOW_TOPLEVEL_DIALOG,
-	PROP_WINDOW_INITIALIZED
+	BASE_WINDOW_PROP_PARENT_ID = 1,
+	BASE_WINDOW_PROP_APPLICATION_ID,
+	BASE_WINDOW_PROP_TOPLEVEL_NAME_ID,
+	BASE_WINDOW_PROP_TOPLEVEL_WIDGET_ID,
+	BASE_WINDOW_PROP_INITIALIZED_ID,
+	BASE_WINDOW_PROP_SAVE_WINDOW_POSITION_ID
+};
+
+/* signals defined in BaseWindow, to be used in all derived classes
+ */
+enum {
+	INITIAL_LOAD,
+	RUNTIME_INIT,
+	ALL_WIDGETS_SHOWED,
+	LAST_SIGNAL
 };
 
 static GObjectClass *st_parent_class = NULL;
+static gint          st_signals[ LAST_SIGNAL ] = { 0 };
+static gboolean      st_debug_signal_connect = FALSE;
 
 static GType            register_type( void );
 static void             class_init( BaseWindowClass *klass );
+static void             iprefs_iface_init( BaseIPrefsInterface *iface );
 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 *application );
 static void             instance_finalize( GObject *application );
 
-static gchar           *v_get_toplevel_name( BaseWindow *window );
-static void             v_initial_load_toplevel( BaseWindow *window );
-static void             v_runtime_init_toplevel( BaseWindow *window );
-static void             v_all_widgets_showed( BaseWindow *window );
+static gboolean         on_delete_event( GtkWidget *widget, GdkEvent *event, BaseWindow *window );
+
+static void             v_initial_load_toplevel( BaseWindow *window, gpointer user_data );
+static void             v_runtime_init_toplevel( BaseWindow *window, gpointer user_data );
+static void             v_all_widgets_showed( BaseWindow *window, gpointer user_data );
 static gboolean         v_dialog_response( GtkDialog *dialog, gint code, BaseWindow *window );
-static gboolean         v_delete_event( GtkWidget *widget, GdkEvent *event, BaseWindow *window );
-
-static void             do_init_window( BaseWindow *window );
-static void             do_initial_load_toplevel( BaseWindow *window );
-static void             do_runtime_init_toplevel( BaseWindow *window );
-static void             do_all_widgets_showed( BaseWindow *window );
-static void             do_run_window( BaseWindow *window );
-static gboolean         do_dialog_response( GtkDialog *dialog, gint code, BaseWindow *window );
-static BaseApplication *do_get_application( BaseWindow *window );
-static GtkWindow       *do_get_toplevel_dialog( BaseWindow *window );
-static GtkWindow       *do_get_dialog( BaseWindow *window, const gchar *name );
-static GtkWidget       *do_get_widget( BaseWindow *window, const gchar *name );
+static BaseApplication *v_get_application( BaseWindow *window );
+static GtkWindow       *v_get_toplevel_window( BaseWindow *window );
+static GtkWindow       *v_get_window( BaseWindow *window, const gchar *name );
+static GtkWidget       *v_get_widget( BaseWindow *window, const gchar *name );
+static gchar           *v_get_iprefs_window_id( BaseWindow *window );
+
+static void             on_runtime_init_toplevel( BaseWindow *window, gpointer user_data );
+
+static void             window_do_initial_load_toplevel( BaseWindow *window, gpointer user_data );
+static void             window_do_runtime_init_toplevel( BaseWindow *window, gpointer user_data );
+static void             window_do_all_widgets_showed( BaseWindow *window, gpointer user_data );
+static gboolean         window_do_dialog_response( GtkDialog *dialog, gint code, BaseWindow *window );
+static gboolean         window_do_delete_event( BaseWindow *window, GtkWindow *toplevel, GdkEvent *event );
+static BaseApplication *window_do_get_application( BaseWindow *window );
+static gchar           *window_do_get_toplevel_name( BaseWindow *window );
+static GtkWindow       *window_do_get_toplevel_window( BaseWindow *window );
+static GtkWindow       *window_do_get_window( BaseWindow *window, const gchar *name );
+static GtkWidget       *window_do_get_widget( BaseWindow *window, const gchar *name );
 
 static gboolean         is_main_window( BaseWindow *window );
 static gboolean         is_toplevel_initialized( BaseWindow *window, GtkWindow *toplevel );
@@ -129,10 +160,18 @@ register_type( void )
 		( GInstanceInitFunc ) instance_init
 	};
 
+	static const GInterfaceInfo prefs_iface_info = {
+		( GInterfaceInitFunc ) iprefs_iface_init,
+		NULL,
+		NULL
+	};
+
 	g_debug( "%s", thisfn );
 
 	type = g_type_register_static( G_TYPE_OBJECT, "BaseWindow", &info, 0 );
 
+	g_type_add_interface_static( type, BASE_IPREFS_TYPE, &prefs_iface_info );
+
 	return( type );
 }
 
@@ -154,53 +193,132 @@ class_init( BaseWindowClass *klass )
 	object_class->set_property = instance_set_property;
 
 	spec = g_param_spec_pointer(
-			PROP_WINDOW_PARENT_STR,
-			PROP_WINDOW_PARENT_STR,
-			"Parent BaseWindow object pointer",
+			BASE_WINDOW_PROP_PARENT,
+			"BaseWindow parent pointer",
+			"A pointer (not a reference) to the BaseWindow parent of this BaseWindow",
 			G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE );
-	g_object_class_install_property( object_class, PROP_WINDOW_PARENT, spec );
+	g_object_class_install_property( object_class, BASE_WINDOW_PROP_PARENT_ID, spec );
 
 	spec = g_param_spec_pointer(
-			PROP_WINDOW_APPLICATION_STR,
-			PROP_WINDOW_APPLICATION_STR,
-			"BaseApplication object pointer",
+			BASE_WINDOW_PROP_APPLICATION,
+			"BaseApplication pointer",
+			"A pointer (not a reference) to the BaseApplication object",
 			G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE );
-	g_object_class_install_property( object_class, PROP_WINDOW_APPLICATION, spec );
+	g_object_class_install_property( object_class, BASE_WINDOW_PROP_APPLICATION_ID, spec );
 
 	spec = g_param_spec_string(
-			PROP_WINDOW_TOPLEVEL_NAME_STR,
-			PROP_WINDOW_TOPLEVEL_NAME_STR,
-			"The internal name of the toplevel window", "",
+			BASE_WINDOW_PROP_TOPLEVEL_NAME,
+			"Internal toplevel name",
+			"The internal name in GtkBuilder of the toplevel window", "",
 			G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE );
-	g_object_class_install_property( object_class, PROP_WINDOW_TOPLEVEL_NAME, spec );
+	g_object_class_install_property( object_class, BASE_WINDOW_PROP_TOPLEVEL_NAME_ID, spec );
 
 	spec = g_param_spec_pointer(
-			PROP_WINDOW_TOPLEVEL_DIALOG_STR,
-			PROP_WINDOW_TOPLEVEL_DIALOG_STR,
-			"The main GtkWindow attached to this object",
+			BASE_WINDOW_PROP_TOPLEVEL_WIDGET,
+			"Main GtkWindow pointer",
+			"A pointer to the main GtkWindow toplevel managed by this BaseWindow instance",
 			G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE );
-	g_object_class_install_property( object_class, PROP_WINDOW_TOPLEVEL_DIALOG, spec );
+	g_object_class_install_property( object_class, BASE_WINDOW_PROP_TOPLEVEL_WIDGET_ID, spec );
 
 	spec = g_param_spec_boolean(
-			PROP_WINDOW_INITIALIZED_STR,
-			PROP_WINDOW_INITIALIZED_STR,
-			"Has base_window_init be ran", FALSE,
+			BASE_WINDOW_PROP_INITIALIZED,
+			"Has base_window_init be run",
+			"Has base_window_init be run", FALSE,
 			G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE );
-	g_object_class_install_property( object_class, PROP_WINDOW_INITIALIZED, spec );
+	g_object_class_install_property( object_class, BASE_WINDOW_PROP_INITIALIZED_ID, spec );
+
+	spec = g_param_spec_boolean(
+			BASE_WINDOW_PROP_SAVE_WINDOW_POSITION,
+			"Save window size and position on dispose",
+			"Whether the size and position of the window must be saved as a GConf preference", FALSE,
+			G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE );
+	g_object_class_install_property( object_class, BASE_WINDOW_PROP_SAVE_WINDOW_POSITION_ID, spec );
 
 	klass->private = g_new0( BaseWindowClassPrivate, 1 );
 
-	klass->init = do_init_window;
-	klass->run = do_run_window;
-	klass->initial_load_toplevel = do_initial_load_toplevel;
-	klass->runtime_init_toplevel = do_runtime_init_toplevel;
-	klass->all_widgets_showed = do_all_widgets_showed;
-	klass->dialog_response = do_dialog_response;
-	klass->get_application = do_get_application;
+	klass->initial_load_toplevel = window_do_initial_load_toplevel;
+	klass->runtime_init_toplevel = window_do_runtime_init_toplevel;
+	klass->all_widgets_showed = window_do_all_widgets_showed;
+	klass->dialog_response = window_do_dialog_response;
+	klass->delete_event = window_do_delete_event;
+	klass->get_application = window_do_get_application;
 	klass->get_toplevel_name = NULL;
-	klass->get_toplevel_dialog = do_get_toplevel_dialog;
-	klass->get_dialog = do_get_dialog;
-	klass->get_widget = do_get_widget;
+	klass->get_toplevel_window = window_do_get_toplevel_window;
+	klass->get_window = window_do_get_window;
+	klass->get_widget = window_do_get_widget;
+	klass->get_iprefs_window_id = NULL;
+
+	/**
+	 * nact-signal-base-window-initial-load:
+	 *
+	 * The signal is emitted by the #BaseWindow instance when it loads
+	 * the toplevel widget for the first time from the GtkBuilder.
+	 */
+	st_signals[ INITIAL_LOAD ] =
+		g_signal_new_class_handler(
+				BASE_WINDOW_SIGNAL_INITIAL_LOAD,
+				G_TYPE_FROM_CLASS( klass ),
+				G_SIGNAL_RUN_LAST,
+				G_CALLBACK( v_initial_load_toplevel ),
+				NULL,
+				NULL,
+				g_cclosure_marshal_VOID__POINTER,
+				G_TYPE_NONE,
+				1,
+				G_TYPE_POINTER );
+
+	/**
+	 * nact-signal-base-window-runtime-init:
+	 *
+	 * The signal is emitted by the #BaseWindow instance when it is
+	 * about to display the toplevel widget. Is is so time to initialize
+	 * it with runtime values.
+	 */
+	st_signals[ RUNTIME_INIT ] =
+		g_signal_new_class_handler(
+				BASE_WINDOW_SIGNAL_RUNTIME_INIT,
+				G_TYPE_FROM_CLASS( klass ),
+				G_SIGNAL_RUN_LAST,
+				G_CALLBACK( v_runtime_init_toplevel ),
+				NULL,
+				NULL,
+				g_cclosure_marshal_VOID__POINTER,
+				G_TYPE_NONE,
+				1,
+				G_TYPE_POINTER );
+
+	/**
+	 * nact-signal-base-window-all-widgets-showed:
+	 *
+	 * The signal is emitted by the #BaseWindow instance when the
+	 * toplevel widget has been initialized with its runtime values,
+	 * just after showing it and all its descendants.
+	 *
+	 * It is typically used by notebooks, to select the first visible
+	 * page.
+	 */
+	st_signals[ ALL_WIDGETS_SHOWED ] =
+		g_signal_new_class_handler(
+				BASE_WINDOW_SIGNAL_ALL_WIDGETS_SHOWED,
+				G_TYPE_FROM_CLASS( klass ),
+				G_SIGNAL_RUN_LAST,
+				G_CALLBACK( v_all_widgets_showed ),
+				NULL,
+				NULL,
+				g_cclosure_marshal_VOID__POINTER,
+				G_TYPE_NONE,
+				1,
+				G_TYPE_POINTER );
+}
+
+static void
+iprefs_iface_init( BaseIPrefsInterface *iface )
+{
+	static const gchar *thisfn = "base_window_iprefs_iface_init";
+
+	g_debug( "%s: iface=%p", thisfn, ( void * ) iface );
+
+	iface->iprefs_get_window_id = v_get_iprefs_window_id;
 }
 
 static void
@@ -211,12 +329,20 @@ instance_init( GTypeInstance *instance, gpointer klass )
 
 	g_debug( "%s: instance=%p, klass=%p", thisfn, ( void * ) instance, ( void * ) klass );
 
-	g_assert( BASE_IS_WINDOW( instance ));
+	g_return_if_fail( BASE_IS_WINDOW( instance ));
 	self = BASE_WINDOW( instance );
 
 	self->private = g_new0( BaseWindowPrivate, 1 );
 
 	self->private->dispose_has_run = FALSE;
+	self->private->signals = NULL;
+	self->private->save_window_position = TRUE;
+
+	base_window_signal_connect(
+			self,
+			G_OBJECT( instance ),
+			BASE_WINDOW_SIGNAL_RUNTIME_INIT,
+			G_CALLBACK( on_runtime_init_toplevel ));
 }
 
 static void
@@ -224,30 +350,34 @@ instance_get_property( GObject *object, guint property_id, GValue *value, GParam
 {
 	BaseWindow *self;
 
-	g_assert( BASE_IS_WINDOW( object ));
+	g_return_if_fail( BASE_IS_WINDOW( object ));
 	self = BASE_WINDOW( object );
 
 	switch( property_id ){
-		case PROP_WINDOW_PARENT:
+		case BASE_WINDOW_PROP_PARENT_ID:
 			g_value_set_pointer( value, self->private->parent );
 			break;
 
-		case PROP_WINDOW_APPLICATION:
+		case BASE_WINDOW_PROP_APPLICATION_ID:
 			g_value_set_pointer( value, self->private->application );
 			break;
 
-		case PROP_WINDOW_TOPLEVEL_NAME:
+		case BASE_WINDOW_PROP_TOPLEVEL_NAME_ID:
 			g_value_set_string( value, self->private->toplevel_name );
 			break;
 
-		case PROP_WINDOW_TOPLEVEL_DIALOG:
-			g_value_set_pointer( value, self->private->toplevel_dialog );
+		case BASE_WINDOW_PROP_TOPLEVEL_WIDGET_ID:
+			g_value_set_pointer( value, self->private->toplevel_window );
 			break;
 
-		case PROP_WINDOW_INITIALIZED:
+		case BASE_WINDOW_PROP_INITIALIZED_ID:
 			g_value_set_boolean( value, self->private->initialized );
 			break;
 
+		case BASE_WINDOW_PROP_SAVE_WINDOW_POSITION_ID:
+			g_value_set_boolean( value, self->private->save_window_position );
+			break;
+
 		default:
 			G_OBJECT_WARN_INVALID_PROPERTY_ID( object, property_id, spec );
 			break;
@@ -259,31 +389,35 @@ instance_set_property( GObject *object, guint property_id, const GValue *value,
 {
 	BaseWindow *self;
 
-	g_assert( BASE_IS_WINDOW( object ));
+	g_return_if_fail( BASE_IS_WINDOW( object ));
 	self = BASE_WINDOW( object );
 
 	switch( property_id ){
-		case PROP_WINDOW_PARENT:
+		case BASE_WINDOW_PROP_PARENT_ID:
 			self->private->parent = g_value_get_pointer( value );
 			break;
 
-		case PROP_WINDOW_APPLICATION:
+		case BASE_WINDOW_PROP_APPLICATION_ID:
 			self->private->application = g_value_get_pointer( value );
 			break;
 
-		case PROP_WINDOW_TOPLEVEL_NAME:
+		case BASE_WINDOW_PROP_TOPLEVEL_NAME_ID:
 			g_free( self->private->toplevel_name );
 			self->private->toplevel_name = g_value_dup_string( value );
 			break;
 
-		case PROP_WINDOW_TOPLEVEL_DIALOG:
-			self->private->toplevel_dialog = g_value_get_pointer( value );
+		case BASE_WINDOW_PROP_TOPLEVEL_WIDGET_ID:
+			self->private->toplevel_window = g_value_get_pointer( value );
 			break;
 
-		case PROP_WINDOW_INITIALIZED:
+		case BASE_WINDOW_PROP_INITIALIZED_ID:
 			self->private->initialized = g_value_get_boolean( value );
 			break;
 
+		case BASE_WINDOW_PROP_SAVE_WINDOW_POSITION_ID:
+			self->private->save_window_position = g_value_get_boolean( value );
+			break;
+
 		default:
 			G_OBJECT_WARN_INVALID_PROPERTY_ID( object, property_id, spec );
 			break;
@@ -295,32 +429,53 @@ instance_dispose( GObject *window )
 {
 	static const gchar *thisfn = "base_window_instance_dispose";
 	BaseWindow *self;
+	GSList *is;
 
 	g_debug( "%s: window=%p", thisfn, ( void * ) window );
-	g_assert( BASE_IS_WINDOW( window ));
+	g_return_if_fail( BASE_IS_WINDOW( window ));
 	self = BASE_WINDOW( window );
 
 	if( !self->private->dispose_has_run ){
 
-		self->private->dispose_has_run = TRUE;
+		if( self->private->save_window_position ){
+			base_iprefs_save_window_position( self );
+		}
+
+		/* signals must be deconnected before quitting main loop
+		 */
+		for( is = self->private->signals ; is ; is = is->next ){
+			BaseWindowRecordedSignal *str = ( BaseWindowRecordedSignal * ) is->data;
+			if( g_signal_handler_is_connected( str->instance, str->handler_id )){
+				g_signal_handler_disconnect( str->instance, str->handler_id );
+				if( st_debug_signal_connect ){
+					g_debug( "%s: disconnecting signal handler %p:%lu", thisfn, str->instance, str->handler_id );
+				}
+			}
+			g_free( str );
+		}
+		g_slist_free( self->private->signals );
 
 		if( is_main_window( BASE_WINDOW( window ))){
 			g_debug( "%s: quitting main window", thisfn );
 			gtk_main_quit ();
-			gtk_widget_destroy( GTK_WIDGET( self->private->toplevel_dialog ));
+			gtk_widget_destroy( GTK_WIDGET( self->private->toplevel_window ));
 
-		} else if( GTK_IS_ASSISTANT( self->private->toplevel_dialog )){
+		} else if( GTK_IS_ASSISTANT( self->private->toplevel_window )){
 			g_debug( "%s: quitting assistant", thisfn );
 			gtk_main_quit();
-			gtk_widget_hide_all( GTK_WIDGET( self->private->toplevel_dialog ));
+			gtk_widget_hide_all( GTK_WIDGET( self->private->toplevel_window ));
 
 		} else {
 			g_debug( "%s: quitting dialog", thisfn );
-			gtk_widget_hide_all( GTK_WIDGET( self->private->toplevel_dialog ));
+			gtk_widget_hide_all( GTK_WIDGET( self->private->toplevel_window ));
 		}
 
+		self->private->dispose_has_run = TRUE;
+
 		/* chain up to the parent class */
-		G_OBJECT_CLASS( st_parent_class )->dispose( window );
+		if( G_OBJECT_CLASS( st_parent_class )->dispose ){
+			G_OBJECT_CLASS( st_parent_class )->dispose( window );
+		}
 	}
 }
 
@@ -331,7 +486,7 @@ instance_finalize( GObject *window )
 	BaseWindow *self;
 
 	g_debug( "%s: window=%p", thisfn, ( void * ) window );
-	g_assert( BASE_IS_WINDOW( window ));
+	g_return_if_fail( BASE_IS_WINDOW( window ));
 	self = ( BaseWindow * ) window;
 
 	g_free( self->private->toplevel_name );
@@ -339,15 +494,14 @@ instance_finalize( GObject *window )
 	g_free( self->private );
 
 	/* chain call to parent class */
-	if( st_parent_class->finalize ){
+	if( G_OBJECT_CLASS( st_parent_class )->finalize ){
 		G_OBJECT_CLASS( st_parent_class )->finalize( window );
 	}
 }
 
 /**
  * Initializes the window.
- *
- * @window: this BaseWindow object.
+ * @window: this #BaseWindow object.
  *
  * This is a one-time initialization just after the BaseWindow has been
  * allocated. This should leave the BaseWindow object with a valid
@@ -360,14 +514,50 @@ instance_finalize( GObject *window )
  * the user opens the dialog, though the GtkWindow itself needs only
  * be initialized the first time it is loaded.
  */
-void
+gboolean
 base_window_init( BaseWindow *window )
 {
-	g_assert( BASE_IS_WINDOW( window ));
+	static const gchar *thisfn = "base_window_init";
+	gchar *dialog_name;
+	GtkWindow *toplevel;
+
+	g_return_val_if_fail( BASE_IS_WINDOW( window ), FALSE );
+
+	if( !window->private->initialized ){
+		g_debug( "%s: window=%p", thisfn, ( void * ) window );
+
+		if( !window->private->application ){
+			g_return_val_if_fail( window->private->parent, FALSE );
+			g_return_val_if_fail( BASE_IS_WINDOW( window->private->parent ), FALSE );
+			window->private->application = BASE_APPLICATION( base_window_get_application( window->private->parent ));
+			g_debug( "%s: application=%p", thisfn, ( void * ) window->private->application );
+		}
+
+		g_assert( window->private->application );
+		g_assert( BASE_IS_APPLICATION( window->private->application ));
+
+		dialog_name = window_do_get_toplevel_name( window );
+		g_assert( dialog_name && strlen( dialog_name ));
+
+		toplevel = base_window_get_toplevel( window, dialog_name );
+		window->private->toplevel_window = toplevel;
+
+		if( toplevel ){
+			g_assert( GTK_IS_WINDOW( toplevel ));
+
+			if( !is_toplevel_initialized( window, toplevel )){
 
-	if( BASE_WINDOW_GET_CLASS( window )->init ){
-		BASE_WINDOW_GET_CLASS( window )->init( window );
+				g_signal_emit_by_name( window, BASE_WINDOW_SIGNAL_INITIAL_LOAD, NULL );
+
+				set_toplevel_initialized( window, toplevel, TRUE );
+			}
+			window->private->initialized = TRUE;
+		}
+
+		g_free( dialog_name );
 	}
+
+	return( window->private->initialized );
 }
 
 /**
@@ -378,9 +568,48 @@ base_window_init( BaseWindow *window )
 void
 base_window_run( BaseWindow *window )
 {
-	g_assert( BASE_IS_WINDOW( window ));
-	if( BASE_WINDOW_GET_CLASS( window )->run ){
-		BASE_WINDOW_GET_CLASS( window )->run( window );
+	static const gchar *thisfn = "base_window_run";
+	GtkWidget *this_dialog;
+	gint code;
+
+	g_return_if_fail( BASE_IS_WINDOW( window ));
+
+	if( !window->private->initialized ){
+		base_window_init( window );
+	}
+
+	g_debug( "%s: window=%p", thisfn, ( void * ) window );
+
+	g_signal_emit_by_name( window, BASE_WINDOW_SIGNAL_RUNTIME_INIT, NULL );
+
+	this_dialog = GTK_WIDGET( window->private->toplevel_window );
+
+	gtk_widget_show_all( this_dialog );
+
+	g_signal_emit_by_name( window, BASE_WINDOW_SIGNAL_ALL_WIDGETS_SHOWED, NULL );
+
+	if( is_main_window( window )){
+
+		if( GTK_IS_DIALOG( this_dialog )){
+			g_signal_connect( G_OBJECT( this_dialog ), "response", G_CALLBACK( v_dialog_response ), window );
+		} else {
+			g_signal_connect( G_OBJECT( this_dialog ), "delete-event", G_CALLBACK( on_delete_event ), window );
+		}
+
+		g_debug( "%s: application=%p, starting gtk_main", thisfn, ( void * ) window->private->application );
+		gtk_main();
+
+	} else if( GTK_IS_ASSISTANT( this_dialog )){
+		g_debug( "%s: starting gtk_main", thisfn );
+		gtk_main();
+
+	} else {
+		g_assert( GTK_IS_DIALOG( this_dialog ));
+		g_debug( "%s: starting gtk_dialog_run", thisfn );
+		do {
+			code = gtk_dialog_run( GTK_DIALOG( this_dialog ));
+		}
+		while( !v_dialog_response( GTK_DIALOG( this_dialog ), code, window ));
 	}
 }
 
@@ -392,34 +621,38 @@ base_window_run( BaseWindow *window )
 BaseApplication *
 base_window_get_application( BaseWindow *window )
 {
-	g_assert( BASE_IS_WINDOW( window ));
-	return( BASE_WINDOW_GET_CLASS( window )->get_application( window ));
+	g_return_val_if_fail( BASE_IS_WINDOW( window ), NULL );
+
+	return( v_get_application( window ));
 }
 
 /**
- * Returns the top-level GtkWindow attached to this BaseWindow object.
+ * base_window_get_toplevel_window:
+ * @window: this #BaseWindow instance..
  *
- * @window: this BaseWindow object.
+ * Returns the top-level GtkWindow attached to this BaseWindow object.
  */
 GtkWindow *
-base_window_get_toplevel_dialog( BaseWindow *window )
+base_window_get_toplevel_window( BaseWindow *window )
 {
-	g_assert( BASE_IS_WINDOW( window ));
-	return( BASE_WINDOW_GET_CLASS( window )->get_toplevel_dialog( window ));
+	g_return_val_if_fail( BASE_IS_WINDOW( window ), NULL );
+
+	return( v_get_toplevel_window( window ));
 }
 
 /**
- * Returns a top-level GtkWindow.
- *
- * @window: this BaseWindow object.
- *
+ * base_window_get_toplevel:
+ * @window: this #BaseWindow instance.
  * @name: the name of the searched GtkWindow.
+ *
+ * Returns a top-level GtkWindow.
  */
 GtkWindow *
-base_window_get_dialog( BaseWindow *window, const gchar *name )
+base_window_get_toplevel( BaseWindow *window, const gchar *name )
 {
 	g_assert( BASE_IS_WINDOW( window ));
-	return( BASE_WINDOW_GET_CLASS( window )->get_dialog( window, name ));
+
+	return( v_get_window( window, name ));
 }
 
 /**
@@ -433,253 +666,280 @@ GtkWidget *
 base_window_get_widget( BaseWindow *window, const gchar *name )
 {
 	g_assert( BASE_IS_WINDOW( window ));
-	return( BASE_WINDOW_GET_CLASS( window )->get_widget( window, name ));
+
+	return( v_get_widget( window, name ));
 }
 
-static gchar *
-v_get_toplevel_name( BaseWindow *window )
+/*
+ * handler of "delete-event" message
+ * let a chance to derived class to handle it
+ * our own function does nothing, and let the signal be propagated.
+ */
+static gboolean
+on_delete_event( GtkWidget *toplevel, GdkEvent *event, BaseWindow *window )
 {
-	gchar *name;
+	static const gchar *thisfn = "base_window_on_delete_event";
 
+	g_debug( "%s: toplevel=%p, event=%p, window=%p",
+			thisfn, ( void * ) toplevel, ( void * ) event, ( void * ) window );
 	g_assert( BASE_IS_WINDOW( window ));
 
-	g_object_get( G_OBJECT( window ), PROP_WINDOW_TOPLEVEL_NAME_STR, &name, NULL );
-
-	if( !name || !strlen( name )){
-		name = BASE_WINDOW_GET_CLASS( window )->get_toplevel_name( window );
-		if( name && strlen( name )){
-			g_object_set( G_OBJECT( window ), PROP_WINDOW_TOPLEVEL_NAME_STR, name, NULL );
-		}
+	if( BASE_WINDOW_GET_CLASS( window )->delete_event ){
+		return( BASE_WINDOW_GET_CLASS( window )->delete_event( window, GTK_WINDOW( toplevel ), event ));
 	}
 
-	return( name );
+	return( window_do_delete_event( window, GTK_WINDOW( toplevel ), event ));
 }
 
+/*
+ * default class handler for "nact-signal-base-window-initial-load" message
+ * -> does nothing here
+ */
 static void
-v_initial_load_toplevel( BaseWindow *window )
+v_initial_load_toplevel( BaseWindow *window, gpointer user_data )
 {
-	GtkWindow *toplevel;
+	static const gchar *thisfn = "base_window_v_initial_load_toplevel";
 
+	g_debug( "%s: window=%p, user_data=%p", thisfn, ( void * ) window, ( void * ) user_data );
 	g_assert( BASE_IS_WINDOW( window ));
 
-	toplevel = window->private->toplevel_dialog;
-	g_assert( toplevel );
-	g_assert( GTK_IS_WINDOW( toplevel ));
+	if( BASE_WINDOW_GET_CLASS( window )->initial_load_toplevel ){
+		BASE_WINDOW_GET_CLASS( window )->initial_load_toplevel( window, user_data );
 
-	if( window->private->toplevel_dialog ){
-		if( BASE_WINDOW_GET_CLASS( window )->initial_load_toplevel ){
-			BASE_WINDOW_GET_CLASS( window )->initial_load_toplevel( window );
-		}
+	} else {
+		window_do_initial_load_toplevel( window, user_data );
 	}
 }
 
+/*
+ * default class handler for "nact-signal-base-window-runtime-init" message
+ * -> does nothing here
+ */
 static void
-v_runtime_init_toplevel( BaseWindow *window )
+v_runtime_init_toplevel( BaseWindow *window, gpointer user_data )
 {
+	static const gchar *thisfn = "base_window_v_runtime_init_toplevel";
+
+	g_debug( "%s: window=%p, user_data=%p", thisfn, ( void * ) window, ( void * ) user_data );
 	g_assert( BASE_IS_WINDOW( window ));
 
-	if( window->private->toplevel_dialog ){
-		if( BASE_WINDOW_GET_CLASS( window )->runtime_init_toplevel ){
-			BASE_WINDOW_GET_CLASS( window )->runtime_init_toplevel( window );
-		}
+	if( BASE_WINDOW_GET_CLASS( window )->runtime_init_toplevel ){
+		BASE_WINDOW_GET_CLASS( window )->runtime_init_toplevel( window, user_data );
+
+	} else {
+		window_do_runtime_init_toplevel( window, user_data );
 	}
 }
 
 static void
-v_all_widgets_showed( BaseWindow *window )
+v_all_widgets_showed( BaseWindow *window, gpointer user_data )
 {
+	static const gchar *thisfn = "base_window_v_all_widgets_showed";
+
+	g_debug( "%s: window=%p, user_data=%p", thisfn, ( void * ) window, ( void * ) user_data );
 	g_assert( BASE_IS_WINDOW( window ));
 
-	if( window->private->toplevel_dialog ){
-		if( BASE_WINDOW_GET_CLASS( window )->all_widgets_showed ){
-			BASE_WINDOW_GET_CLASS( window )->all_widgets_showed( window );
-		}
+	if( BASE_WINDOW_GET_CLASS( window )->all_widgets_showed ){
+		BASE_WINDOW_GET_CLASS( window )->all_widgets_showed( window, user_data );
+
+	} else {
+		window_do_all_widgets_showed( window, user_data );
 	}
 }
 
-/*
- * return TRUE to quit the dialog loop
- */
 static gboolean
 v_dialog_response( GtkDialog *dialog, gint code, BaseWindow *window )
 {
+	static const gchar *thisfn = "base_window_v_dialog_response";
+
+	g_debug( "%s: dialog=%p, code=%d, window=%p", thisfn, ( void * ) dialog, code, ( void * ) window );
 	g_assert( BASE_IS_WINDOW( window ));
 
 	if( BASE_WINDOW_GET_CLASS( window )->dialog_response ){
 		return( BASE_WINDOW_GET_CLASS( window )->dialog_response( dialog, code, window ));
 	}
 
-	return( TRUE );
+	return( window_do_dialog_response( dialog, code, window ));
 }
 
-/*
- * return TRUE to quit the toplevel window loop
- */
-static gboolean
-v_delete_event( GtkWidget *widget, GdkEvent *event, BaseWindow *window )
+static BaseApplication *
+v_get_application( BaseWindow *window )
 {
 	g_assert( BASE_IS_WINDOW( window ));
-	g_assert( GTK_IS_WINDOW( widget ));
 
-	if( BASE_WINDOW_GET_CLASS( window )->delete_event ){
-		return( BASE_WINDOW_GET_CLASS( window )->delete_event( window, GTK_WINDOW( widget ), event ));
+	if( BASE_WINDOW_GET_CLASS( window )->get_application ){
+		return( BASE_WINDOW_GET_CLASS( window )->get_application( window ));
 	}
 
-	return( TRUE );
+	return( window_do_get_application( window ));
 }
 
-static void
-do_init_window( BaseWindow *window )
+static GtkWindow *
+v_get_toplevel_window( BaseWindow *window )
 {
-	static const gchar *thisfn = "base_window_do_init_window";
-	gchar *dialog_name;
-	GtkWindow *toplevel;
-
 	g_assert( BASE_IS_WINDOW( window ));
 
-	if( !window->private->initialized ){
-		g_debug( "%s: window=%p", thisfn, ( void * ) window );
-
-		if( !window->private->application ){
-			g_assert( window->private->parent );
-			g_assert( BASE_IS_WINDOW( window->private->parent ));
-			window->private->application = BASE_APPLICATION( base_window_get_application( window->private->parent ));
-			g_debug( "%s: application=%p", thisfn, ( void * ) window->private->application );
-		}
-
-		g_assert( window->private->application );
-		g_assert( BASE_IS_APPLICATION( window->private->application ));
+	if( BASE_WINDOW_GET_CLASS( window )->get_toplevel_window ){
+		return( BASE_WINDOW_GET_CLASS( window )->get_toplevel_window( window ));
+	}
 
-		dialog_name = v_get_toplevel_name( window );
-		g_assert( dialog_name && strlen( dialog_name ));
+	return( window_do_get_toplevel_window( window ));
+}
 
-		toplevel = base_window_get_dialog( window, dialog_name );
-		window->private->toplevel_dialog = toplevel;
+static GtkWindow *
+v_get_window( BaseWindow *window, const gchar *name )
+{
+	g_assert( BASE_IS_WINDOW( window ));
 
-		if( toplevel ){
-			g_assert( GTK_IS_WINDOW( toplevel ));
+	if( BASE_WINDOW_GET_CLASS( window )->get_window ){
+		return( BASE_WINDOW_GET_CLASS( window )->get_window( window, name ));
+	}
 
-			if( !is_toplevel_initialized( window, toplevel )){
+	return( window_do_get_window( window, name ));
+}
 
-				v_initial_load_toplevel( window );
-				set_toplevel_initialized( window, toplevel, TRUE );
-			}
-		}
+static GtkWidget *
+v_get_widget( BaseWindow *window, const gchar *name )
+{
+	g_assert( BASE_IS_WINDOW( window ));
 
-		g_free( dialog_name );
-		window->private->initialized = TRUE;
+	if( BASE_WINDOW_GET_CLASS( window )->get_widget ){
+		return( BASE_WINDOW_GET_CLASS( window )->get_widget( window, name ));
 	}
+
+	return( window_do_get_widget( window, name ));
 }
 
-static void
-do_initial_load_toplevel( BaseWindow *window )
+static gchar *
+v_get_iprefs_window_id( BaseWindow *window )
 {
-	static const gchar *thisfn = "base_window_do_initial_load_toplevel";
+	g_assert( BASE_IS_IPREFS( window ));
 
-	g_debug( "%s: window=%p", thisfn, ( void * ) window );
+	if( BASE_WINDOW_GET_CLASS( window )->get_iprefs_window_id ){
+		return( BASE_WINDOW_GET_CLASS( window )->get_iprefs_window_id( window ));
+	}
+
+	return( NULL );
 }
 
 static void
-do_runtime_init_toplevel( BaseWindow *window )
+on_runtime_init_toplevel( BaseWindow *window, gpointer user_data )
 {
-	static const gchar *thisfn = "base_window_do_runtime_init_toplevel";
+	static const gchar *thisfn = "base_window_on_runtime_init_toplevel";
 	GtkWindow *parent_toplevel;
 
-	g_debug( "%s: window=%p, parent_window=%p",
-			thisfn, ( void * ) window, ( void * ) window->private->parent );
+	g_debug( "%s: window=%p, user_data=%p, parent_window=%p",
+			thisfn, ( void * ) window, ( void * ) user_data, ( void * ) window->private->parent );
 
 	if( window->private->parent ){
 		g_assert( BASE_IS_WINDOW( window->private->parent ));
-		parent_toplevel = base_window_get_toplevel_dialog( BASE_WINDOW( window->private->parent ));
-		gtk_window_set_transient_for( window->private->toplevel_dialog, parent_toplevel );
+		parent_toplevel = base_window_get_toplevel_window( BASE_WINDOW( window->private->parent ));
+		gtk_window_set_transient_for( window->private->toplevel_window, parent_toplevel );
 	}
+
+	base_iprefs_position_window( window );
 }
 
 static void
-do_all_widgets_showed( BaseWindow *window )
+window_do_initial_load_toplevel( BaseWindow *window, gpointer user_data )
 {
-	static const gchar *thisfn = "base_window_do_all_widgets_showed";
+	static const gchar *thisfn = "base_window_do_initial_load_toplevel";
 
-	g_debug( "%s: window=%p", thisfn, ( void * ) window );
+	g_debug( "%s: window=%p, user_data=%p", thisfn, ( void * ) window, ( void * ) user_data );
 }
 
 static void
-do_run_window( BaseWindow *window )
+window_do_runtime_init_toplevel( BaseWindow *window, gpointer user_data )
 {
-	static const gchar *thisfn = "base_window_do_run_window";
-	GtkWidget *this_dialog;
-	gint code;
-
-	if( !window->private->initialized ){
-		base_window_init( window );
-	}
-
-	v_runtime_init_toplevel( window );
-
-	g_debug( "%s: window=%p", thisfn, ( void * ) window );
-
-	this_dialog = GTK_WIDGET( window->private->toplevel_dialog );
-	gtk_widget_show_all( this_dialog );
-	v_all_widgets_showed( window );
-
-	if( is_main_window( window )){
-
-		if( GTK_IS_DIALOG( this_dialog )){
-			g_signal_connect( G_OBJECT( this_dialog ), "response", G_CALLBACK( v_dialog_response ), window );
-		} else {
-			g_signal_connect( G_OBJECT( this_dialog ), "delete-event", G_CALLBACK( v_delete_event ), window );
-		}
+	static const gchar *thisfn = "base_window_do_runtime_init_toplevel";
 
-		g_debug( "%s: application=%p, starting gtk_main", thisfn, ( void * ) window->private->application );
-		gtk_main();
+	g_debug( "%s: window=%p, user_data=%p", thisfn, ( void * ) window, ( void * ) user_data );
+}
 
-	} else if( GTK_IS_ASSISTANT( this_dialog )){
-		g_debug( "%s: starting gtk_main", thisfn );
-		gtk_main();
+static void
+window_do_all_widgets_showed( BaseWindow *window, gpointer user_data )
+{
+	static const gchar *thisfn = "base_window_do_all_widgets_showed";
 
-	} else {
-		g_assert( GTK_IS_DIALOG( this_dialog ));
-		g_debug( "%s: starting gtk_dialog_run", thisfn );
-		do {
-			code = gtk_dialog_run( GTK_DIALOG( this_dialog ));
-		}
-		while( !v_dialog_response( GTK_DIALOG( this_dialog ), code, window ));
-	}
+	g_debug( "%s: window=%p, user_data=%p", thisfn, ( void * ) window, ( void * ) user_data );
 }
 
+/*
+ * return TRUE to quit the dialog loop
+ */
 static gboolean
-do_dialog_response( GtkDialog *dialog, gint code, BaseWindow *window )
+window_do_dialog_response( GtkDialog *dialog, gint code, BaseWindow *window )
 {
 	static const gchar *thisfn = "base_window_do_dialog_response";
 
 	g_debug( "%s: dialog=%p, code=%d, window=%p", thisfn, ( void * ) dialog, code, ( void * ) window );
+	g_return_val_if_fail( GTK_IS_DIALOG( dialog ), FALSE );
+	g_return_val_if_fail( BASE_IS_WINDOW( window ), FALSE );
 
 	return( TRUE );
 }
 
+/*
+ * return TRUE to stop other handlers from being invoked for the event.
+ * note that default handler will destroy this window
+ */
+static gboolean
+window_do_delete_event( BaseWindow *window, GtkWindow *toplevel, GdkEvent *event )
+{
+	static const gchar *thisfn = "base_window_do_delete_event";
+
+	g_debug( "%s: window=%p, toplevel=%p, event=%p",
+			thisfn, ( void * ) window, ( void * ) toplevel, ( void * ) event );
+	g_return_val_if_fail( BASE_IS_WINDOW( window ), FALSE );
+	g_return_val_if_fail( GTK_IS_WINDOW( toplevel ), FALSE );
+
+	return( FALSE );
+}
+
 static BaseApplication *
-do_get_application( BaseWindow *window )
+window_do_get_application( BaseWindow *window )
 {
 	return( window->private->application );
 }
 
+static gchar *
+window_do_get_toplevel_name( BaseWindow *window )
+{
+	gchar *name;
+
+	g_assert( BASE_IS_WINDOW( window ));
+
+	g_object_get( G_OBJECT( window ), BASE_WINDOW_PROP_TOPLEVEL_NAME, &name, NULL );
+
+	if( !name || !strlen( name )){
+		name = BASE_WINDOW_GET_CLASS( window )->get_toplevel_name( window );
+		if( name && strlen( name )){
+			g_object_set( G_OBJECT( window ), BASE_WINDOW_PROP_TOPLEVEL_NAME, name, NULL );
+		}
+	}
+
+	return( name );
+}
+
 static GtkWindow *
-do_get_toplevel_dialog( BaseWindow *window )
+window_do_get_toplevel_window( BaseWindow *window )
 {
-	return( window->private->toplevel_dialog );
+	return( window->private->toplevel_window );
 }
 
 static GtkWindow *
-do_get_dialog( BaseWindow *window, const gchar *name )
+window_do_get_window( BaseWindow *window, const gchar *name )
 {
 	g_assert( BASE_IS_WINDOW( window ));
-	return( base_application_get_dialog( window->private->application, name ));
+
+	return( base_application_get_toplevel( window->private->application, name ));
 }
 
 static GtkWidget *
-do_get_widget( BaseWindow *window, const gchar *name )
+window_do_get_widget( BaseWindow *window, const gchar *name )
 {
 	g_assert( BASE_IS_WINDOW( window ));
+
 	return( base_application_get_widget( window->private->application, window, name ));
 }
 
@@ -690,9 +950,9 @@ is_main_window( BaseWindow *window )
 
 	BaseWindow *main_window = BASE_WINDOW( base_application_get_main_window( appli ));
 
-	GtkWidget *main_dialog = GTK_WIDGET( base_window_get_toplevel_dialog( main_window ));
+	GtkWidget *main_dialog = GTK_WIDGET( base_window_get_toplevel_window( main_window ));
 
-	GtkWidget *this_dialog = GTK_WIDGET( window->private->toplevel_dialog );
+	GtkWidget *this_dialog = GTK_WIDGET( window->private->toplevel_window );
 
 	return( main_dialog == this_dialog );
 }
@@ -726,3 +986,32 @@ base_window_yesno_dlg( BaseWindow *window, GtkMessageType type, const gchar *fir
 	g_assert( BASE_IS_WINDOW( window ));
 	return( base_application_yesno_dlg( window->private->application, type, first, second ));
 }
+
+/**
+ * Records a connected signal, to be disconnected at NactWindow dispose.
+ */
+void
+base_window_signal_connect( BaseWindow *window, GObject *instance, const gchar *signal, GCallback fn )
+{
+	static const gchar *thisfn = "base_window_signal_connect";
+
+	gulong handler_id = g_signal_connect( instance, signal, fn, window );
+
+	BaseWindowRecordedSignal *str = g_new0( BaseWindowRecordedSignal, 1 );
+	str->instance = instance;
+	str->handler_id = handler_id;
+	window->private->signals = g_slist_prepend( window->private->signals, str );
+
+	if( st_debug_signal_connect ){
+		g_debug( "%s: connecting signal handler %p:%lu", thisfn, ( void * ) instance, handler_id );
+	}
+}
+
+void
+base_window_signal_connect_by_name( BaseWindow *window, const gchar *name, const gchar *signal, GCallback fn )
+{
+	GtkWidget *widget = base_window_get_widget( window, name );
+	if( GTK_IS_WIDGET( widget )){
+		base_window_signal_connect( window, G_OBJECT( widget ), signal, fn );
+	}
+}
diff --git a/src/nact/base-window.h b/src/nact/base-window.h
index 6a9b5b7..c55a817 100644
--- a/src/nact/base-window.h
+++ b/src/nact/base-window.h
@@ -48,23 +48,44 @@ G_BEGIN_DECLS
 
 /* instance properties
  */
-#define PROP_WINDOW_PARENT_STR				"base-window-parent"
-#define PROP_WINDOW_APPLICATION_STR			"base-window-application"
-#define PROP_WINDOW_TOPLEVEL_NAME_STR		"base-window-toplevel-name"
-#define PROP_WINDOW_TOPLEVEL_DIALOG_STR		"base-window-toplevel-dialog"
-#define PROP_WINDOW_INITIALIZED_STR			"base-window-is-initialized"
+#define BASE_WINDOW_PROP_PARENT						"base-window-parent"
+#define BASE_WINDOW_PROP_APPLICATION				"base-window-application"
+#define BASE_WINDOW_PROP_TOPLEVEL_NAME				"base-window-toplevel-name"
+#define BASE_WINDOW_PROP_TOPLEVEL_WIDGET			"base-window-toplevel-widget"
+#define BASE_WINDOW_PROP_INITIALIZED				"base-window-is-initialized"
+#define BASE_WINDOW_PROP_SAVE_WINDOW_POSITION		"base-window-save-window-position"
 
-void             base_window_init( BaseWindow *window );
+/* signals defined in this class
+ *
+ * All signals of this class have the same behavior:
+ * - the message is sent to all derived classes, which are free to
+ *   connect to the signal in order to implement their own code
+ * - finally, the default class handler points to a virtual function
+ * - the virtual function actually tries to call the actual function
+ *   as possibly implemented by the derived class
+ * - if no derived class has implemented the virtual function, the call
+ *   fall back to doing nothing at all
+ */
+#define BASE_WINDOW_SIGNAL_INITIAL_LOAD				"nact-base-window-initial-load"
+#define BASE_WINDOW_SIGNAL_RUNTIME_INIT				"nact-base-window-runtime-init"
+#define BASE_WINDOW_SIGNAL_ALL_WIDGETS_SHOWED		"nact-base-window-all-widgets-showed"
+
+gboolean         base_window_init( BaseWindow *window );
 void             base_window_run( BaseWindow *window );
 
-GtkWindow       *base_window_get_toplevel_dialog( BaseWindow *window );
+GtkWindow       *base_window_get_toplevel_window( BaseWindow *window );
 BaseApplication *base_window_get_application( BaseWindow *window );
-GtkWindow       *base_window_get_dialog( BaseWindow *window, const gchar *name );
+GtkWindow       *base_window_get_toplevel( BaseWindow *window, const gchar *name );
 GtkWidget       *base_window_get_widget( BaseWindow *window, const gchar *name );
 
+void             base_window_set_save_window_position( BaseWindow *window, gboolean save );
+
 void             base_window_error_dlg( BaseWindow *window, GtkMessageType type, const gchar *primary, const gchar *secondary );
 gboolean         base_window_yesno_dlg( BaseWindow *window, GtkMessageType type, const gchar *first, const gchar *second );
 
+void             base_window_signal_connect( BaseWindow *window, GObject *instance, const gchar *signal, GCallback fn );
+void             base_window_signal_connect_by_name( BaseWindow *window, const gchar *name, const gchar *signal, GCallback fn );
+
 G_END_DECLS
 
 #endif /* __BASE_WINDOW_H__ */
diff --git a/src/nact/egg-tree-multi-dnd.c b/src/nact/egg-tree-multi-dnd.c
index 226d785..0352e3c 100644
--- a/src/nact/egg-tree-multi-dnd.c
+++ b/src/nact/egg-tree-multi-dnd.c
@@ -57,11 +57,6 @@
 
 #define EGG_TREE_MULTI_DND_STRING		"EggTreeMultiDndString"
 
-/*static GtkTargetEntry target_table[] = {
-        { "XdndDirectSave0", 0, 0 },
-        { "XdndNautilusActions0", 0, 1 }
-};*/
-
 typedef struct
 {
 	guint    pressed_button;
@@ -89,8 +84,6 @@ static gboolean       on_drag_data_get( GtkWidget *widget, GdkDragContext *conte
 static void           stop_drag_check( GtkWidget *widget );
 static void           selection_foreach( GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, GList **path_list );
 static void           path_list_free( GList *path_list );
-/*static void     set_context_data( GdkDragContext *context, GList *path_list );
-static GList   *get_context_data( GdkDragContext *context );*/
 static void           set_treeview_data( GtkWidget *treeview, GList *path_list );
 static GList         *get_treeview_data( GtkWidget *treeview );
 
@@ -397,7 +390,6 @@ on_motion_event( GtkWidget *widget, GdkEventMotion *event, EggTreeMultiDragSourc
 
 			context = gtk_drag_begin(
 					widget, target_list, actions, priv_data->pressed_button, ( GdkEvent * ) event );
-			/*set_context_data( context, path_list );*/
 
 			set_treeview_data( widget, path_list );
 
@@ -416,7 +408,7 @@ on_motion_event( GtkWidget *widget, GdkEventMotion *event, EggTreeMultiDragSourc
 static gboolean
 on_drag_data_get( GtkWidget *widget, GdkDragContext *context, GtkSelectionData *selection_data, guint info, guint time )
 {
-	static const gchar *thisfn = "on_drag_data_get";
+	static const gchar *thisfn = "egg_tree_multi_dnd_on_drag_data_get";
 	GtkTreeView  *tree_view;
 	GtkTreeModel *model;
 	GList        *path_list;
@@ -429,7 +421,6 @@ on_drag_data_get( GtkWidget *widget, GdkDragContext *context, GtkSelectionData *
 	g_assert( model );
 	g_assert( EGG_IS_TREE_MULTI_DRAG_SOURCE( model ));
 
-	/*path_list = get_context_data( context );*/
 	path_list = get_treeview_data( widget );
 	if( path_list == NULL ){
 		return( FALSE );
@@ -476,20 +467,6 @@ path_list_free( GList *path_list )
 	g_list_free( path_list );
 }
 
-/*static void
-set_context_data( GdkDragContext *context, GList *path_list )
-{
-	g_object_set_data_full(
-			G_OBJECT( context ),
-			"egg-tree-view-multi-source-row", path_list, ( GDestroyNotify ) path_list_free );
-}
-
-static GList *
-get_context_data( GdkDragContext *context )
-{
-	return( g_object_get_data( G_OBJECT( context ), "egg-tree-view-multi-source-row" ));
-}*/
-
 static void
 set_treeview_data( GtkWidget *treeview, GList *path_list )
 {
diff --git a/src/nact/nact-application.c b/src/nact/nact-application.c
index 58d762a..da13609 100644
--- a/src/nact/nact-application.c
+++ b/src/nact/nact-application.c
@@ -36,6 +36,7 @@
 #include <gtk/gtk.h>
 
 #include <common/na-about.h>
+#include <common/na-ipivot-consumer.h>
 
 #include "nact-application.h"
 #include "nact-main-window.h"
@@ -56,10 +57,10 @@ struct NactApplicationPrivate {
 /* private instance properties
  */
 enum {
-	PROP_PIVOT = 1
+	NACT_APPLICATION_PROP_PIVOT_ID = 1
 };
 
-#define PROP_PIVOT_STR					"nact-application-pivot"
+#define NACT_APPLICATION_PROP_PIVOT		"nact-application-pivot"
 
 static BaseApplicationClass *st_parent_class = NULL;
 
@@ -135,23 +136,22 @@ class_init( NactApplicationClass *klass )
 	object_class->set_property = instance_set_property;
 
 	spec = g_param_spec_pointer(
-			PROP_PIVOT_STR,
-			PROP_PIVOT_STR,
+			NACT_APPLICATION_PROP_PIVOT,
+			NACT_APPLICATION_PROP_PIVOT,
 			"NAPivot object pointer",
 			G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE );
-	g_object_class_install_property( object_class, PROP_PIVOT, spec );
+	g_object_class_install_property( object_class, NACT_APPLICATION_PROP_PIVOT_ID, spec );
 
 	klass->private = g_new0( NactApplicationClassPrivate, 1 );
 
 	appli_class = BASE_APPLICATION_CLASS( klass );
-
-	appli_class->application_initialize_unique_app = appli_initialize_unique_app;
-	appli_class->application_initialize_application = appli_initialize_application;
-	appli_class->application_get_application_name = appli_get_application_name;
-	appli_class->application_get_icon_name = appli_get_icon_name;
-	appli_class->application_get_unique_app_name = appli_get_unique_app_name;
-	appli_class->application_get_ui_filename = appli_get_gtkbuilder_filename;
-	appli_class->application_get_main_window = appli_get_main_window;
+	appli_class->initialize_unique_app = appli_initialize_unique_app;
+	appli_class->initialize_application = appli_initialize_application;
+	appli_class->get_application_name = appli_get_application_name;
+	appli_class->get_icon_name = appli_get_icon_name;
+	appli_class->get_unique_app_name = appli_get_unique_app_name;
+	appli_class->get_ui_filename = appli_get_gtkbuilder_filename;
+	appli_class->get_main_window = appli_get_main_window;
 }
 
 static void
@@ -179,7 +179,7 @@ instance_get_property( GObject *object, guint property_id, GValue *value, GParam
 	self = NACT_APPLICATION( object );
 
 	switch( property_id ){
-		case PROP_PIVOT:
+		case NACT_APPLICATION_PROP_PIVOT_ID:
 			g_value_set_pointer( value, self->private->pivot );
 			break;
 
@@ -198,7 +198,7 @@ instance_set_property( GObject *object, guint property_id, const GValue *value,
 	self = NACT_APPLICATION( object );
 
 	switch( property_id ){
-		case PROP_PIVOT:
+		case NACT_APPLICATION_PROP_PIVOT_ID:
 			self->private->pivot = g_value_get_pointer( value );
 			break;
 
@@ -220,14 +220,16 @@ instance_dispose( GObject *application )
 
 	if( !self->private->dispose_has_run ){
 
-		self->private->dispose_has_run = TRUE;
-
 		if( self->private->pivot ){
 			g_object_unref( self->private->pivot );
 		}
 
 		/* chain up to the parent class */
-		G_OBJECT_CLASS( st_parent_class )->dispose( application );
+		if( G_OBJECT_CLASS( st_parent_class )->dispose ){
+			G_OBJECT_CLASS( st_parent_class )->dispose( application );
+		}
+
+		self->private->dispose_has_run = TRUE;
 	}
 }
 
@@ -262,8 +264,8 @@ nact_application_new_with_args( int argc, char **argv )
 	return(
 			g_object_new(
 					NACT_APPLICATION_TYPE,
-					PROP_APPLICATION_ARGC, argc,
-					PROP_APPLICATION_ARGV, argv,
+					BASE_APPLICATION_PROP_ARGC, argc,
+					BASE_APPLICATION_PROP_ARGV, argv,
 					NULL )
 	);
 }
@@ -293,7 +295,7 @@ appli_initialize_unique_app( BaseApplication *application )
 	gchar *msg1, *msg2;
 
 	/* call parent class */
-	ok = st_parent_class->application_initialize_unique_app( application );
+	ok = BASE_APPLICATION_CLASS( st_parent_class )->initialize_unique_app( application );
 
 	if( !ok ){
 		msg1 = g_strdup( _( "Another instance of Nautilus Actions Configuration Tool is already running." ));
@@ -301,8 +303,8 @@ appli_initialize_unique_app( BaseApplication *application )
 		msg2 = g_strdup( _( "Please switch back to it." ));
 
 		g_object_set( G_OBJECT( application ),
-				PROP_APPLICATION_EXIT_MESSAGE1, msg1,
-				PROP_APPLICATION_EXIT_MESSAGE2, msg2,
+				BASE_APPLICATION_PROP_EXIT_MESSAGE1, msg1,
+				BASE_APPLICATION_PROP_EXIT_MESSAGE2, msg2,
 				NULL );
 
 		g_free( msg2 );
@@ -313,18 +315,27 @@ appli_initialize_unique_app( BaseApplication *application )
 }
 
 /*
- * overrided to complete the initialization of the application
- * note that pivot must be initialized _before_ the main window be created
+ * Overrided to complete the initialization of the application:
+ * - allocate the #NApivot here, so that it will be available when the
+ *   #NactMainWindow will require it
+ * - do not register #NactApplication as a NAIPivotConsumer as this is
+ *   essentially the NactMainwindow which will receive and deal with
+ *   NAPivot notification messages
+ *
+ * At last, let the base class do its work, i.e. creating the main window.
  */
 static gboolean
 appli_initialize_application( BaseApplication *application )
 {
+	static const gchar *thisfn = "nact_application_appli_initialize_application";
 	gboolean ok;
 
+	g_debug( "%s: application=%p", thisfn, ( void * ) application );
+
 	NACT_APPLICATION( application )->private->pivot = na_pivot_new( NULL );
 
 	/* call parent class */
-	ok = st_parent_class->application_initialize_application( application );
+	ok = BASE_APPLICATION_CLASS( st_parent_class )->initialize_application( application );
 
 	return( ok );
 }
@@ -380,9 +391,9 @@ appli_get_main_window( BaseApplication *application )
 
 	window = BASE_WINDOW( nact_main_window_new( application ));
 
-	na_pivot_add_consumer(
-			NA_PIVOT( nact_application_get_pivot( NACT_APPLICATION( application ))),
-			G_OBJECT( window ));
+	na_pivot_register_consumer(
+			nact_application_get_pivot( NACT_APPLICATION( application )),
+			NA_IPIVOT_CONSUMER( window ));
 
 	return( G_OBJECT( window ));
 }
diff --git a/src/nact/nact-assistant-export.c b/src/nact/nact-assistant-export.c
index 499dbb0..e29390a 100644
--- a/src/nact/nact-assistant-export.c
+++ b/src/nact/nact-assistant-export.c
@@ -36,15 +36,17 @@
 #include <gtk/gtk.h>
 #include <string.h>
 
+#include <common/na-iprefs.h>
+#include <common/na-object-api.h>
 #include <common/na-utils.h>
 #include <common/na-xml-names.h>
 #include <common/na-xml-writer.h>
 
-#include "base-application.h"
+#include "base-iprefs.h"
+#include "nact-application.h"
 #include "nact-main-window.h"
 #include "nact-assistant-export.h"
 #include "nact-iactions-list.h"
-#include "nact-iprefs.h"
 
 /* Export Assistant
  *
@@ -85,32 +87,35 @@ struct NactAssistantExportPrivate {
 	gint            format;
 };
 
-static GObjectClass *st_parent_class = NULL;
+#define IPREFS_EXPORT_ACTIONS_FOLDER_URI		"export-folder-uri"
+
+static BaseAssistantClass *st_parent_class = NULL;
 
 static GType           register_type( void );
 static void            class_init( NactAssistantExportClass *klass );
 static void            iactions_list_iface_init( NactIActionsListInterface *iface );
+static void            iprefs_iface_init( NAIPrefsInterface *iface );
 static void            instance_init( GTypeInstance *instance, gpointer klass );
 static void            instance_dispose( GObject *application );
 static void            instance_finalize( GObject *application );
 
 static NactAssistantExport *assist_new( BaseApplication *application );
 
-static gchar          *do_get_iprefs_window_id( NactWindow *window );
-static gchar          *do_get_dialog_name( BaseWindow *dialog );
-static GSList         *get_actions( NactWindow *window );
-static void            on_initial_load_dialog( BaseWindow *dialog );
-static void            on_runtime_init_dialog( BaseWindow *dialog );
-static void            on_all_widgets_showed( BaseWindow *dialog );
-static void            on_apply( NactAssistant *window, GtkAssistant *assistant );
-static void            on_prepare( NactAssistant *window, GtkAssistant *assistant, GtkWidget *page );
+static gchar          *window_get_iprefs_window_id( BaseWindow *window );
+static gchar          *window_get_toplevel_name( BaseWindow *dialog );
+
+static void            on_initial_load_dialog( NactAssistantExport *dialog, gpointer user_data );
+static void            on_runtime_init_dialog( NactAssistantExport *dialog, gpointer user_data );
+
+static void            assistant_apply( BaseAssistant *window, GtkAssistant *assistant );
+static void            assistant_prepare( BaseAssistant *window, GtkAssistant *assistant, GtkWidget *page );
 
 static void            assist_initial_load_intro( NactAssistantExport *window, GtkAssistant *assistant );
 static void            assist_runtime_init_intro( NactAssistantExport *window, GtkAssistant *assistant );
 
 static void            assist_initial_load_actions_list( NactAssistantExport *window, GtkAssistant *assistant );
 static void            assist_runtime_init_actions_list( NactAssistantExport *window, GtkAssistant *assistant );
-static void            on_actions_list_selection_changed( NactIActionsList *instance, GSList *selected_items );
+static void            on_iactions_list_selection_changed( NactIActionsList *instance, GSList *selected_items );
 
 static void            assist_initial_load_target_folder( NactAssistantExport *window, GtkAssistant *assistant );
 static void            assist_runtime_init_target_folder( NactAssistantExport *window, GtkAssistant *assistant );
@@ -119,10 +124,10 @@ static void            on_folder_selection_changed( GtkFileChooser *chooser, gpo
 
 static void            assist_initial_load_format( NactAssistantExport *window, GtkAssistant *assistant );
 static void            assist_runtime_init_format( NactAssistantExport *window, GtkAssistant *assistant );
-static void            on_format_toggled( GtkToggleButton *button, gpointer user_data );
-static GtkWidget      *get_gconfschemav1_button( NactWindow *window );
-static GtkWidget      *get_gconfschemav2_button( NactWindow *window );
-static GtkWidget      *get_gconfdump_button( NactWindow *window );
+static void            on_format_toggled( GtkToggleButton *button, NactAssistantExport *window );
+static GtkWidget      *get_gconfschemav1_button( NactAssistantExport *window );
+static GtkWidget      *get_gconfschemav2_button( NactAssistantExport *window );
+static GtkWidget      *get_gconfdump_button( NactAssistantExport *window );
 
 static void            assist_initial_load_confirm( NactAssistantExport *window, GtkAssistant *assistant );
 static void            assist_runtime_init_confirm( NactAssistantExport *window, GtkAssistant *assistant );
@@ -133,7 +138,7 @@ static void            assist_runtime_init_exportdone( NactAssistantExport *wind
 static void            assist_prepare_exportdone( NactAssistantExport *window, GtkAssistant *assistant, GtkWidget *page );
 
 #ifdef NA_MAINTAINER_MODE
-static void              dump( NactAssistantExport *window );
+static void            dump( NactAssistantExport *window );
 #endif
 
 GType
@@ -172,12 +177,20 @@ register_type( void )
 		NULL
 	};
 
+	static const GInterfaceInfo iprefs_iface_info = {
+		( GInterfaceInitFunc ) iprefs_iface_init,
+		NULL,
+		NULL
+	};
+
 	g_debug( "%s", thisfn );
 
-	type = g_type_register_static( NACT_ASSISTANT_TYPE, "NactAssistantExport", &info, 0 );
+	type = g_type_register_static( BASE_ASSISTANT_TYPE, "NactAssistantExport", &info, 0 );
 
 	g_type_add_interface_static( type, NACT_IACTIONS_LIST_TYPE, &iactions_list_iface_info );
 
+	g_type_add_interface_static( type, NA_IPREFS_TYPE, &iprefs_iface_info );
+
 	return( type );
 }
 
@@ -187,8 +200,7 @@ class_init( NactAssistantExportClass *klass )
 	static const gchar *thisfn = "nact_assistant_export_class_init";
 	GObjectClass *object_class;
 	BaseWindowClass *base_class;
-	NactWindowClass *nact_class;
-	NactAssistantClass *assist_class;
+	BaseAssistantClass *assist_class;
 
 	g_debug( "%s: klass=%p", thisfn, ( void * ) klass );
 
@@ -201,17 +213,12 @@ class_init( NactAssistantExportClass *klass )
 	klass->private = g_new0( NactAssistantExportClassPrivate, 1 );
 
 	base_class = BASE_WINDOW_CLASS( klass );
-	base_class->get_toplevel_name = do_get_dialog_name;
-	base_class->initial_load_toplevel = on_initial_load_dialog;
-	base_class->runtime_init_toplevel = on_runtime_init_dialog;
-	base_class->all_widgets_showed = on_all_widgets_showed;
+	base_class->get_toplevel_name = window_get_toplevel_name;
+	base_class->get_iprefs_window_id = window_get_iprefs_window_id;
 
-	nact_class = NACT_WINDOW_CLASS( klass );
-	nact_class->get_iprefs_window_id = do_get_iprefs_window_id;
-
-	assist_class = NACT_ASSISTANT_CLASS( klass );
-	assist_class->on_assistant_apply = on_apply;
-	assist_class->on_assistant_prepare = on_prepare;
+	assist_class = BASE_ASSISTANT_CLASS( klass );
+	assist_class->apply = assistant_apply;
+	assist_class->prepare = assistant_prepare;
 }
 
 static void
@@ -221,8 +228,15 @@ iactions_list_iface_init( NactIActionsListInterface *iface )
 
 	g_debug( "%s: iface=%p", thisfn, ( void * ) iface );
 
-	iface->get_actions = get_actions;
-	iface->on_selection_changed = on_actions_list_selection_changed;
+	iface->selection_changed = on_iactions_list_selection_changed;
+}
+
+static void
+iprefs_iface_init( NAIPrefsInterface *iface )
+{
+	static const gchar *thisfn = "nact_assistant_export_iprefs_iface_init";
+
+	g_debug( "%s: iface=%p", thisfn, ( void * ) iface );
 }
 
 static void
@@ -240,6 +254,18 @@ instance_init( GTypeInstance *instance, gpointer klass )
 	self->private->dispose_has_run = FALSE;
 	self->private->fnames = NULL;
 	self->private->errors = 0;
+
+	base_window_signal_connect(
+			BASE_WINDOW( instance ),
+			G_OBJECT( instance ),
+			BASE_WINDOW_SIGNAL_INITIAL_LOAD,
+			G_CALLBACK( on_initial_load_dialog ));
+
+	base_window_signal_connect(
+			BASE_WINDOW( instance ),
+			G_OBJECT( instance ),
+			BASE_WINDOW_SIGNAL_RUNTIME_INIT,
+			G_CALLBACK( on_runtime_init_dialog ));
 }
 
 static void
@@ -257,7 +283,9 @@ instance_dispose( GObject *window )
 		self->private->dispose_has_run = TRUE;
 
 		/* chain up to the parent class */
-		G_OBJECT_CLASS( st_parent_class )->dispose( window );
+		if( G_OBJECT_CLASS( st_parent_class )->dispose ){
+			G_OBJECT_CLASS( st_parent_class )->dispose( window );
+		}
 	}
 }
 
@@ -278,7 +306,7 @@ instance_finalize( GObject *window )
 	g_free( self->private );
 
 	/* chain call to parent class */
-	if( st_parent_class->finalize ){
+	if( G_OBJECT_CLASS( st_parent_class )->finalize ){
 		G_OBJECT_CLASS( st_parent_class )->finalize( window );
 	}
 }
@@ -286,7 +314,7 @@ instance_finalize( GObject *window )
 static NactAssistantExport *
 assist_new( BaseApplication *application )
 {
-	return( g_object_new( NACT_ASSISTANT_EXPORT_TYPE, PROP_WINDOW_APPLICATION_STR, application, NULL ));
+	return( g_object_new( NACT_ASSISTANT_EXPORT_TYPE, BASE_WINDOW_PROP_APPLICATION, application, NULL ));
 }
 
 /**
@@ -295,15 +323,15 @@ assist_new( BaseApplication *application )
  * @main: the main window of the application.
  */
 void
-nact_assistant_export_run( NactWindow *main_window )
+nact_assistant_export_run( BaseWindow *main_window )
 {
 	BaseApplication *appli;
 	NactAssistantExport *assist;
 
-	appli = BASE_APPLICATION( base_window_get_application( BASE_WINDOW( main_window )));
+	appli = BASE_APPLICATION( base_window_get_application( main_window ));
 
 	assist = assist_new( appli );
-	g_object_set( G_OBJECT( assist ), PROP_WINDOW_PARENT_STR, main_window, NULL );
+	g_object_set( G_OBJECT( assist ), BASE_WINDOW_PROP_PARENT, main_window, NULL );
 
 	assist->private->main_window = NACT_MAIN_WINDOW( main_window );
 
@@ -311,78 +339,56 @@ nact_assistant_export_run( NactWindow *main_window )
 }
 
 static gchar *
-do_get_iprefs_window_id( NactWindow *window )
+window_get_iprefs_window_id( BaseWindow *window )
 {
 	return( g_strdup( "export-assistant" ));
 }
 
 static gchar *
-do_get_dialog_name( BaseWindow *dialog )
+window_get_toplevel_name( BaseWindow *dialog )
 {
 	return( g_strdup( "ExportAssistant" ));
 }
 
-static GSList *
-get_actions( NactWindow *window )
-{
-	return( nact_main_window_get_actions( NACT_ASSISTANT_EXPORT( window )->private->main_window ));
-}
-
 static void
-on_initial_load_dialog( BaseWindow *dialog )
+on_initial_load_dialog( NactAssistantExport *dialog, gpointer user_data )
 {
 	static const gchar *thisfn = "nact_assistant_export_on_initial_load_dialog";
-	NactAssistantExport *window;
 	GtkAssistant *assistant;
 
-	/* call parent class at the very beginning */
-	if( BASE_WINDOW_CLASS( st_parent_class )->initial_load_toplevel ){
-		BASE_WINDOW_CLASS( st_parent_class )->initial_load_toplevel( dialog );
-	}
-
-	g_debug( "%s: dialog=%p", thisfn, ( void * ) dialog );
+	g_debug( "%s: dialog=%p, user_data=%p", thisfn, ( void * ) dialog, ( void * ) user_data );
 	g_assert( NACT_IS_ASSISTANT_EXPORT( dialog ));
-	window = NACT_ASSISTANT_EXPORT( dialog );
 
-	assistant = GTK_ASSISTANT( base_window_get_toplevel_dialog( dialog ));
+	assistant = GTK_ASSISTANT( base_window_get_toplevel_window( BASE_WINDOW( dialog )));
 
-	assist_initial_load_intro( window, assistant );
-	assist_initial_load_actions_list( window, assistant );
-	assist_initial_load_target_folder( window, assistant );
-	assist_initial_load_format( window, assistant );
-	assist_initial_load_confirm( window, assistant );
-	assist_initial_load_exportdone( window, assistant );
+	assist_initial_load_intro( dialog, assistant );
+	assist_initial_load_actions_list( dialog, assistant );
+	assist_initial_load_target_folder( dialog, assistant );
+	assist_initial_load_format( dialog, assistant );
+	assist_initial_load_confirm( dialog, assistant );
+	assist_initial_load_exportdone( dialog, assistant );
+
+	base_assistant_set_cancel_on_esc( BASE_ASSISTANT( dialog ), TRUE );
+	base_assistant_set_warn_on_esc( BASE_ASSISTANT( dialog ), TRUE );
 }
 
 static void
-on_runtime_init_dialog( BaseWindow *dialog )
+on_runtime_init_dialog( NactAssistantExport *dialog, gpointer user_data )
 {
 	static const gchar *thisfn = "nact_assistant_export_on_runtime_init_dialog";
-	NactAssistantExport *window;
 	GtkAssistant *assistant;
 
-	/* call parent class at the very beginning */
-	if( BASE_WINDOW_CLASS( st_parent_class )->runtime_init_toplevel ){
-		BASE_WINDOW_CLASS( st_parent_class )->runtime_init_toplevel( dialog );
-	}
-
-	g_debug( "%s: dialog=%p", thisfn, ( void * ) dialog );
+	g_debug( "%s: dialog=%p, user_data=%p", thisfn, ( void * ) dialog, ( void * ) user_data );
 	g_assert( NACT_IS_ASSISTANT_EXPORT( dialog ));
-	window = NACT_ASSISTANT_EXPORT( dialog );
 
-	assistant = GTK_ASSISTANT( base_window_get_toplevel_dialog( dialog ));
+	assistant = GTK_ASSISTANT( base_window_get_toplevel_window( BASE_WINDOW( dialog )));
 
-	assist_runtime_init_intro( window, assistant );
-	assist_runtime_init_actions_list( window, assistant );
-	assist_runtime_init_target_folder( window, assistant );
-	assist_runtime_init_format( window, assistant );
-	assist_runtime_init_confirm( window, assistant );
-	assist_runtime_init_exportdone( window, assistant );
-}
-
-static void
-on_all_widgets_showed( BaseWindow *dialog )
-{
+	assist_runtime_init_intro( dialog, assistant );
+	assist_runtime_init_actions_list( dialog, assistant );
+	assist_runtime_init_target_folder( dialog, assistant );
+	assist_runtime_init_format( dialog, assistant );
+	assist_runtime_init_confirm( dialog, assistant );
+	assist_runtime_init_exportdone( dialog, assistant );
 }
 
 /*
@@ -391,7 +397,7 @@ on_all_widgets_showed( BaseWindow *dialog )
  * So we provide a general error message.
  */
 static void
-on_apply( NactAssistant *wnd, GtkAssistant *assistant )
+assistant_apply( BaseAssistant *wnd, GtkAssistant *assistant )
 {
 	static const gchar *thisfn = "nact_assistant_export_on_apply";
 	NactAssistantExport *window;
@@ -399,18 +405,18 @@ on_apply( NactAssistant *wnd, GtkAssistant *assistant )
 	gchar *msg = NULL;
 	gchar *reason = NULL;
 	gchar *tmp, *fname;
-	NAAction *action;
+	NAObjectAction *action;
 
 	g_debug( "%s: window=%p, assistant=%p", thisfn, ( void * ) wnd, ( void * ) assistant );
 	g_assert( NACT_IS_ASSISTANT_EXPORT( wnd ));
 	window = NACT_ASSISTANT_EXPORT( wnd );
 
-	actions = nact_iactions_list_get_selected_actions( NACT_WINDOW( window ));
+	actions = nact_iactions_list_get_selected_items( NACT_IACTIONS_LIST( window ));
 
 	g_assert( window->private->uri && strlen( window->private->uri ));
 
 	for( ia = actions ; ia ; ia = ia->next ){
-		action = NA_ACTION( ia->data );
+		action = NA_OBJECT_ACTION( ia->data );
 		fname = na_xml_writer_export( action, window->private->uri, window->private->format, &msg );
 
 		if( fname && strlen( fname )){
@@ -444,7 +450,7 @@ on_apply( NactAssistant *wnd, GtkAssistant *assistant )
 }
 
 static void
-on_prepare( NactAssistant *window, GtkAssistant *assistant, GtkWidget *page )
+assistant_prepare( BaseAssistant *window, GtkAssistant *assistant, GtkWidget *page )
 {
 	/*static const gchar *thisfn = "nact_assistant_export_on_prepare";
 	g_debug( "%s: window=%p, assistant=%p, page=%p", thisfn, window, assistant, page );*/
@@ -486,18 +492,24 @@ static void
 assist_initial_load_actions_list( NactAssistantExport *window, GtkAssistant *assistant )
 {
 	g_assert( NACT_IS_IACTIONS_LIST( window ));
-	nact_iactions_list_initial_load( NACT_WINDOW( window ));
-	nact_iactions_list_set_edition_mode( NACT_WINDOW( window ), FALSE );
-	nact_iactions_list_set_multiple_selection( NACT_WINDOW( window ), TRUE );
-	nact_iactions_list_set_send_selection_changed_on_fill_list( NACT_WINDOW( window ), FALSE );
+	nact_iactions_list_initial_load_toplevel( NACT_IACTIONS_LIST( window ));
+	nact_iactions_list_set_multiple_selection_mode( NACT_IACTIONS_LIST( window ), TRUE );
+	nact_iactions_list_set_only_actions_mode( NACT_IACTIONS_LIST( window ), TRUE );
 }
 
 static void
 assist_runtime_init_actions_list( NactAssistantExport *window, GtkAssistant *assistant )
 {
 	GtkWidget *content;
+	NactApplication *appli;
+	NAPivot *pivot;
+	GSList *tree;
+
+	appli = NACT_APPLICATION( base_window_get_application( BASE_WINDOW( window )));
+	pivot = nact_application_get_pivot( appli );
+	tree = na_pivot_get_items_tree( pivot );
 
-	nact_iactions_list_runtime_init( NACT_WINDOW( window ));
+	nact_iactions_list_runtime_init_toplevel( NACT_IACTIONS_LIST( window ), tree );
 
 	content = gtk_assistant_get_nth_page( assistant, ASSIST_PAGE_ACTIONS_SELECTION );
 
@@ -505,7 +517,7 @@ assist_runtime_init_actions_list( NactAssistantExport *window, GtkAssistant *ass
 }
 
 static void
-on_actions_list_selection_changed( NactIActionsList *instance, GSList *selected_items )
+on_iactions_list_selection_changed( NactIActionsList *instance, GSList *selected_items )
 {
 	/*static const gchar *thisfn = "nact_assistant_export_on_actions_list_selection_changed";
 	g_debug( "%s: selection=%p, user_data=%p", thisfn, selection, user_data );*/
@@ -516,7 +528,7 @@ on_actions_list_selection_changed( NactIActionsList *instance, GSList *selected_
 	GtkWidget *content;
 
 	g_assert( NACT_IS_ASSISTANT_EXPORT( instance ));
-	assistant = GTK_ASSISTANT( base_window_get_toplevel_dialog( BASE_WINDOW( instance )));
+	assistant = GTK_ASSISTANT( base_window_get_toplevel_window( BASE_WINDOW( instance )));
 	pos = gtk_assistant_get_current_page( assistant );
 	if( pos == ASSIST_PAGE_ACTIONS_SELECTION ){
 
@@ -546,13 +558,17 @@ assist_runtime_init_target_folder( NactAssistantExport *window, GtkAssistant *as
 	chooser = get_folder_chooser( window );
 	gtk_file_chooser_unselect_all( chooser );
 
-	uri = nact_iprefs_get_export_folder_uri( NACT_WINDOW( window ));
+	uri = base_iprefs_get_string( BASE_WINDOW( window ), IPREFS_EXPORT_ACTIONS_FOLDER_URI );
 	if( uri && strlen( uri )){
 		gtk_file_chooser_set_uri( GTK_FILE_CHOOSER( chooser ), uri );
 	}
 	g_free( uri );
 
-	nact_window_signal_connect( NACT_WINDOW( window ), G_OBJECT( chooser ), "selection-changed", G_CALLBACK( on_folder_selection_changed ));
+	base_window_signal_connect(
+			BASE_WINDOW( window ),
+			G_OBJECT( chooser ),
+			"selection-changed",
+			G_CALLBACK( on_folder_selection_changed ));
 
 	content = gtk_assistant_get_nth_page( assistant, ASSIST_PAGE_FOLDER_SELECTION );
 	gtk_assistant_set_page_complete( assistant, content, FALSE );
@@ -583,7 +599,7 @@ on_folder_selection_changed( GtkFileChooser *chooser, gpointer user_data )
 	g_debug( "%s: chooser=%p, user_data=%p", thisfn, ( void * ) chooser, ( void * ) user_data );
 	g_assert( NACT_IS_ASSISTANT_EXPORT( user_data ));
 
-	assistant = GTK_ASSISTANT( base_window_get_toplevel_dialog( BASE_WINDOW( user_data )));
+	assistant = GTK_ASSISTANT( base_window_get_toplevel_window( BASE_WINDOW( user_data )));
 	pos = gtk_assistant_get_current_page( assistant );
 	if( pos == ASSIST_PAGE_FOLDER_SELECTION ){
 
@@ -595,7 +611,7 @@ on_folder_selection_changed( GtkFileChooser *chooser, gpointer user_data )
 			assist = NACT_ASSISTANT_EXPORT( user_data );
 			g_free( assist->private->uri );
 			assist->private->uri = g_strdup( uri );
-			nact_iprefs_save_export_folder_uri( NACT_WINDOW( user_data ), uri );
+			base_iprefs_set_string( BASE_WINDOW( user_data ), IPREFS_EXPORT_ACTIONS_FOLDER_URI, uri );
 		}
 
 		g_free( uri );
@@ -617,28 +633,37 @@ assist_runtime_init_format( NactAssistantExport *window, GtkAssistant *assistant
 	GtkWidget *button;
 	GtkWidget *content;
 
-	button = get_gconfschemav1_button( NACT_WINDOW( window ));
-	nact_window_signal_connect( NACT_WINDOW( window ), G_OBJECT( button ), "toggled", G_CALLBACK( on_format_toggled ));
-
-	button = get_gconfschemav2_button( NACT_WINDOW( window ));
-	nact_window_signal_connect( NACT_WINDOW( window ), G_OBJECT( button ), "toggled", G_CALLBACK( on_format_toggled ));
-
-	button = get_gconfdump_button( NACT_WINDOW( window ));
+	button = get_gconfschemav1_button( window );
+	base_window_signal_connect(
+			BASE_WINDOW( window ),
+			G_OBJECT( button ),
+			"toggled",
+			G_CALLBACK( on_format_toggled ));
+
+	button = get_gconfschemav2_button( window );
+	base_window_signal_connect(
+			BASE_WINDOW( window ),
+			G_OBJECT( button ),
+			"toggled",
+			G_CALLBACK( on_format_toggled ));
+
+	button = get_gconfdump_button( window );
 	gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( button ), TRUE );
 	window->private->format = FORMAT_GCONFENTRY;
-	nact_window_signal_connect( NACT_WINDOW( window ), G_OBJECT( button ), "toggled", G_CALLBACK( on_format_toggled ));
+	base_window_signal_connect(
+			BASE_WINDOW( window ),
+			G_OBJECT( button ),
+			"toggled",
+			G_CALLBACK( on_format_toggled ));
 
 	content = gtk_assistant_get_nth_page( assistant, ASSIST_PAGE_FORMAT_SELECTION );
 	gtk_assistant_set_page_complete( assistant, content, TRUE );
 }
 
 static void
-on_format_toggled( GtkToggleButton *button, gpointer user_data )
+on_format_toggled( GtkToggleButton *button, NactAssistantExport *window )
 {
-	NactWindow *window;
-
-	g_assert( NACT_IS_WINDOW( user_data ));
-	window = NACT_WINDOW( user_data );
+	g_assert( NACT_IS_ASSISTANT_EXPORT( window ));
 
 	if( gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON( get_gconfschemav1_button( window )))){
 		NACT_ASSISTANT_EXPORT( window )->private->format = FORMAT_GCONFSCHEMAFILE_V1;
@@ -652,19 +677,19 @@ on_format_toggled( GtkToggleButton *button, gpointer user_data )
 }
 
 static GtkWidget *
-get_gconfschemav1_button( NactWindow *window )
+get_gconfschemav1_button( NactAssistantExport *window )
 {
 	return( base_window_get_widget( BASE_WINDOW( window ), "ExportSchemaV1Button" ));
 }
 
 static GtkWidget *
-get_gconfschemav2_button( NactWindow *window )
+get_gconfschemav2_button( NactAssistantExport *window )
 {
 	return( base_window_get_widget( BASE_WINDOW( window ), "ExportSchemaV2Button" ));
 }
 
 static GtkWidget *
-get_gconfdump_button( NactWindow *window )
+get_gconfdump_button( NactAssistantExport *window )
 {
 	return( base_window_get_widget( BASE_WINDOW( window ), "ExportGConfDumpButton" ));
 }
@@ -700,10 +725,10 @@ assist_prepare_confirm( NactAssistantExport *window, GtkAssistant *assistant, Gt
 	g_free( text );
 	text = tmp;
 
-	actions = nact_iactions_list_get_selected_actions( NACT_WINDOW( window ));
+	actions = nact_iactions_list_get_selected_items( NACT_IACTIONS_LIST( window ));
 
 	for( ia = actions ; ia ; ia = ia->next ){
-		tmp = g_strdup_printf( "%s\t%s\n", text, na_action_get_label( NA_ACTION( ia->data )));
+		tmp = g_strdup_printf( "%s\t%s\n", text, na_object_get_label( ia->data ));
 		g_free( text );
 		text = tmp;
 	}
@@ -721,17 +746,17 @@ assist_prepare_confirm( NactAssistantExport *window, GtkAssistant *assistant, Gt
 	label2 = NULL;
 	switch( window->private->format ){
 		case FORMAT_GCONFSCHEMAFILE_V1:
-			label1 = g_strdup( gtk_button_get_label( GTK_BUTTON( get_gconfschemav1_button( NACT_WINDOW( window )))));
+			label1 = g_strdup( gtk_button_get_label( GTK_BUTTON( get_gconfschemav1_button( window ))));
 			label2 = g_strdup( gtk_label_get_text( GTK_LABEL( base_window_get_widget( BASE_WINDOW( window ), "ExportSchemaV1Label"))));
 			break;
 
 		case FORMAT_GCONFSCHEMAFILE_V2:
-			label1 = g_strdup( gtk_button_get_label( GTK_BUTTON( get_gconfschemav2_button( NACT_WINDOW( window )))));
+			label1 = g_strdup( gtk_button_get_label( GTK_BUTTON( get_gconfschemav2_button( window ))));
 			label2 = g_strdup( gtk_label_get_text( GTK_LABEL( base_window_get_widget( BASE_WINDOW( window ), "ExportSchemaV2Label"))));
 			break;
 
 		case FORMAT_GCONFENTRY:
-			label1 = g_strdup( gtk_button_get_label( GTK_BUTTON( get_gconfdump_button( NACT_WINDOW( window )))));
+			label1 = g_strdup( gtk_button_get_label( GTK_BUTTON( get_gconfdump_button( window ))));
 			label2 = g_strdup( gtk_label_get_text( GTK_LABEL( base_window_get_widget( BASE_WINDOW( window ), "ExportGConfDumpLabel"))));
 			break;
 
@@ -819,7 +844,7 @@ assist_prepare_exportdone( NactAssistantExport *window, GtkAssistant *assistant,
 	g_free( text );
 
 	gtk_assistant_set_page_complete( assistant, page, TRUE );
-	nact_assistant_set_warn_on_cancel( NACT_ASSISTANT( window ), FALSE );
+	base_assistant_set_warn_on_cancel( BASE_ASSISTANT( window ), FALSE );
 }
 
 #ifdef NA_MAINTAINER_MODE
diff --git a/src/nact/nact-assistant-export.h b/src/nact/nact-assistant-export.h
index 52bd2d1..d52c357 100644
--- a/src/nact/nact-assistant-export.h
+++ b/src/nact/nact-assistant-export.h
@@ -60,7 +60,7 @@
  * with v1.10 and previous series, and via gconftool-2 --install-schema-file.
  */
 
-#include "nact-assistant.h"
+#include "base-assistant.h"
 
 G_BEGIN_DECLS
 
@@ -74,7 +74,7 @@ G_BEGIN_DECLS
 typedef struct NactAssistantExportPrivate NactAssistantExportPrivate;
 
 typedef struct {
-	NactAssistant               parent;
+	BaseAssistant               parent;
 	NactAssistantExportPrivate *private;
 }
 	NactAssistantExport;
@@ -82,14 +82,14 @@ typedef struct {
 typedef struct NactAssistantExportClassPrivate NactAssistantExportClassPrivate;
 
 typedef struct {
-	NactAssistantClass               parent;
+	BaseAssistantClass               parent;
 	NactAssistantExportClassPrivate *private;
 }
 	NactAssistantExportClass;
 
 GType nact_assistant_export_get_type( void );
 
-void  nact_assistant_export_run( NactWindow *main );
+void  nact_assistant_export_run( BaseWindow *main );
 
 G_END_DECLS
 
diff --git a/src/nact/nact-assistant-import.c b/src/nact/nact-assistant-import.c
index f8b8372..842fcb6 100644
--- a/src/nact/nact-assistant-import.c
+++ b/src/nact/nact-assistant-import.c
@@ -36,13 +36,15 @@
 #include <gtk/gtk.h>
 #include <string.h>
 
+#include <common/na-object-api.h>
+#include <common/na-obj-action-class.h>
 #include <common/na-iio-provider.h>
 #include <common/na-utils.h>
 
+#include "base-iprefs.h"
 #include "base-application.h"
 #include "nact-assistant-import.h"
 #include "nact-xml-reader.h"
-#include "nact-iprefs.h"
 
 /* Import Assistant
  *
@@ -62,9 +64,9 @@ enum {
 };
 
 typedef struct {
-	gchar    *uri;
-	NAAction *action;
-	GSList   *msg;
+	gchar          *uri;
+	NAObjectAction *action;
+	GSList         *msg;
 }
 	ImportUriStruct;
 
@@ -82,7 +84,9 @@ struct NactAssistantImportPrivate {
 	GSList   *actions;
 };
 
-static GObjectClass *st_parent_class = NULL;
+#define IPREFS_IMPORT_ACTIONS_FOLDER_URI		"import-folder-uri"
+
+static BaseAssistantClass *st_parent_class = NULL;
 
 static GType    register_type( void );
 static void     class_init( NactAssistantImportClass *klass );
@@ -92,15 +96,18 @@ static void     instance_finalize( GObject *application );
 
 static NactAssistantImport *assist_new( BaseApplication *application );
 
-static gchar   *do_get_iprefs_window_id( NactWindow *window );
-static gchar   *do_get_dialog_name( BaseWindow *dialog );
-static void     on_runtime_init_dialog( BaseWindow *dialog );
+static gchar   *window_get_iprefs_window_id( BaseWindow *window );
+static gchar   *window_get_dialog_name( BaseWindow *dialog );
+
+static void     on_runtime_init_dialog( NactAssistantImport *dialog, gpointer user_data );
 static void     runtime_init_intro( NactAssistantImport *window, GtkAssistant *assistant );
 static void     runtime_init_file_selector( NactAssistantImport *window, GtkAssistant *assistant );
 static void     on_file_selection_changed( GtkFileChooser *chooser, gpointer user_data );
 static gboolean has_readable_files( GSList *uris );
-static void     on_apply( NactAssistant *window, GtkAssistant *assistant );
-static void     on_prepare( NactAssistant *window, GtkAssistant *assistant, GtkWidget *page );
+
+static void     assistant_apply( BaseAssistant *window, GtkAssistant *assistant );
+static void     assistant_prepare( BaseAssistant *window, GtkAssistant *assistant, GtkWidget *page );
+
 static void     prepare_confirm( NactAssistantImport *window, GtkAssistant *assistant, GtkWidget *page );
 static void     prepare_importdone( NactAssistantImport *window, GtkAssistant *assistant, GtkWidget *page );
 static void     free_results( GSList *list );
@@ -137,7 +144,7 @@ register_type( void )
 
 	g_debug( "%s", thisfn );
 
-	type = g_type_register_static( NACT_ASSISTANT_TYPE, "NactAssistantImport", &info, 0 );
+	type = g_type_register_static( BASE_ASSISTANT_TYPE, "NactAssistantImport", &info, 0 );
 
 	return( type );
 }
@@ -148,8 +155,7 @@ class_init( NactAssistantImportClass *klass )
 	static const gchar *thisfn = "nact_assistant_import_class_init";
 	GObjectClass *object_class;
 	BaseWindowClass *base_class;
-	NactWindowClass *nact_class;
-	NactAssistantClass *assist_class;
+	BaseAssistantClass *assist_class;
 
 	g_debug( "%s: klass=%p", thisfn, ( void * ) klass );
 
@@ -162,15 +168,12 @@ class_init( NactAssistantImportClass *klass )
 	klass->private = g_new0( NactAssistantImportClassPrivate, 1 );
 
 	base_class = BASE_WINDOW_CLASS( klass );
-	base_class->get_toplevel_name = do_get_dialog_name;
-	base_class->runtime_init_toplevel = on_runtime_init_dialog;
-
-	nact_class = NACT_WINDOW_CLASS( klass );
-	nact_class->get_iprefs_window_id = do_get_iprefs_window_id;
+	base_class->get_toplevel_name = window_get_dialog_name;
+	base_class->get_iprefs_window_id = window_get_iprefs_window_id;
 
-	assist_class = NACT_ASSISTANT_CLASS( klass );
-	assist_class->on_assistant_apply = on_apply;
-	assist_class->on_assistant_prepare = on_prepare;
+	assist_class = BASE_ASSISTANT_CLASS( klass );
+	assist_class->apply = assistant_apply;
+	assist_class->prepare = assistant_prepare;
 }
 
 static void
@@ -188,6 +191,12 @@ instance_init( GTypeInstance *instance, gpointer klass )
 
 	self->private->dispose_has_run = FALSE;
 	self->private->results = NULL;
+
+	base_window_signal_connect(
+			BASE_WINDOW( instance ),
+			G_OBJECT( instance ),
+			BASE_WINDOW_SIGNAL_RUNTIME_INIT,
+			G_CALLBACK( on_runtime_init_dialog ));
 }
 
 static void
@@ -205,7 +214,9 @@ instance_dispose( GObject *window )
 		self->private->dispose_has_run = TRUE;
 
 		/* chain up to the parent class */
-		G_OBJECT_CLASS( st_parent_class )->dispose( window );
+		if( G_OBJECT_CLASS( st_parent_class )->dispose ){
+			G_OBJECT_CLASS( st_parent_class )->dispose( window );
+		}
 	}
 }
 
@@ -224,7 +235,7 @@ instance_finalize( GObject *window )
 	g_free( self->private );
 
 	/* chain call to parent class */
-	if( st_parent_class->finalize ){
+	if( G_OBJECT_CLASS( st_parent_class )->finalize ){
 		G_OBJECT_CLASS( st_parent_class )->finalize( window );
 	}
 }
@@ -232,7 +243,7 @@ instance_finalize( GObject *window )
 static NactAssistantImport *
 assist_new( BaseApplication *application )
 {
-	return( g_object_new( NACT_ASSISTANT_IMPORT_TYPE, PROP_WINDOW_APPLICATION_STR, application, NULL ));
+	return( g_object_new( NACT_ASSISTANT_IMPORT_TYPE, BASE_WINDOW_PROP_APPLICATION, application, NULL ));
 }
 
 /**
@@ -241,16 +252,16 @@ assist_new( BaseApplication *application )
  * @main: the main window of the application.
  */
 GSList *
-nact_assistant_import_run( NactWindow *main_window )
+nact_assistant_import_run( BaseWindow *main_window )
 {
 	BaseApplication *appli;
 	NactAssistantImport *assist;
 
-	appli = BASE_APPLICATION( base_window_get_application( BASE_WINDOW( main_window )));
+	appli = BASE_APPLICATION( base_window_get_application( main_window ));
 
 	assist = assist_new( appli );
 
-	g_object_set( G_OBJECT( assist ), PROP_WINDOW_PARENT_STR, main_window, NULL );
+	g_object_set( G_OBJECT( assist ), BASE_WINDOW_PROP_PARENT, main_window, NULL );
 
 	base_window_run( BASE_WINDOW( assist ));
 
@@ -258,37 +269,30 @@ nact_assistant_import_run( NactWindow *main_window )
 }
 
 static gchar *
-do_get_iprefs_window_id( NactWindow *window )
+window_get_iprefs_window_id( BaseWindow *window )
 {
 	return( g_strdup( "import-assistant" ));
 }
 
 static gchar *
-do_get_dialog_name( BaseWindow *dialog )
+window_get_dialog_name( BaseWindow *dialog )
 {
 	return( g_strdup( "ImportAssistant" ));
 }
 
 static void
-on_runtime_init_dialog( BaseWindow *dialog )
+on_runtime_init_dialog( NactAssistantImport *dialog, gpointer user_data )
 {
 	static const gchar *thisfn = "nact_assistant_import_on_runtime_init_dialog";
-	NactAssistantImport *window;
 	GtkAssistant *assistant;
 
-	/* call parent class at the very beginning */
-	if( BASE_WINDOW_CLASS( st_parent_class )->runtime_init_toplevel ){
-		BASE_WINDOW_CLASS( st_parent_class )->runtime_init_toplevel( dialog );
-	}
-
-	g_debug( "%s: dialog=%p", thisfn, ( void * ) dialog );
+	g_debug( "%s: dialog=%p, user_data=%p", thisfn, ( void * ) dialog, ( void * ) user_data );
 	g_assert( NACT_IS_ASSISTANT_IMPORT( dialog ));
-	window = NACT_ASSISTANT_IMPORT( dialog );
 
-	assistant = GTK_ASSISTANT( base_window_get_toplevel_dialog( dialog ));
+	assistant = GTK_ASSISTANT( base_window_get_toplevel_window( BASE_WINDOW( dialog )));
 
-	runtime_init_intro( window, assistant );
-	runtime_init_file_selector( window, assistant );
+	runtime_init_intro( dialog, assistant );
+	runtime_init_file_selector( dialog, assistant );
 }
 
 static void
@@ -317,13 +321,17 @@ runtime_init_file_selector( NactAssistantImport *window, GtkAssistant *assistant
 	g_debug( "%s: window=%p, assistant=%p, chooser=%p",
 			thisfn, ( void * ) window, ( void * ) assistant, ( void * ) chooser );
 
-	uri = nact_iprefs_get_import_folder_uri( NACT_WINDOW( window ));
+	uri = base_iprefs_get_string( BASE_WINDOW( window ), IPREFS_IMPORT_ACTIONS_FOLDER_URI );
 	if( uri && strlen( uri )){
 		gtk_file_chooser_set_current_folder_uri( GTK_FILE_CHOOSER( chooser ), uri );
 	}
 	g_free( uri );
 
-	nact_window_signal_connect( NACT_WINDOW( window ), G_OBJECT( chooser ), "selection-changed", G_CALLBACK( on_file_selection_changed ));
+	base_window_signal_connect(
+			BASE_WINDOW( window ),
+			G_OBJECT( chooser ),
+			"selection-changed",
+			G_CALLBACK( on_file_selection_changed ));
 
 	gtk_assistant_set_page_complete( assistant, chooser, FALSE );
 }
@@ -342,7 +350,7 @@ on_file_selection_changed( GtkFileChooser *chooser, gpointer user_data )
 	GtkWidget *content;
 
 	g_assert( NACT_IS_ASSISTANT_IMPORT( user_data ));
-	assistant = GTK_ASSISTANT( base_window_get_toplevel_dialog( BASE_WINDOW( user_data )));
+	assistant = GTK_ASSISTANT( base_window_get_toplevel_window( BASE_WINDOW( user_data )));
 	pos = gtk_assistant_get_current_page( assistant );
 	if( pos == ASSIST_PAGE_FILES_SELECTION ){
 
@@ -351,7 +359,7 @@ on_file_selection_changed( GtkFileChooser *chooser, gpointer user_data )
 
 		if( enabled ){
 			folder = gtk_file_chooser_get_current_folder_uri( GTK_FILE_CHOOSER( chooser ));
-			nact_iprefs_save_import_folder_uri( NACT_WINDOW( user_data ), folder );
+			base_iprefs_set_string( BASE_WINDOW( user_data ), IPREFS_IMPORT_ACTIONS_FOLDER_URI, folder );
 			g_free( folder );
 		}
 
@@ -417,13 +425,13 @@ has_readable_files( GSList *uris )
 }
 
 static void
-on_apply( NactAssistant *wnd, GtkAssistant *assistant )
+assistant_apply( BaseAssistant *wnd, GtkAssistant *assistant )
 {
-	static const gchar *thisfn = "nact_assistant_import_on_apply";
+	static const gchar *thisfn = "nact_assistant_import_assistant_apply";
 	NactAssistantImport *window;
 	GtkWidget *chooser;
 	GSList *uris, *is, *msg;
-	NAAction *action;
+	NAObjectAction *action;
 	ImportUriStruct *str;
 
 	g_debug( "%s: window=%p, assistant=%p", thisfn, ( void * ) wnd, ( void * ) assistant );
@@ -436,7 +444,7 @@ on_apply( NactAssistant *wnd, GtkAssistant *assistant )
 	for( is = uris ; is ; is = is->next ){
 
 		msg = NULL;
-		action = nact_xml_reader_import( NACT_WINDOW( window ), ( const gchar * ) is->data, &msg );
+		action = nact_xml_reader_import( BASE_WINDOW( window ), ( const gchar * ) is->data, &msg );
 
 		str = g_new0( ImportUriStruct, 1 );
 		str->uri = g_strdup(( const gchar * ) is->data );
@@ -452,9 +460,9 @@ on_apply( NactAssistant *wnd, GtkAssistant *assistant )
 }
 
 static void
-on_prepare( NactAssistant *window, GtkAssistant *assistant, GtkWidget *page )
+assistant_prepare( BaseAssistant *window, GtkAssistant *assistant, GtkWidget *page )
 {
-	static const gchar *thisfn = "nact_assistant_import_on_prepare";
+	static const gchar *thisfn = "nact_assistant_import_assistant_prepare";
 	GtkAssistantPageType type;
 
 	g_debug( "%s: window=%p, assistant=%p, page=%p",
@@ -541,8 +549,8 @@ prepare_importdone( NactAssistantImport *window, GtkAssistant *assistant, GtkWid
 		g_free( bname );
 
 		if( str->action ){
-			uuid = na_action_get_uuid( str->action );
-			label = na_action_get_label( str->action );
+			uuid = na_object_get_id( str->action );
+			label = na_object_get_label( str->action );
 			/* i18n: this is the globally unique identifier and the label of the newly imported action */
 			text2 = g_strdup_printf( _( "UUID: %s\t%s" ), uuid, label);
 			g_free( label );
@@ -576,7 +584,7 @@ prepare_importdone( NactAssistantImport *window, GtkAssistant *assistant, GtkWid
 	g_free( text );
 
 	gtk_assistant_set_page_complete( assistant, page, TRUE );
-	nact_assistant_set_warn_on_cancel( NACT_ASSISTANT( window ), FALSE );
+	base_assistant_set_warn_on_cancel( BASE_ASSISTANT( window ), FALSE );
 }
 
 static void
diff --git a/src/nact/nact-assistant-import.h b/src/nact/nact-assistant-import.h
index efa1391..0ca3572 100644
--- a/src/nact/nact-assistant-import.h
+++ b/src/nact/nact-assistant-import.h
@@ -35,7 +35,7 @@
  * NactAssistantImport class definition.
  */
 
-#include "nact-assistant.h"
+#include "base-assistant.h"
 
 G_BEGIN_DECLS
 
@@ -49,7 +49,7 @@ G_BEGIN_DECLS
 typedef struct NactAssistantImportPrivate NactAssistantImportPrivate;
 
 typedef struct {
-	NactAssistant               parent;
+	BaseAssistant               parent;
 	NactAssistantImportPrivate *private;
 }
 	NactAssistantImport;
@@ -57,14 +57,14 @@ typedef struct {
 typedef struct NactAssistantImportClassPrivate NactAssistantImportClassPrivate;
 
 typedef struct {
-	NactAssistantClass               parent;
+	BaseAssistantClass               parent;
 	NactAssistantImportClassPrivate *private;
 }
 	NactAssistantImportClass;
 
 GType   nact_assistant_import_get_type( void );
 
-GSList *nact_assistant_import_run( NactWindow *main );
+GSList *nact_assistant_import_run( BaseWindow *main );
 
 G_END_DECLS
 
diff --git a/src/nact/nact-clipboard.c b/src/nact/nact-clipboard.c
new file mode 100644
index 0000000..4ab03a3
--- /dev/null
+++ b/src/nact/nact-clipboard.c
@@ -0,0 +1,398 @@
+/*
+ * 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 <gtk/gtk.h>
+#include <string.h>
+
+#include <common/na-object-api.h>
+#include <common/na-obj-action-class.h>
+#include <common/na-obj-profile.h>
+#include <common/na-xml-names.h>
+#include <common/na-xml-writer.h>
+
+#include "nact-clipboard.h"
+
+#define NACT_CLIPBOARD_ATOM				gdk_atom_intern( "_NACT_CLIPBOARD", FALSE )
+
+#define CLIPBOARD_PROP_PRIMAY_USED		"nact-clipboard-primary-used"
+
+enum {
+	NACT_CLIPBOARD_FORMAT_NACT = 0,
+	NACT_CLIPBOARD_FORMAT_APPLICATION_XML,
+	NACT_CLIPBOARD_FORMAT_TEXT_PLAIN
+};
+
+/* clipboard formats
+ * - a special XdndNautilusAction format for internal move/copy
+ * - a XdndDirectSave, suitable for exporting to a file manager
+ *   (note that Nautilus recognized the "XdndDirectSave0" format as XDS
+ *   protocol)
+ * - a text (xml) format, to go to clipboard or a text editor
+ */
+static GtkTargetEntry clipboard_formats[] = {
+	{ "ClipboardNautilusActions", 0, NACT_CLIPBOARD_FORMAT_NACT },
+	{ "application/xml",          0, NACT_CLIPBOARD_FORMAT_APPLICATION_XML },
+	{ "text/plain",               0, NACT_CLIPBOARD_FORMAT_TEXT_PLAIN },
+};
+
+typedef struct {
+	gboolean only_profiles;
+	GSList  *items;
+}
+	NactClipboardData;
+
+static GtkClipboard *get_clipboard( void );
+static gboolean      have_only_profiles( GSList *items );
+static void          add_item_to_clipboard0( NAObject *object, gboolean copy_data, gboolean only_profiles, GSList **copied );
+static void          add_item_to_clipboard( NAObject *object, GSList **copied );
+static void          export_action( const gchar *uri, const NAObject *action, GSList **exported );
+static gchar        *get_action_xml_buffer( const NAObject *action, GSList **exported );
+static void          get_from_clipboard_callback( GtkClipboard *clipboard, GtkSelectionData *selection_data, guint info, NactClipboardData *data );
+static void          clear_clipboard_callback( GtkClipboard *clipboard, NactClipboardData *data );
+
+/**
+ * nact_clipboard_get_data_for_intern_use:
+ *
+ * Set the selected items into our custom clipboard.
+ *
+ * Note that we take a copy of the selected items, so that we will be
+ * able to paste them when needed.
+ */
+void
+nact_clipboard_get_data_for_intern_use( GSList *selected_items, gboolean copy_data )
+{
+	static const gchar *thisfn = "nact_clipboard_get_data_for_intern_use";
+	GtkClipboard *clipboard;
+	NactClipboardData *data;
+	GSList *item;
+
+	clipboard = get_clipboard();
+
+	data = g_new0( NactClipboardData, 1 );
+	data->only_profiles = have_only_profiles( selected_items );
+
+	for( item = selected_items ; item ; item = item->next ){
+		NAObject *item_object = NA_OBJECT( item->data );
+		add_item_to_clipboard0( item_object, copy_data, data->only_profiles, &data->items );
+	}
+	data->items = g_slist_reverse( data->items );
+
+	gtk_clipboard_set_with_data( clipboard,
+			clipboard_formats, G_N_ELEMENTS( clipboard_formats ),
+			( GtkClipboardGetFunc ) get_from_clipboard_callback,
+			( GtkClipboardClearFunc ) clear_clipboard_callback,
+			data );
+
+	g_object_set_data( G_OBJECT( clipboard ), CLIPBOARD_PROP_PRIMAY_USED, GINT_TO_POINTER( TRUE ));
+	g_debug( "%s: clipboard=%p, data=%p", thisfn, ( void * ) clipboard, ( void * ) data );
+}
+
+/**
+ * Get text/plain from selected actions.
+ *
+ * This is called when we drop or paste a selection onto an application
+ * willing to deal with Xdnd protocol, for text/plain or application/xml
+ * mime types.
+ *
+ * Selected items may include menus, actions and profiles.
+ * For now, we only exports actions as XML files.
+ */
+char *
+nact_clipboard_get_data_for_extern_use( GSList *selected_items )
+{
+	GSList *item;
+	GSList *exported = NULL;
+	GString *data;
+	gchar *chunk;
+
+	data = g_string_new( "" );
+
+	for( item = selected_items ; item ; item = item->next ){
+		NAObject *item_object = NA_OBJECT( item->data );
+		chunk = NULL;
+
+		if( NA_IS_OBJECT_ACTION( item_object )){
+			chunk = get_action_xml_buffer( item_object, &exported );
+
+		} else if( NA_IS_OBJECT_PROFILE( item_object )){
+			NAObjectAction *action = na_object_profile_get_action( NA_OBJECT_PROFILE( item_object ));
+			chunk = get_action_xml_buffer( NA_OBJECT( action ), &exported );
+		}
+
+		if( chunk && strlen( chunk )){
+			data = g_string_append( data, chunk );
+		}
+		g_free( chunk );
+	}
+
+	g_slist_free( exported );
+	return( g_string_free( data, FALSE ));
+}
+
+/**
+ * Exports selected actions.
+ *
+ * This is called when we drop or paste a selection onto an application
+ * willing to deal with XdndDirectSave (XDS) protocol.
+ *
+ * Selected items may include menus, actions and profiles.
+ * For now, we only exports actions as XML files.
+ */
+void
+nact_clipboard_export_items( const gchar *uri, GSList *items )
+{
+	GSList *item;
+	GSList *exported = NULL;
+
+	for( item = items ; item ; item = item->next ){
+		NAObject *item_object = NA_OBJECT( item->data );
+
+		if( NA_IS_OBJECT_ACTION( item_object )){
+			export_action( uri, item_object, &exported );
+
+		} else if( NA_IS_OBJECT_PROFILE( item_object )){
+			NAObjectAction *action = na_object_profile_get_action( NA_OBJECT_PROFILE( item_object ));
+			export_action( uri, NA_OBJECT( action ), &exported );
+		}
+	}
+
+	g_slist_free( exported );
+}
+
+/**
+ * nact_clipboard_is_empty:
+ *
+ * This is called to know if we can enable paste item in the menubar.
+ */
+gboolean
+nact_clipboard_is_empty( void )
+{
+	GtkClipboard *clipboard;
+	gboolean used;
+	gpointer data;
+
+	clipboard = get_clipboard();
+	data = g_object_get_data( G_OBJECT( clipboard ), CLIPBOARD_PROP_PRIMAY_USED );
+	used = ( gboolean ) GPOINTER_TO_INT( data );
+	/*g_debug( "nact_clipboard_is_empty: used=%s", used ? "True":"False" );*/
+
+	return( !used );
+}
+
+/**
+ * nact_clipboard_get:
+ *
+ * Returns: the list of items previously referenced in the internal
+ * clipboard.
+ *
+ * The list is owned by the clipboard, and should not be g_free() nor
+ * g_object_unref() by the caller.
+ */
+GSList *
+nact_clipboard_get( void )
+{
+	GtkClipboard *clipboard;
+	GtkSelectionData *selection;
+	NactClipboardData *data;
+	GSList *items;
+
+	if( nact_clipboard_is_empty()){
+		return( NULL );
+	}
+
+	clipboard = get_clipboard();
+	selection = gtk_clipboard_wait_for_contents( clipboard, GDK_SELECTION_PRIMARY );
+	data = ( NactClipboardData * ) selection->data;
+
+	/* prepare the next paste by renumeroting the ids */
+	/*for( it = items ; it ; it = it->next ){
+		na_object_set_new_id( it->data );
+	}*/
+
+	return( data->items );
+}
+
+/**
+ * nact_clipboard_set:
+ * @items: a list of #NAObject items
+ *
+ * Takes a reference on the specified list of items, and installs them
+ * in the internal clipboard.
+ */
+void
+nact_clipboard_set( GSList *items )
+{
+	GtkClipboard *clipboard;
+	NactClipboardData *data;
+	GSList *it;
+
+	clipboard = get_clipboard();
+
+	gtk_clipboard_clear( clipboard );
+
+	data = g_new0( NactClipboardData, 1 );
+	data->only_profiles = have_only_profiles( items );
+
+	for( it = items ; it ; it = it->next ){
+		add_item_to_clipboard( NA_OBJECT( it->data ), &data->items );
+	}
+	data->items = g_slist_reverse( data->items );
+
+	gtk_clipboard_set_with_data( clipboard,
+			clipboard_formats, G_N_ELEMENTS( clipboard_formats ),
+			( GtkClipboardGetFunc ) get_from_clipboard_callback,
+			( GtkClipboardClearFunc ) clear_clipboard_callback,
+			data );
+
+	g_object_set_data( G_OBJECT( clipboard ), CLIPBOARD_PROP_PRIMAY_USED, GINT_TO_POINTER( TRUE ));
+}
+
+static GtkClipboard *
+get_clipboard( void )
+{
+	GdkDisplay *display;
+	GtkClipboard *clipboard;
+
+	display = gdk_display_get_default();
+	clipboard = gtk_clipboard_get_for_display( display, GDK_SELECTION_PRIMARY );
+
+	return( clipboard );
+}
+
+static gboolean
+have_only_profiles( GSList *items )
+{
+	GSList *item;
+	gboolean only_profiles = TRUE;
+
+	for( item = items ; item ; item = item->next ){
+		if( !NA_IS_OBJECT_PROFILE( item->data )){
+			only_profiles = FALSE;
+			break;
+		}
+	}
+
+	return( only_profiles );
+}
+
+static void
+add_item_to_clipboard0( NAObject *object, gboolean copy_data, gboolean only_profiles, GSList **items_list )
+{
+	NAObject *source;
+	gint index;
+
+	source = object;
+	if( !only_profiles && NA_IS_OBJECT_PROFILE( object )){
+		source = NA_OBJECT( na_object_profile_get_action( NA_OBJECT_PROFILE( object )));
+	}
+
+	index = g_slist_index( *items_list, ( gconstpointer ) source );
+	if( index != -1 ){
+		return;
+	}
+
+	*items_list = g_slist_prepend( *items_list, na_object_ref( source ));
+}
+
+static void
+add_item_to_clipboard( NAObject *object, GSList **items_list )
+{
+	*items_list = g_slist_prepend( *items_list, na_object_ref( object ));
+}
+
+static void
+export_action( const gchar *uri, const NAObject *action, GSList **exported )
+{
+	gint index;
+	gchar *fname, *buffer;
+
+	index = g_slist_index( *exported, ( gconstpointer ) action );
+	if( index != -1 ){
+		return;
+	}
+
+	fname = na_xml_writer_get_output_fname( NA_OBJECT_ACTION( action ), uri, FORMAT_GCONFENTRY );
+	buffer = na_xml_writer_get_xml_buffer( NA_OBJECT_ACTION( action ), FORMAT_GCONFENTRY );
+
+	na_xml_writer_output_xml( buffer, fname );
+
+	g_free( buffer );
+	g_free( fname );
+
+	*exported = g_slist_prepend( *exported, ( gpointer ) action );
+}
+
+static gchar *
+get_action_xml_buffer( const NAObject *action, GSList **exported )
+{
+	gint index;
+	gchar *buffer;
+
+	index = g_slist_index( *exported, ( gconstpointer ) action );
+	if( index != -1 ){
+		return( NULL );
+	}
+
+	buffer = na_xml_writer_get_xml_buffer( NA_OBJECT_ACTION( action ), FORMAT_GCONFENTRY );
+
+	*exported = g_slist_prepend( *exported, ( gpointer ) action );
+
+	return( buffer );
+}
+
+static void
+get_from_clipboard_callback( GtkClipboard *clipboard, GtkSelectionData *selection_data, guint info, NactClipboardData *data )
+{
+	static const gchar *thisfn = "nact_clipboard_get_from_clipboard_callback";
+
+	g_debug( "%s: clipboard=%p, selection_data=%p, target=%s, info=%d, data=%p",
+			thisfn, ( void * ) clipboard,
+			( void * ) selection_data, gtk_atom_name( selection_data->target ), info, ( void * ) data );
+
+	gtk_selection_data_set( selection_data, selection_data->target, 8, data, sizeof( NactClipboardData ));
+}
+
+static void
+clear_clipboard_callback( GtkClipboard *clipboard, NactClipboardData *data )
+{
+	static const gchar *thisfn = "nact_clipboard_clear_clipboard_callback";
+
+	g_debug( "%s: clipboard=%p, data=%p", thisfn, ( void * ) clipboard, ( void * ) data );
+
+	g_slist_foreach( data->items, ( GFunc ) g_object_unref, NULL );
+	g_slist_free( data->items );
+	g_free( data );
+
+	g_object_set_data( G_OBJECT( clipboard ), CLIPBOARD_PROP_PRIMAY_USED, GINT_TO_POINTER( FALSE ));
+}
diff --git a/src/nact/nact-selection.h b/src/nact/nact-clipboard.h
similarity index 70%
copy from src/nact/nact-selection.h
copy to src/nact/nact-clipboard.h
index 0ac54c6..dbffec8 100644
--- a/src/nact/nact-selection.h
+++ b/src/nact/nact-clipboard.h
@@ -28,18 +28,24 @@
  *   ... and many others (see AUTHORS)
  */
 
-#ifndef __NACT_DND_H__
-#define __NACT_DND_H__
+#ifndef __NACT_CLIPBOARD_H__
+#define __NACT_CLIPBOARD_H__
 
 #include <glib.h>
 
 G_BEGIN_DECLS
 
-char *nact_selection_get_data_for_intern_use( GSList *selected_items );
-char *nact_selection_get_data_for_extern_use( GSList *selected_items );
+void     nact_clipboard_get_data_for_intern_use( GSList *selected_items, gboolean copy_data );
+char    *nact_clipboard_get_data_for_extern_use( GSList *selected_items );
 
-void  nact_selection_export_items( const gchar *uri, GSList *items );
+gboolean nact_clipboard_is_empty( void );
+GSList  *nact_clipboard_get( void );
+void     nact_clipboard_set( GSList *items );
+
+void     nact_clipboard_free_items( GSList *items );
+
+void     nact_clipboard_export_items( const gchar *uri, GSList *items );
 
 G_END_DECLS
 
-#endif /* __NACT_DND_H__ */
+#endif /* __NACT_CLIPBOARD_H__ */
diff --git a/src/nact/nact-iaction-tab.c b/src/nact/nact-iaction-tab.c
index 06a8308..6555585 100644
--- a/src/nact/nact-iaction-tab.c
+++ b/src/nact/nact-iaction-tab.c
@@ -35,8 +35,13 @@
 #include <glib/gi18n.h>
 #include <string.h>
 
+#include <common/na-object-api.h>
+#include <common/na-obj-action-class.h>
+
+#include "base-window.h"
 #include "nact-application.h"
-#include "nact-statusbar.h"
+#include "nact-main-statusbar.h"
+#include "nact-main-tab.h"
 #include "nact-iaction-tab.h"
 
 /* private interface data
@@ -53,30 +58,28 @@ enum {
 	ICON_N_COLUMN
 };
 
-/* IActionTab properties, set on the main window
+/* IActionTab properties, set against the GObject instance
  */
-#define PROP_IACTION_TAB_STATUS_CONTEXT	"nact-iaction-tab-status-context"
+#define IACTION_TAB_PROP_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 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          set_label_label( NactWindow *window, const gchar *color );
-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 );
-static void          icon_combo_list_fill( GtkComboBoxEntry* combo );
+static void          on_tab_updatable_selection_updated( NactIActionTab *instance, gint count_selected );
+static void          check_for_label( NactIActionTab *instance, GtkEntry *entry, const gchar *label );
 static GtkTreeModel *create_stock_icon_model( void );
+static void          display_icon( NactIActionTab *instance, GtkWidget *image, gboolean display );
+static GtkButton    *get_enabled_button( NactIActionTab *instance );
+static void          icon_combo_list_fill( GtkComboBoxEntry* combo );
+static void          on_enabled_toggled( GtkToggleButton *button, NactIActionTab *instance );
+static void          on_icon_browse( GtkButton *button, NactIActionTab *instance );
+static void          on_icon_changed( GtkEntry *entry, NactIActionTab *instance );
+static void          on_label_changed( GtkEntry *entry, NactIActionTab *instance );
+static void          on_tooltip_changed( GtkEntry *entry, NactIActionTab *instance );
+static void          set_label_label( NactIActionTab *instance, const gchar *color );
 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          on_enabled_toggled( GtkToggleButton *button, gpointer user_data );
-static GtkButton    *get_enabled_button( NactWindow *window );
 
 GType
 nact_iaction_tab_get_type( void )
@@ -112,7 +115,7 @@ register_type( void )
 
 	type = g_type_register_static( G_TYPE_INTERFACE, "NactIActionTab", &info, 0 );
 
-	g_type_interface_add_prerequisite( type, NACT_WINDOW_TYPE );
+	g_type_interface_add_prerequisite( type, BASE_WINDOW_TYPE );
 
 	return( type );
 }
@@ -128,9 +131,6 @@ interface_base_init( NactIActionTabInterface *klass )
 
 		klass->private = g_new0( NactIActionTabInterfacePrivate, 1 );
 
-		klass->get_edited_action = NULL;
-		klass->field_modified = NULL;
-
 		initialized = TRUE;
 	}
 }
@@ -151,300 +151,336 @@ interface_base_finalize( NactIActionTabInterface *klass )
 }
 
 void
-nact_iaction_tab_initial_load( NactWindow *dialog )
+nact_iaction_tab_initial_load_toplevel( NactIActionTab *instance )
 {
-	static const gchar *thisfn = "nact_iaction_tab_initial_load";
+	static const gchar *thisfn = "nact_iaction_tab_initial_load_toplevel";
 	GtkWidget *icon_widget;
 
-	g_debug( "%s: dialog=%p", thisfn, ( void * ) dialog );
+	g_debug( "%s: instance=%p", thisfn, ( void * ) instance );
 
-	icon_widget = base_window_get_widget( BASE_WINDOW( dialog ), "ActionIconComboBoxEntry" );
+	icon_widget = base_window_get_widget( BASE_WINDOW( instance ), "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 ));
 }
 
 void
-nact_iaction_tab_runtime_init( NactWindow *dialog )
+nact_iaction_tab_runtime_init_toplevel( NactIActionTab *instance )
 {
-	static const gchar *thisfn = "nact_iaction_tab_runtime_init";
+	static const gchar *thisfn = "nact_iaction_tab_runtime_init_toplevel";
 	GtkWidget *label_widget, *tooltip_widget, *icon_widget;
 	GtkWidget *button;
 	GtkButton *enabled_button;
 
-	g_debug( "%s: dialog=%p", thisfn, ( void * ) dialog );
-
-	label_widget = base_window_get_widget( BASE_WINDOW( dialog ), "ActionLabelEntry" );
-	nact_window_signal_connect( dialog, G_OBJECT( label_widget ), "changed", G_CALLBACK( on_label_changed ));
-
-	tooltip_widget = base_window_get_widget( BASE_WINDOW( dialog ), "ActionTooltipEntry" );
-	nact_window_signal_connect( dialog, G_OBJECT( tooltip_widget ), "changed", G_CALLBACK( on_tooltip_changed ));
-
-	icon_widget = base_window_get_widget( BASE_WINDOW( dialog ), "ActionIconComboBoxEntry" );
-	nact_window_signal_connect( dialog, G_OBJECT( GTK_BIN( icon_widget )->child ), "changed", G_CALLBACK( on_icon_changed ));
-
-	button = base_window_get_widget( BASE_WINDOW( dialog ), "ActionIconBrowseButton" );
-	nact_window_signal_connect( dialog, G_OBJECT( button ), "clicked", G_CALLBACK( on_icon_browse ));
-
-	enabled_button = get_enabled_button( dialog );
-	nact_window_signal_connect( dialog, G_OBJECT( enabled_button ), "toggled", G_CALLBACK( on_enabled_toggled ));
+	g_debug( "%s: instance=%p", thisfn, ( void * ) instance );
+
+	label_widget = base_window_get_widget( BASE_WINDOW( instance ), "ActionLabelEntry" );
+	g_signal_connect(
+			G_OBJECT( label_widget ),
+			"changed",
+			G_CALLBACK( on_label_changed ),
+			instance );
+
+	tooltip_widget = base_window_get_widget( BASE_WINDOW( instance ), "ActionTooltipEntry" );
+	g_signal_connect(
+			G_OBJECT( tooltip_widget ),
+			"changed",
+			G_CALLBACK( on_tooltip_changed ),
+			instance );
+
+	icon_widget = base_window_get_widget( BASE_WINDOW( instance ), "ActionIconComboBoxEntry" );
+	g_signal_connect(
+			G_OBJECT( GTK_BIN( icon_widget )->child ),
+			"changed",
+			G_CALLBACK( on_icon_changed ),
+			instance );
+
+	button = base_window_get_widget( BASE_WINDOW( instance ), "ActionIconBrowseButton" );
+	g_signal_connect(
+			G_OBJECT( button ),
+			"clicked",
+			G_CALLBACK( on_icon_browse ),
+			instance );
+
+	enabled_button = get_enabled_button( instance );
+	g_signal_connect(
+			G_OBJECT( enabled_button ),
+			"toggled",
+			G_CALLBACK( on_enabled_toggled ),
+			instance );
+
+	g_signal_connect(
+			G_OBJECT( instance ),
+			TAB_UPDATABLE_SIGNAL_SELECTION_UPDATED,
+			G_CALLBACK( on_tab_updatable_selection_updated ),
+			instance );
 }
 
-/**
- * A good place to set focus to the first visible field.
- */
 void
-nact_iaction_tab_all_widgets_showed( NactWindow *dialog )
+nact_iaction_tab_all_widgets_showed( NactIActionTab *instance )
 {
 	static const gchar *thisfn = "nact_iaction_tab_all_widgets_showed";
 
-	g_debug( "%s: dialog=%p", thisfn, ( void * ) dialog );
+	g_debug( "%s: instance=%p", thisfn, ( void * ) instance );
 }
 
 void
-nact_iaction_tab_dispose( NactWindow *dialog )
+nact_iaction_tab_dispose( NactIActionTab *instance )
 {
 	static const gchar *thisfn = "nact_iaction_tab_dispose";
 
-	g_debug( "%s: dialog=%p", thisfn, ( void * ) dialog );
+	g_debug( "%s: instance=%p", thisfn, ( void * ) instance );
 }
 
-/*
- * disable the tab if current row is a profile and the action has more
- * than one profile
+/**
+ * nact_iaction_tab_has_label:
+ * @window: this #NactIActionTab instance.
+ *
+ * An action or a menu can only be written if it has at least a label.
+ *
+ * Returns %TRUE if the label of the action or of the menu is not empty.
  */
-void
-nact_iaction_tab_set_action( NactWindow *dialog, const NAAction *action, GSList *selected_items )
+gboolean
+nact_iaction_tab_has_label( NactIActionTab *instance )
 {
-	static const gchar *thisfn = "nact_iaction_tab_set_action";
-	NAObject *current;
-	gboolean enabled;
-	GtkWidget *label_widget, *tooltip_widget, *icon_widget, *button;
+	GtkWidget *label_widget;
+	const gchar *label;
+
+	label_widget = base_window_get_widget( BASE_WINDOW( instance ), "ActionLabelEntry" );
+	label = gtk_entry_get_text( GTK_ENTRY( label_widget ));
+	return( g_utf8_strlen( label, -1 ) > 0 );
+}
+
+static void
+on_tab_updatable_selection_updated( NactIActionTab *instance, gint count_selected )
+{
+	static const gchar *thisfn = "nact_iaction_tab_on_tab_updatable_selection_updated";
+	NAObjectItem *item;
+	GtkWidget *label_widget, *tooltip_widget, *icon_widget, *button, *group_title;
 	gchar *label, *tooltip, *icon;
 	GtkButton *enabled_button;
 	gboolean enabled_action;
+	gboolean enabled_tab;
 
-	g_debug( "%s: dialog=%p, action=%p, selected_items=%p",
-			thisfn, ( void * ) dialog, ( void * ) action, ( void * ) selected_items );
+	g_debug( "%s: instance=%p, count_selected=%d", thisfn, ( void * ) instance, count_selected );
+	g_return_if_fail( BASE_IS_WINDOW( instance ));
 
-	enabled = ( action != NULL && selected_items != NULL && g_slist_length( selected_items ) == 1 );
-	if( enabled ){
-		current = NA_OBJECT( selected_items->data );
-		if( NA_IS_ACTION_PROFILE( current)){
-			if( na_action_get_profiles_count( action ) > 1 ){
-				enabled = FALSE;
-			}
-		}
-	}
+	g_object_get(
+			G_OBJECT( instance ),
+			TAB_UPDATABLE_PROP_EDITED_ACTION, &item,
+			NULL );
+
+	g_return_if_fail( !item || NA_IS_OBJECT_ITEM( item ));
+
+	enabled_tab = ( count_selected == 1 );
 
-	label_widget = base_window_get_widget( BASE_WINDOW( dialog ), "ActionLabelEntry" );
-	label = action ? na_action_get_label( action ) : g_strdup( "" );
+	label_widget = base_window_get_widget( BASE_WINDOW( instance ), "ActionLabelEntry" );
+	label = item ? na_object_get_label( item ) : g_strdup( "" );
 	gtk_entry_set_text( GTK_ENTRY( label_widget ), label );
-	gtk_widget_set_sensitive( label_widget, enabled );
-	if( action ){
-		check_for_label( dialog, GTK_ENTRY( label_widget ), label );
+	gtk_widget_set_sensitive( label_widget, enabled_tab );
+	if( item ){
+		check_for_label( instance, GTK_ENTRY( label_widget ), label );
 	}
 	g_free( label );
 
-	tooltip_widget = base_window_get_widget( BASE_WINDOW( dialog ), "ActionTooltipEntry" );
-	tooltip = action ? na_action_get_tooltip( action ) : g_strdup( "" );
+	tooltip_widget = base_window_get_widget( BASE_WINDOW( instance ), "ActionTooltipEntry" );
+	tooltip = item ? na_object_get_tooltip( item ) : g_strdup( "" );
 	gtk_entry_set_text( GTK_ENTRY( tooltip_widget ), tooltip );
-	gtk_widget_set_sensitive( tooltip_widget, enabled );
+	gtk_widget_set_sensitive( tooltip_widget, enabled_tab );
 	g_free( tooltip );
 
-	icon_widget = base_window_get_widget( BASE_WINDOW( dialog ), "ActionIconComboBoxEntry" );
-	icon = action ? na_action_get_icon( action ) : g_strdup( "" );
+	icon_widget = base_window_get_widget( BASE_WINDOW( instance ), "ActionIconComboBoxEntry" );
+	icon = item ? na_object_get_icon( item ) : g_strdup( "" );
 	gtk_entry_set_text( GTK_ENTRY( GTK_BIN( icon_widget )->child ), icon );
-	gtk_widget_set_sensitive( icon_widget, enabled );
+	gtk_widget_set_sensitive( icon_widget, enabled_tab );
 	g_free( icon );
 
-	button = base_window_get_widget( BASE_WINDOW( dialog ), "ActionIconBrowseButton" );
-	gtk_widget_set_sensitive( button, enabled );
+	button = base_window_get_widget( BASE_WINDOW( instance ), "ActionIconBrowseButton" );
+	gtk_widget_set_sensitive( button, enabled_tab );
 
-	enabled_button = get_enabled_button( dialog );
-	enabled_action = action ? na_action_is_enabled( action ) : FALSE;
+	group_title = base_window_get_widget( BASE_WINDOW( instance ), "ActionPropertiesGroupTitle" );
+	if( NA_IS_OBJECT_MENU( item )){
+		gtk_label_set_markup( GTK_LABEL( group_title ), _( "<b>Menu properties</b>" ));
+	} else {
+		gtk_label_set_markup( GTK_LABEL( group_title ), _( "<b>Action properties</b>" ));
+	}
+
+	enabled_button = get_enabled_button( instance );
+	enabled_action = item ? na_object_is_enabled( NA_OBJECT_ITEM( item )) : FALSE;
 	gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( enabled_button ), enabled_action );
-	gtk_widget_set_sensitive( GTK_WIDGET( enabled_button ), enabled );
+	gtk_widget_set_sensitive( GTK_WIDGET( enabled_button ), enabled_tab && NA_IS_OBJECT_ACTION( item ));
+
+	/* TODO: manage read-only flag */
 }
 
-/**
- * An action can only be written if it has at least a label.
- * Returns TRUE if the label of the action is not empty.
- */
-gboolean
-nact_iaction_tab_has_label( NactWindow *window )
+static void
+check_for_label( NactIActionTab *instance, GtkEntry *entry, const gchar *label )
 {
-	GtkWidget *label_widget;
-	const gchar *label;
+	NAObjectItem *edited;
 
-	label_widget = base_window_get_widget( BASE_WINDOW( window ), "ActionLabelEntry" );
-	label = gtk_entry_get_text( GTK_ENTRY( label_widget ));
-	return( g_utf8_strlen( label, -1 ) > 0 );
-}
+	g_return_if_fail( NACT_IS_IACTION_TAB( instance ));
+	g_return_if_fail( GTK_IS_ENTRY( entry ));
 
-static NAAction *
-v_get_edited_action( NactWindow *window )
-{
-	g_assert( NACT_IS_IACTION_TAB( window ));
+	nact_main_statusbar_hide_status(
+			NACT_MAIN_WINDOW( instance ),
+			IACTION_TAB_PROP_STATUS_CONTEXT );
 
-	if( NACT_IACTION_TAB_GET_INTERFACE( window )->get_edited_action ){
-		return( NACT_IACTION_TAB_GET_INTERFACE( window )->get_edited_action( window ));
-	}
+	set_label_label( instance, "black" );
 
-	return( NULL );
-}
+	g_object_get(
+			G_OBJECT( instance ),
+			TAB_UPDATABLE_PROP_EDITED_ACTION, &edited,
+			NULL );
 
-static void
-v_field_modified( NactWindow *window )
-{
-	g_assert( NACT_IS_IACTION_TAB( window ));
+	if( edited && g_utf8_strlen( label, -1 ) == 0 ){
+
+		/* i18n: status bar message when the action label is empty */
+		nact_main_statusbar_display_status(
+				NACT_MAIN_WINDOW( instance ),
+				IACTION_TAB_PROP_STATUS_CONTEXT,
+				_( "Caution: a label is mandatory for the action or the menu." ));
 
-	if( NACT_IACTION_TAB_GET_INTERFACE( window )->field_modified ){
-		NACT_IACTION_TAB_GET_INTERFACE( window )->field_modified( window );
+		set_label_label( instance, "red" );
 	}
 }
 
-static void
-on_label_changed( GtkEntry *entry, gpointer user_data )
+static GtkTreeModel *
+create_stock_icon_model( void )
 {
-	NactWindow *dialog;
-	NAAction *edited;
-	const gchar *label;
+	GtkStockItem stock_item;
+	gchar* label;
+	GtkListStore *model;
+	GtkTreeIter row;
+	GSList *stock_list, *iter;
+	GtkIconTheme *icon_theme;
+	GtkIconInfo *icon_info;
 
-	g_assert( NACT_IS_WINDOW( user_data ));
-	dialog = NACT_WINDOW( user_data );
+	model = gtk_list_store_new( ICON_N_COLUMN, G_TYPE_STRING, G_TYPE_STRING );
 
-	edited = v_get_edited_action( dialog );
+	gtk_list_store_append( model, &row );
 
-	if( edited ){
-		label = gtk_entry_get_text( entry );
-		na_action_set_label( edited, label );
-		v_field_modified( dialog );
-		check_for_label( dialog, entry, label );
-	}
+	/* i18n notes: when no icon is selected in the drop-down list */
+	gtk_list_store_set( model, &row, ICON_STOCK_COLUMN, "", ICON_LABEL_COLUMN, _( "None" ), -1 );
 
-	/* 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 );
+	stock_list = gtk_stock_list_ids();
+	icon_theme = gtk_icon_theme_get_default();
+	stock_list = g_slist_sort( stock_list, ( GCompareFunc ) sort_stock_ids );
+
+	for( iter = stock_list ; iter ; iter = iter->next ){
+		icon_info = gtk_icon_theme_lookup_icon( icon_theme, ( gchar * ) iter->data, GTK_ICON_SIZE_MENU, GTK_ICON_LOOKUP_FORCE_SVG );
+		if( icon_info ){
+			if( gtk_stock_lookup(( gchar * ) iter->data, &stock_item )){
+				gtk_list_store_append( model, &row );
+				label = strip_underscore( stock_item.label );
+				gtk_list_store_set( model, &row, ICON_STOCK_COLUMN, ( gchar * ) iter->data, ICON_LABEL_COLUMN, label, -1 );
+				g_free( label );
+			}
+			gtk_icon_info_free( icon_info );
+		}
 	}
-	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 );*/
+
+	g_slist_foreach( stock_list, ( GFunc ) g_free, NULL );
+	g_slist_free( stock_list );
+
+	return( GTK_TREE_MODEL( model ));
 }
 
 static void
-check_for_label( NactWindow *window, GtkEntry *entry, const gchar *label )
+display_icon( NactIActionTab *instance, GtkWidget *image, gboolean show )
 {
-	NAAction *edited;
+	GtkFrame *frame = GTK_FRAME( base_window_get_widget( BASE_WINDOW( instance ), "ActionIconFrame" ));
 
-	nact_statusbar_hide_status( NACT_MAIN_WINDOW( window ), PROP_IACTION_TAB_STATUS_CONTEXT );
-	set_label_label( window, "black" );
-
-	edited = v_get_edited_action( window );
+	if( show ){
+		gtk_widget_show( image );
+		gtk_frame_set_shadow_type( frame, GTK_SHADOW_NONE );
 
-	if( edited && g_utf8_strlen( label, -1 ) == 0 ){
-		/* i18n: status bar message when the action label is empty */
-		nact_statusbar_display_status( NACT_MAIN_WINDOW( window ), PROP_IACTION_TAB_STATUS_CONTEXT, _( "Caution: a label is mandatory for the action." ));
-		set_label_label( window, "red" );
+	} else {
+		gtk_widget_hide( image );
+		gtk_frame_set_shadow_type( frame, GTK_SHADOW_IN );
 	}
 }
 
-static void
-set_label_label( NactWindow *window, const gchar *color )
+static GtkButton *
+get_enabled_button( NactIActionTab *instance )
 {
-	GtkWidget *label;
-	gchar *text;
-
-	label = base_window_get_widget( BASE_WINDOW( window ), "ActionLabelLabel" );
-	/* i18n: label in front of the GtkEntry where user enters the action label */
-	text = g_markup_printf_escaped( "<span color=\"%s\">%s</span>", color, _( "_Label :" ));
-	gtk_label_set_markup_with_mnemonic( GTK_LABEL( label ), text );
+	return( GTK_BUTTON( base_window_get_widget( BASE_WINDOW( instance ), "ActionEnabledButton" )));
 }
 
 static void
-on_tooltip_changed( GtkEntry *entry, gpointer user_data )
+icon_combo_list_fill( GtkComboBoxEntry* combo )
 {
-	NactWindow *dialog;
-	NAAction *edited;
+	GtkCellRenderer *cell_renderer_pix;
+	GtkCellRenderer *cell_renderer_text;
 
-	g_assert( NACT_IS_WINDOW( user_data ));
-	dialog = NACT_WINDOW( user_data );
+	if( gtk_combo_box_entry_get_text_column( combo ) == -1 ){
+		gtk_combo_box_entry_set_text_column( combo, ICON_STOCK_COLUMN );
+	}
+	gtk_cell_layout_clear( GTK_CELL_LAYOUT( combo ));
 
-	edited = v_get_edited_action( dialog );
+	cell_renderer_pix = gtk_cell_renderer_pixbuf_new();
+	gtk_cell_layout_pack_start( GTK_CELL_LAYOUT( combo ), cell_renderer_pix, FALSE );
+	gtk_cell_layout_add_attribute( GTK_CELL_LAYOUT( combo ), cell_renderer_pix, "stock-id", ICON_STOCK_COLUMN );
 
-	if( edited ){
-		na_action_set_tooltip( edited, gtk_entry_get_text( entry ));
-		v_field_modified( dialog );
-	}
+	cell_renderer_text = gtk_cell_renderer_text_new();
+	gtk_cell_layout_pack_start( GTK_CELL_LAYOUT( combo ), cell_renderer_text, TRUE );
+	gtk_cell_layout_add_attribute( GTK_CELL_LAYOUT( combo ), cell_renderer_text, "text", ICON_LABEL_COLUMN );
+
+	gtk_combo_box_set_active( GTK_COMBO_BOX( combo ), 0 );
 }
 
 static void
-on_icon_changed( GtkEntry *icon_entry, gpointer user_data )
+on_enabled_toggled( GtkToggleButton *button, NactIActionTab *instance )
 {
-	static const gchar *thisfn = "nact_iaction_tab_on_icon_changed";
-	NactWindow *dialog;
-	GtkWidget *image;
-	const gchar *icon_name;
-	GtkStockItem stock_item;
-	GdkPixbuf *icon = NULL;
-	gint width, height;
-	GError *error = NULL;
-	NAAction *edited;
-
-	g_assert( NACT_IS_WINDOW( user_data ));
-	dialog = NACT_WINDOW( user_data );
-
-	image = base_window_get_widget( BASE_WINDOW( dialog ), "ActionIconImage" );
-	g_assert( GTK_IS_WIDGET( image ));
-	display_icon( dialog, image, FALSE );
-
-	icon_name = gtk_entry_get_text( icon_entry );
-	/*g_debug( "%s: icon_name=%s", thisfn, icon_name );*/
+	NAObjectItem *edited;
+	gboolean enabled;
 
-	if( icon_name && strlen( icon_name ) > 0 ){
+	g_object_get(
+			G_OBJECT( instance ),
+			TAB_UPDATABLE_PROP_EDITED_ACTION, &edited,
+			NULL );
 
-		/* TODO: code should be mutualized with those IActionsList */
-		if( gtk_stock_lookup( icon_name, &stock_item )){
-			g_debug( "%s: gtk_stock_lookup", thisfn );
-			gtk_image_set_from_stock( GTK_IMAGE( image ), icon_name, GTK_ICON_SIZE_MENU );
-			display_icon( dialog, image, TRUE );
+	if( edited && NA_IS_OBJECT_ACTION( edited )){
+		enabled = gtk_toggle_button_get_active( button );
+		na_object_item_set_enabled( edited, enabled );
+		/*g_signal_emit_by_name( G_OBJECT( window ), NACT_SIGNAL_MODIFIED_FIELD );*/
+	}
+}
 
-		} else if( g_file_test( icon_name, G_FILE_TEST_EXISTS ) &&
-					g_file_test( icon_name, G_FILE_TEST_IS_REGULAR )){
-			g_debug( "%s: g_file_test", thisfn );
+static void
+on_label_changed( GtkEntry *entry, NactIActionTab *instance )
+{
+	NAObjectItem *edited;
+	const gchar *label;
 
-			gtk_icon_size_lookup( GTK_ICON_SIZE_MENU, &width, &height );
-			icon = gdk_pixbuf_new_from_file_at_size( icon_name, width, height, &error );
-			if( error ){
-				g_warning( "%s: gdk_pixbuf_new_from_file_at_size:%s", thisfn, error->message );
-				icon = NULL;
-				g_error_free( error );
-			}
-			gtk_image_set_from_pixbuf( GTK_IMAGE( image ), icon );
-			display_icon( dialog, image, TRUE );
+	g_object_get(
+			G_OBJECT( instance ),
+			TAB_UPDATABLE_PROP_EDITED_ACTION, &edited,
+			NULL );
 
-		}
+	if( edited ){
+		label = gtk_entry_get_text( entry );
+		na_object_set_label( NA_OBJECT( edited ), label );
+		/*g_signal_emit_by_name( G_OBJECT( window ), NACT_SIGNAL_MODIFIED_FIELD );*/
+		check_for_label( instance, entry, label );
 	}
 
-	edited = v_get_edited_action( dialog );
-
-	if( edited ){
-		na_action_set_icon( edited, icon_name );
+	/* 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 );*/
 }
 
-/* TODO: replace with a fds-compliant icon chooser */
 static void
-on_icon_browse( GtkButton *button, gpointer user_data )
+on_icon_browse( GtkButton *button, NactIActionTab *instance )
 {
 	GtkWidget *dialog;
 	gchar *filename;
 	GtkWidget *icon_widget;
 
-	g_assert( NACT_IS_IACTION_TAB( user_data ));
-
 	dialog = gtk_file_chooser_dialog_new(
 			_( "Choosing an icon" ),
 			NULL,
@@ -456,7 +492,7 @@ on_icon_browse( GtkButton *button, gpointer user_data )
 
 	if( gtk_dialog_run( GTK_DIALOG( dialog )) == GTK_RESPONSE_ACCEPT ){
 		filename = gtk_file_chooser_get_filename( GTK_FILE_CHOOSER( dialog ));
-		icon_widget = base_window_get_widget( BASE_WINDOW( user_data ), "MenuIconComboBoxEntry" );
+		icon_widget = base_window_get_widget( BASE_WINDOW( instance ), "MenuIconComboBoxEntry" );
 		gtk_entry_set_text( GTK_ENTRY( GTK_BIN( icon_widget )->child ), filename );
 	    g_free (filename);
 	  }
@@ -465,66 +501,62 @@ on_icon_browse( GtkButton *button, gpointer user_data )
 }
 
 static void
-icon_combo_list_fill( GtkComboBoxEntry* combo )
+on_icon_changed( GtkEntry *icon_entry, NactIActionTab *instance )
 {
-	GtkCellRenderer *cell_renderer_pix;
-	GtkCellRenderer *cell_renderer_text;
+	/*static const gchar *thisfn = "nact_iaction_tab_on_icon_changed";*/
+	GtkWidget *image;
+	GdkPixbuf *icon;
+	NAObjectItem *edited;
+	const gchar *icon_name;
 
-	if( gtk_combo_box_entry_get_text_column( combo ) == -1 ){
-		gtk_combo_box_entry_set_text_column( combo, ICON_STOCK_COLUMN );
-	}
-	gtk_cell_layout_clear( GTK_CELL_LAYOUT( combo ));
+	image = base_window_get_widget( BASE_WINDOW( instance ), "ActionIconImage" );
+	g_assert( GTK_IS_WIDGET( image ));
+	display_icon( instance, image, FALSE );
 
-	cell_renderer_pix = gtk_cell_renderer_pixbuf_new();
-	gtk_cell_layout_pack_start( GTK_CELL_LAYOUT( combo ), cell_renderer_pix, FALSE );
-	gtk_cell_layout_add_attribute( GTK_CELL_LAYOUT( combo ), cell_renderer_pix, "stock-id", ICON_STOCK_COLUMN );
+	g_object_get(
+			G_OBJECT( instance ),
+			TAB_UPDATABLE_PROP_EDITED_ACTION, &edited,
+			NULL );
 
-	cell_renderer_text = gtk_cell_renderer_text_new();
-	gtk_cell_layout_pack_start( GTK_CELL_LAYOUT( combo ), cell_renderer_text, TRUE );
-	gtk_cell_layout_add_attribute( GTK_CELL_LAYOUT( combo ), cell_renderer_text, "text", ICON_LABEL_COLUMN );
+	if( edited ){
+		icon_name = gtk_entry_get_text( icon_entry );
+		na_object_item_set_icon( edited, icon_name );
+		/*g_signal_emit_by_name( G_OBJECT( window ), NACT_SIGNAL_MODIFIED_FIELD );*/
 
-	gtk_combo_box_set_active( GTK_COMBO_BOX( combo ), 0 );
+		if( icon_name && strlen( icon_name ) > 0 ){
+			icon = na_object_item_get_pixbuf( edited, image );
+			gtk_image_set_from_pixbuf( GTK_IMAGE( image ), icon );
+			display_icon( instance, image, TRUE );
+		}
+	}
 }
 
-static GtkTreeModel *
-create_stock_icon_model( void )
+static void
+on_tooltip_changed( GtkEntry *entry, NactIActionTab *instance )
 {
-	GtkStockItem stock_item;
-	gchar* label;
-	GtkListStore *model;
-	GtkTreeIter row;
-	GSList *stock_list, *iter;
-	GtkIconTheme *icon_theme;
-	GtkIconInfo *icon_info;
-
-	model = gtk_list_store_new( ICON_N_COLUMN, G_TYPE_STRING, G_TYPE_STRING );
-
-	gtk_list_store_append( model, &row );
-
-	/* i18n notes: when no icon is selected in the drop-down list */
-	gtk_list_store_set( model, &row, ICON_STOCK_COLUMN, "", ICON_LABEL_COLUMN, _( "None" ), -1 );
+	NAObjectItem *edited;
 
-	stock_list = gtk_stock_list_ids();
-	icon_theme = gtk_icon_theme_get_default();
-	stock_list = g_slist_sort( stock_list, ( GCompareFunc ) sort_stock_ids );
+	g_object_get(
+			G_OBJECT( instance ),
+			TAB_UPDATABLE_PROP_EDITED_ACTION, &edited,
+			NULL );
 
-	for( iter = stock_list ; iter ; iter = iter->next ){
-		icon_info = gtk_icon_theme_lookup_icon( icon_theme, ( gchar * ) iter->data, GTK_ICON_SIZE_MENU, GTK_ICON_LOOKUP_FORCE_SVG );
-		if( icon_info ){
-			if( gtk_stock_lookup(( gchar * ) iter->data, &stock_item )){
-				gtk_list_store_append( model, &row );
-				label = strip_underscore( stock_item.label );
-				gtk_list_store_set( model, &row, ICON_STOCK_COLUMN, ( gchar * ) iter->data, ICON_LABEL_COLUMN, label, -1 );
-				g_free( label );
-			}
-			gtk_icon_info_free( icon_info );
-		}
+	if( edited ){
+		na_object_item_set_tooltip( edited, gtk_entry_get_text( entry ));
+		/*g_signal_emit_by_name( G_OBJECT( window ), NACT_SIGNAL_MODIFIED_FIELD );*/
 	}
+}
 
-	g_slist_foreach( stock_list, ( GFunc ) g_free, NULL );
-	g_slist_free( stock_list );
+static void
+set_label_label( NactIActionTab *instance, const gchar *color )
+{
+	GtkWidget *label;
+	gchar *text;
 
-	return( GTK_TREE_MODEL( model ));
+	label = base_window_get_widget( BASE_WINDOW( instance ), "ActionLabelLabel" );
+	/* i18n: label in front of the GtkEntry where user enters the action label */
+	text = g_markup_printf_escaped( "<span color=\"%s\">%s</span>", color, _( "_Label :" ));
+	gtk_label_set_markup_with_mnemonic( GTK_LABEL( label ), text );
 }
 
 static gint
@@ -578,42 +610,3 @@ strip_underscore( const gchar *text )
 
 	return( result );
 }
-
-static void
-display_icon( NactWindow *window, GtkWidget *image, gboolean show )
-{
-	GtkFrame *frame = GTK_FRAME( base_window_get_widget( BASE_WINDOW( window ), "ActionIconFrame" ));
-
-	if( show ){
-		gtk_widget_show( image );
-		gtk_frame_set_shadow_type( frame, GTK_SHADOW_NONE );
-
-	} else {
-		gtk_widget_hide( image );
-		gtk_frame_set_shadow_type( frame, GTK_SHADOW_IN );
-	}
-}
-
-static void
-on_enabled_toggled( GtkToggleButton *button, gpointer user_data )
-{
-	NactWindow *dialog;
-	NAAction *edited;
-	gboolean enabled;
-
-	g_assert( NACT_IS_WINDOW( user_data ));
-	dialog = NACT_WINDOW( user_data );
-
-	edited = v_get_edited_action( dialog );
-	if( edited ){
-		enabled = gtk_toggle_button_get_active( button );
-		na_action_set_enabled( edited, enabled );
-		v_field_modified( dialog );
-	}
-}
-
-static GtkButton *
-get_enabled_button( NactWindow *window )
-{
-	return( GTK_BUTTON( base_window_get_widget( BASE_WINDOW( window ), "ActionEnabledButton" )));
-}
diff --git a/src/nact/nact-iaction-tab.h b/src/nact/nact-iaction-tab.h
index 9d4d72a..ed236ca 100644
--- a/src/nact/nact-iaction-tab.h
+++ b/src/nact/nact-iaction-tab.h
@@ -31,13 +31,18 @@
 #ifndef __NACT_IACTION_TAB_H__
 #define __NACT_IACTION_TAB_H__
 
-/*
- * NactIActionTab interface definition.
+/**
+ * SECTION: nact_iaction_tab
+ * @short_description: #NactIActionTab interface definition.
+ * @include: nact/nact-iaction-tab.h
+ *
+ * This interface implements the "Nautilus Menu Item" tab of the notebook.
  *
- * This interface implements the "Nautilus Menu Item" box.
+ * Entry fields are enabled, as soon as an edited item has been set a a
+ * property of the main window,
  */
 
-#include "nact-window.h"
+#include <glib-object.h>
 
 G_BEGIN_DECLS
 
@@ -53,23 +58,17 @@ typedef struct NactIActionTabInterfacePrivate NactIActionTabInterfacePrivate;
 typedef struct {
 	GTypeInterface                  parent;
 	NactIActionTabInterfacePrivate *private;
-
-	/* api */
-	NAObject *  ( *get_selected )     ( NactWindow *window );
-	NAAction *  ( *get_edited_action )( NactWindow *window );
-	void        ( *field_modified )   ( NactWindow *window );
 }
 	NactIActionTabInterface;
 
 GType    nact_iaction_tab_get_type( void );
 
-void     nact_iaction_tab_initial_load( NactWindow *dialog );
-void     nact_iaction_tab_runtime_init( NactWindow *dialog );
-void     nact_iaction_tab_all_widgets_showed( NactWindow *dialog );
-void     nact_iaction_tab_dispose( NactWindow *dialog );
+void     nact_iaction_tab_initial_load_toplevel( NactIActionTab *instance );
+void     nact_iaction_tab_runtime_init_toplevel( NactIActionTab *instance );
+void     nact_iaction_tab_all_widgets_showed( NactIActionTab *instance );
+void     nact_iaction_tab_dispose( NactIActionTab *instance );
 
-void     nact_iaction_tab_set_action( NactWindow *dialog, const NAAction *action, GSList *selected_items );
-gboolean nact_iaction_tab_has_label( NactWindow *window );
+gboolean nact_iaction_tab_has_label( NactIActionTab *instance );
 
 G_END_DECLS
 
diff --git a/src/nact/nact-iactions-list.c b/src/nact/nact-iactions-list.c
index 2693319..8943edd 100644
--- a/src/nact/nact-iactions-list.c
+++ b/src/nact/nact-iactions-list.c
@@ -35,11 +35,16 @@
 #include <gdk/gdkkeysyms.h>
 #include <string.h>
 
+#include <common/na-object-api.h>
+#include <common/na-obj-action.h>
+#include <common/na-obj-menu.h>
+#include <common/na-obj-profile.h>
 #include <common/na-iprefs.h>
 
 #include "nact-application.h"
-#include "nact-iactions-list.h"
+#include "nact-main-tab.h"
 #include "nact-tree-model.h"
+#include "nact-iactions-list.h"
 
 /* private interface data
  */
@@ -47,35 +52,61 @@ struct NactIActionsListInterfacePrivate {
 	void *empty;						/* so that gcc -pedantic is happy */
 };
 
+/* signals
+ */
+enum {
+	SELECTION_CHANGED,
+	ITEM_UPDATED,
+	LAST_SIGNAL
+};
+
+/* iter on selection prototype
+ */
+typedef gboolean ( *FnIterOnSelection )( NactIActionsList *, GtkTreeView *, GtkTreeModel *, GtkTreeIter *, NAObject *, gpointer );
+
+/* when toggle collapse/expand rows, we want all rows have the same
+ * behavior, e.g. all rows collapse, or all rows expand
+ * this behavior is fixed by the first rows which will actually be
+ * toggled
+ */
+enum {
+	TOGGLE_UNDEFINED,
+	TOGGLE_COLLAPSE,
+	TOGGLE_EXPAND
+};
+
 /* data set against GObject
  */
-#define IS_EDITION_MODE					"iactions-list-edition-mode"
-#define ACCEPT_MULTIPLE_SELECTION		"iactions-list-accept-multiple-selection"
-#define IS_FILLING_LIST					"iactions-list-is-filling-list"
-#define SEND_SELECTION_CHANGED_MESSAGE	"iactions-list-send-selection-changed-message"
-#define HAVE_DND_MODE					"iactions-list-dnd-mode"
-
-static GType      register_type( void );
-static void       interface_base_init( NactIActionsListInterface *klass );
-static void       interface_base_finalize( NactIActionsListInterface *klass );
-
-static GSList    *v_get_actions( NactWindow *window );
-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       on_selection_changed( GtkTreeSelection *selection, NactIActionsList *instance );
-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 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 );
-static gboolean   is_edition_mode( NactWindow *window );
+#define SHOW_ONLY_ACTIONS_MODE			"nact-iactions-list-show-only-actions-mode"
+#define IS_FILLING_LIST					"nact-iactions-list-is-filling-list"
+#define HAVE_DND_MODE					"nact-iactions-list-dnd-mode"
+
+static gint         st_signals[ LAST_SIGNAL ] = { 0 };
+
+static GType        register_type( void );
+static void         interface_base_init( NactIActionsListInterface *klass );
+static void         interface_base_finalize( NactIActionsListInterface *klass );
+
+static void         display_label( GtkTreeViewColumn *column, GtkCellRenderer *cell, GtkTreeModel *model, GtkTreeIter *iter, NactIActionsList *instance );
+static void         extend_selection_to_childs( NactIActionsList *instance, GtkTreeView *treeview, GtkTreeModel *model, GtkTreeIter *parent );
+static void         free_items_flat_list_callback( NactIActionsList *instance, GSList *items );
+static GtkTreeView *get_actions_list_treeview( NactIActionsList *instance );
+static gboolean     get_item( NactTreeModel *model, GtkTreePath *path, NAObject *object, GSList **items );
+static gboolean     have_dnd_mode( NactIActionsList *instance );
+static void         insert_item( NactIActionsList *instance, NAObject *item );
+static gboolean     is_modified_item( NactTreeModel *model, GtkTreePath *path, NAObject *object, GSList **items );
+static void         iter_on_selection( NactIActionsList *instance, FnIterOnSelection fn_iter, gpointer user_data );
+static gboolean     on_button_press_event( GtkWidget *widget, GdkEventButton *event, NactIActionsList *instance );
+static gboolean     on_key_pressed_event( GtkWidget *widget, GdkEventKey *event, NactIActionsList *instance );
+static void         on_treeview_selection_changed( GtkTreeSelection *selection, NactIActionsList *instance );
+static void         on_iactions_list_item_updated( NactIActionsList *instance, GSList *updated_items );
+static void         on_iactions_list_item_updated_treeview( NactIActionsList *instance, GSList *updated_items );
+static void         on_iactions_list_selection_changed( NactIActionsList *instance, GSList *selected_items );
+static void         select_first_row( NactIActionsList *instance );
+static void         set_is_filling_list( NactIActionsList *instance, gboolean is_filling );
+static void         toggle_collapse( NactIActionsList *instance );
+static gboolean     toggle_collapse_iter( NactIActionsList *instance, GtkTreeView *treeview, GtkTreeModel *model, GtkTreeIter *iter, NAObject *object, gpointer user_data );
+static void         toggle_collapse_row( GtkTreeView *treeview, GtkTreePath *path, guint *toggle );
 
 GType
 nact_iactions_list_get_type( void )
@@ -111,7 +142,7 @@ register_type( void )
 
 	type = g_type_register_static( G_TYPE_INTERFACE, "NactIActionsList", &info, 0 );
 
-	g_type_interface_add_prerequisite( type, G_TYPE_OBJECT );
+	g_type_interface_add_prerequisite( type, BASE_WINDOW_TYPE );
 
 	return( type );
 }
@@ -127,6 +158,53 @@ interface_base_init( NactIActionsListInterface *klass )
 
 		klass->private = g_new0( NactIActionsListInterfacePrivate, 1 );
 
+		/**
+		 * "nact-iactions-list-selection-changed":
+		 *
+		 * This signal is emitted each time the selection is changed in
+		 * the treeview.
+		 *
+		 * User_data is a flat GSList of newly selected #NAObjects.
+		 * It is owned by the #IActionsList interface, and will be
+		 * released in the cleanup handler.
+		 */
+		st_signals[ SELECTION_CHANGED ] = g_signal_new_class_handler(
+				IACTIONS_LIST_SIGNAL_SELECTION_CHANGED,
+				G_TYPE_OBJECT,
+				G_SIGNAL_RUN_CLEANUP,
+				G_CALLBACK( free_items_flat_list_callback ),
+				NULL,
+				NULL,
+				g_cclosure_marshal_VOID__POINTER,
+				G_TYPE_NONE,
+				1,
+				G_TYPE_POINTER );
+
+		/**
+		 * "nact-iactions-list-item-updated":
+		 *
+		 * This signal is emitted to inform all widgets that an item
+		 * has been updated.
+		 * This typically results in a modification of the status of
+		 * this item, and of all its hierarchy in the #IActionsList
+		 * view.
+		 *
+		 * User_data is a flat GSList of modified #NAObjects. This
+		 * list is owned by the emitter, and will be released in the
+		 * cleanup handler.
+		 */
+		st_signals[ ITEM_UPDATED ] = g_signal_new_class_handler(
+				IACTIONS_LIST_SIGNAL_ITEM_UPDATED,
+				G_TYPE_OBJECT,
+				G_SIGNAL_RUN_CLEANUP,
+				G_CALLBACK( free_items_flat_list_callback ),
+				NULL,
+				NULL,
+				g_cclosure_marshal_VOID__POINTER,
+				G_TYPE_NONE,
+				1,
+				G_TYPE_POINTER );
+
 		initialized = TRUE;
 	}
 }
@@ -147,6 +225,9 @@ interface_base_finalize( NactIActionsListInterface *klass )
 }
 
 /**
+ * nact_iactions_list_initial_load_toplevel:
+ * @window: this #NactIActionsList *instance.
+ *
  * Allocates and initializes the ActionsList widget.
  *
  * GtkTreeView is created with NactTreeModel model
@@ -156,371 +237,321 @@ interface_base_finalize( NactIActionsListInterface *klass )
  *     GtkTreeModelFilter is built on top of GtkTreeStore
  */
 void
-nact_iactions_list_initial_load( NactWindow *window )
+nact_iactions_list_initial_load_toplevel( NactIActionsList *instance )
 {
-	static const gchar *thisfn = "nact_iactions_list_initial_load";
-	GtkWidget *widget, *label;
-	NactTreeModel *model;
+	static const gchar *thisfn = "nact_iactions_list_initial_load_toplevel";
+	GtkWidget *label;
+	GtkTreeView *treeview;
 	GtkTreeViewColumn *column;
 	GtkCellRenderer *renderer;
 
-	g_debug( "%s: window=%p", thisfn, ( void * ) window );
-	g_assert( NACT_IS_IACTIONS_LIST( window ));
-	g_assert( NACT_IS_WINDOW( window ));
+	g_debug( "%s: instance=%p", thisfn, ( void * ) instance );
+	g_return_if_fail( NACT_IS_IACTIONS_LIST( instance ));
 
-	widget = get_actions_list_widget( window );
+	treeview = get_actions_list_treeview( instance );
 
 	/* associates the ActionsList to the label */
-	label = base_window_get_widget( BASE_WINDOW( window ), "ActionsListLabel" );
-	gtk_label_set_mnemonic_widget( GTK_LABEL( label ), widget );
+	label = base_window_get_widget( BASE_WINDOW( instance ), "ActionsListLabel" );
+	gtk_label_set_mnemonic_widget( GTK_LABEL( label ), GTK_WIDGET( treeview ));
+
+	nact_iactions_list_set_dnd_mode( instance, FALSE );
+	nact_iactions_list_set_multiple_selection_mode( instance, FALSE );
+	nact_iactions_list_set_only_actions_mode( instance, FALSE );
+	set_is_filling_list( instance, FALSE );
 
-	nact_iactions_list_set_send_selection_changed_on_fill_list( window, FALSE );
-	nact_iactions_list_set_is_filling_list( window, FALSE );
+	nact_tree_model_initial_load( BASE_WINDOW( instance ), treeview );
 
-	model = nact_tree_model_new( NACT_MAIN_WINDOW( window ));
-	gtk_tree_view_set_model( GTK_TREE_VIEW( widget ), GTK_TREE_MODEL( model ));
-	gtk_tree_view_set_enable_tree_lines( GTK_TREE_VIEW( widget ), TRUE );
-	g_object_unref( model );
+	gtk_tree_view_set_enable_tree_lines( treeview, TRUE );
 
-	/* create visible columns on the tree view */
+	/* create visible columns on the tree view
+	 */
 	column = gtk_tree_view_column_new_with_attributes(
 			"icon", gtk_cell_renderer_pixbuf_new(), "pixbuf", IACTIONS_LIST_ICON_COLUMN, NULL );
-	gtk_tree_view_append_column( GTK_TREE_VIEW( widget ), column );
+	gtk_tree_view_append_column( treeview, 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();
 	gtk_tree_view_column_set_title( column, "label" );
 	gtk_tree_view_column_set_sort_column_id( column, IACTIONS_LIST_LABEL_COLUMN );
 	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 );
+			column, renderer, ( GtkTreeCellDataFunc ) display_label, instance, NULL );
+	gtk_tree_view_append_column( treeview, column );
 }
 
 /**
+ * nact_iactions_list_runtime_init_toplevel:
+ * @window: this #NactIActionsList *instance.
+ * @items: list of #NAObject actions and menus as provided by #NAPivot.
+ *
  * Allocates and initializes the ActionsList widget.
  */
 void
-nact_iactions_list_runtime_init( NactWindow *window )
+nact_iactions_list_runtime_init_toplevel( NactIActionsList *instance, GSList *items )
 {
-	static const gchar *thisfn = "nact_iactions_list_runtime_init";
-	GtkWidget *widget;
-	GtkTreeSelection *selection;
+	static const gchar *thisfn = "nact_iactions_list_runtime_init_toplevel";
+	GtkTreeView *treeview;
+	NactTreeModel *model;
+	gboolean have_dnd;
 
-	g_debug( "%s: window=%p", thisfn, ( void * ) window );
-	g_assert( NACT_IS_IACTIONS_LIST( window ));
-	g_assert( NACT_IS_WINDOW( window ));
+	g_debug( "%s: instance=%p, items=%p (%d items)",
+			thisfn, ( void * ) instance, ( void * ) items, g_slist_length( items ));
+	g_return_if_fail( NACT_IS_IACTIONS_LIST( instance ));
 
-	widget = get_actions_list_widget( window );
-	g_assert( GTK_IS_WIDGET( widget ));
+	treeview = get_actions_list_treeview( instance );
+	model = NACT_TREE_MODEL( gtk_tree_view_get_model( treeview ));
+	have_dnd = have_dnd_mode( instance );
 
-	nact_iactions_list_fill( window, TRUE );
-	nact_tree_model_runtime_init_dnd( NACT_MAIN_WINDOW( window ), GTK_TREE_VIEW( widget ));
+	nact_tree_model_runtime_init( model, have_dnd );
 
 	/* set up selection control */
-	nact_window_signal_connect(
-			window,
-			G_OBJECT( gtk_tree_view_get_selection( GTK_TREE_VIEW( widget ))),
+	base_window_signal_connect(
+			BASE_WINDOW( instance ),
+			G_OBJECT( gtk_tree_view_get_selection( treeview )),
 			"changed",
-			G_CALLBACK( on_selection_changed ));
+			G_CALLBACK( on_treeview_selection_changed ));
 
 	/* catch press 'Enter' */
-	nact_window_signal_connect(
-			window,
-			G_OBJECT( widget ),
+	base_window_signal_connect(
+			BASE_WINDOW( instance ),
+			G_OBJECT( treeview ),
 			"key-press-event",
-			G_CALLBACK( v_on_key_pressed_event ));
+			G_CALLBACK( on_key_pressed_event ));
 
 	/* catch double-click */
-	nact_window_signal_connect(
-			window,
-			G_OBJECT( widget ),
+	base_window_signal_connect(
+			BASE_WINDOW( instance ),
+			G_OBJECT( treeview ),
 			"button-press-event",
-			G_CALLBACK( v_on_button_press_event ));
-
-	/* clear the selection */
-	selection = gtk_tree_view_get_selection( GTK_TREE_VIEW( widget ));
-	gtk_tree_selection_unselect_all( selection );
+			G_CALLBACK( on_button_press_event ));
+
+	/* install a virtual function as 'selection-changed' handler */
+	base_window_signal_connect(
+			BASE_WINDOW( instance ),
+			G_OBJECT( instance ),
+			IACTIONS_LIST_SIGNAL_SELECTION_CHANGED,
+			G_CALLBACK( on_iactions_list_selection_changed ));
+
+	/* updates the treeview display when an item is modified */
+	base_window_signal_connect(
+			BASE_WINDOW( instance ),
+			G_OBJECT( instance ),
+			IACTIONS_LIST_SIGNAL_ITEM_UPDATED,
+			G_CALLBACK( on_iactions_list_item_updated_treeview ));
+
+	/* install a virtual function as 'item-updated' handler */
+	base_window_signal_connect(
+			BASE_WINDOW( instance ),
+			G_OBJECT( instance ),
+			IACTIONS_LIST_SIGNAL_ITEM_UPDATED,
+			G_CALLBACK( on_iactions_list_item_updated ));
+
+	/* fill the model after having connected the signals
+	 * so that callbacks are triggered at last
+	 */
+	nact_iactions_list_fill( instance, items );
 }
 
 /**
- * Fill the listbox with current actions.
+ * nact_iactions_list_all_widgets_showed:
+ * @window: this #NactIActionsList *instance.
  */
 void
-nact_iactions_list_fill( NactWindow *window, gboolean keep_expanded )
+nact_iactions_list_all_widgets_showed( NactIActionsList *instance )
 {
-	static const gchar *thisfn = "nact_iactions_list_fill";
-	GSList *expanded = NULL;
-	GtkWidget *widget;
-	GtkTreeModelFilter *tmf_model;
-	GtkTreeStore *ts_model;
-	GSList *actions, *ia;
-	GSList *profiles, *ip;
-	GtkTreeIter iter, profile_iter;
-	NAAction *action;
-	NAActionProfile *profile;
-
-	g_debug( "%s: window=%p, keep_expanded=%s",
-			thisfn, ( void * ) window, keep_expanded ? "True":"False" );
+	static const gchar *thisfn = "nact_iactions_list_all_widgets_showed";
 
-	g_assert( NACT_IS_IACTIONS_LIST( window ));
-
-	nact_iactions_list_set_is_filling_list( window, TRUE );
+	g_debug( "%s: instance=%p", thisfn, ( void * ) instance );
+}
 
-	if( keep_expanded ){
-		expanded = get_expanded_rows( window );
-	}
+/**
+ * nact_iactions_list_dispose:
+ * @window: this #NactIActionsList *instance.
+ */
+void
+nact_iactions_list_dispose( NactIActionsList *instance )
+{
+	static const gchar *thisfn = "nact_iactions_list_dispose";
+	GtkTreeView *treeview;
+	NactTreeModel *model;
 
-	widget = get_actions_list_widget( window );
-	tmf_model = GTK_TREE_MODEL_FILTER( gtk_tree_view_get_model( GTK_TREE_VIEW( widget )));
-	ts_model = GTK_TREE_STORE( gtk_tree_model_filter_get_model( tmf_model ));
-	gtk_tree_store_clear( ts_model );
-
-	actions = v_get_actions( window );
-	g_debug( "%s: actions has %d elements", thisfn, g_slist_length( actions ));
-
-	for( ia = actions ; ia != NULL ; ia = ia->next ){
-		action = NA_ACTION( ia->data );
-		gtk_tree_store_append( ts_model, &iter, NULL );
-		gtk_tree_store_set( ts_model, &iter, IACTIONS_LIST_NAOBJECT_COLUMN, action, -1);
-		setup_action( widget, ts_model, &iter, action );
-		g_debug( "%s: action=%p", thisfn, ( void * ) action );
-
-		if( is_edition_mode( window )){
-			profiles = na_action_get_profiles( action );
-			for( ip = profiles ; ip ; ip = ip->next ){
-				profile = NA_ACTION_PROFILE( ip->data );
-				gtk_tree_store_append( ts_model, &profile_iter, &iter );
-				gtk_tree_store_set( ts_model, &profile_iter, IACTIONS_LIST_NAOBJECT_COLUMN, profile, -1 );
-				setup_profile( widget, ts_model, &profile_iter, profile );
-			}
-		}
-	}
-	/*g_debug( "%s: at end, actions has %d elements", thisfn, g_slist_length( actions ));*/
+	g_debug( "%s: instance=%p", thisfn, ( void * ) instance );
 
-	if( keep_expanded ){
-		expand_rows( window, expanded );
-		free_expanded_list( expanded );
-	}
+	treeview = get_actions_list_treeview( instance );
+	model = NACT_TREE_MODEL( gtk_tree_view_get_model( treeview ));
 
-	nact_iactions_list_set_is_filling_list( window, FALSE );
+	nact_tree_model_dispose( model );
 }
 
 /**
- * Set the selection to the specified object.
+ * nact_iactions_list_delete_selection:
+ * @window: this #NactIActionsList instance.
+ * @path: a #GtkTreePath allocated here to point to the new row to select.
  *
- * @type: select a profile or an action
- * @uuid: uuid of the relevant action
- * @label: label of the action, or of the profile
+ * Deletes the current selection from the underlying tree store.
  *
- * if we want select an action:
- * - set type = NA_ACTION_TYPE
- * - set uuid = uuid of the action
- * - set label = label of the action
+ * Returns the list of deleted #NAObject items.
  *
- * 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 label is NULL, then we consider that the action must be found, and we
- * explore the whole list for the uuid ; if not found, we select the last item.
- *
- * 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)
+ * the returned @path sould be gtk_tree_path_free() by the caller.
  */
-void
-nact_iactions_list_set_selection( NactWindow *window, GType type, const gchar *uuid, const gchar *label )
+GSList *
+nact_iactions_list_delete_selection( NactIActionsList *instance, GtkTreePath **path )
 {
-	static const gchar *thisfn = "nact_iactions_list_set_selection";
-	GtkWidget *list;
-	GtkTreeSelection *selection;
-	GtkTreeIter iter;
+	GtkTreeView *treeview;
 	GtkTreeModel *model;
-	gboolean iterok, iter_child_ok;
-	gboolean found = FALSE;
-	GtkTreeIter previous;
-	NAObject *iter_object;
-	gchar *iter_uuid, *iter_label;
-	gint ret_uuid, ret_label;
-	guint nb_profiles;
-	GtkTreeIter iter_child, previous_child;
+	GtkTreeSelection *selection;
+	GList *selected;
+	GSList *deleted = NULL;
 
-	g_debug( "%s: window=%p, type=%s, uuid=%s, label=%s",
-			thisfn, ( void * ) window, type == NA_ACTION_TYPE ? "action":"profile", uuid, label );
+	g_return_val_if_fail( NACT_IS_IACTIONS_LIST( instance ), NULL );
 
-	list = get_actions_list_widget( window );
-	selection = gtk_tree_view_get_selection( GTK_TREE_VIEW( list ));
+	treeview = get_actions_list_treeview( instance );
+	selection = gtk_tree_view_get_selection( treeview );
+	selected = gtk_tree_selection_get_selected_rows( selection, &model );
 
-	if( !uuid || !strlen( uuid )){
-		g_debug( "%s: null or empty uuid: unselect all", thisfn );
-		gtk_tree_selection_unselect_all( selection );
-		on_selection_changed( selection, NACT_IACTIONS_LIST( window ));
-		return;
+	if( g_list_length( selected )){
+		*path = gtk_tree_path_copy(( GtkTreePath * ) selected->data );
+		deleted = nact_tree_model_remove( NACT_TREE_MODEL( model ), selected );
 	}
 
-	model = gtk_tree_view_get_model( GTK_TREE_VIEW( list ));
-	iterok = gtk_tree_model_get_iter_first( model, &iter );
-	if( !iterok ){
-		g_debug( "%s: empty actions list: unselect all", thisfn );
-		gtk_tree_selection_unselect_all( selection );
-		on_selection_changed( selection, NACT_IACTIONS_LIST( window ));
-		return;
-	}
+	g_list_foreach( selected, ( GFunc ) gtk_tree_path_free, NULL );
+	g_list_free( selected );
 
-	while( iterok && !found ){
-		gtk_tree_model_get( model, &iter, IACTIONS_LIST_NAOBJECT_COLUMN, &iter_object, IACTIONS_LIST_LABEL_COLUMN, &iter_label, -1 );
-		g_assert( NA_IS_ACTION( iter_object ));
+	return( deleted );
+}
 
-		iter_uuid = na_action_get_uuid( NA_ACTION( iter_object ));
-		ret_uuid = g_ascii_strcasecmp( iter_uuid, uuid );
-		nb_profiles = na_action_get_profiles_count( NA_ACTION( iter_object ));
+/**
+ * nact_iactions_list_fill:
+ * @window: this #NactIActionsList instance.
+ *
+ * Fill the listbox with the provided list of items.
+ *
+ * Menus are expanded, profiles are not.
+ * The selection is reset to the first line of the tree, if there is one.
+ */
+void
+nact_iactions_list_fill( NactIActionsList *instance, GSList *items )
+{
+	static const gchar *thisfn = "nact_iactions_list_fill";
+	GtkTreeView *treeview;
+	NactTreeModel *model;
+	gboolean only_actions;
 
-		if( type == NA_ACTION_TYPE || ( ret_uuid == 0 && nb_profiles == 1 )){
-			ret_label = label ? g_utf8_collate( iter_label, label ) : -1;
+	g_debug( "%s: instance=%p, items=%p", thisfn, ( void * ) instance, ( void * ) items );
 
-			if( ret_uuid == 0 || ret_label > 0 ){
-				g_debug( "%s: selecting action iter_object=%p, ret_uuid=%d, ret_label=%d", thisfn, ( void * ) iter_object, ret_uuid, ret_label );
-				gtk_tree_selection_select_iter( selection, &iter );
-				found = TRUE;
-				break;
-			}
+	treeview = get_actions_list_treeview( instance );
+	model = NACT_TREE_MODEL( gtk_tree_view_get_model( treeview ));
+	only_actions = nact_iactions_list_is_only_actions_mode( instance );
 
-		} else if( ret_uuid == 0 && gtk_tree_model_iter_has_child( model, &iter )){
-			iter_child_ok = gtk_tree_model_iter_children( model, &iter_child, &iter );
+	set_is_filling_list( instance, TRUE );
+	nact_tree_model_fill( model, items, only_actions );
+	set_is_filling_list( instance, FALSE );
 
-			while( iter_child_ok ){
-				gtk_tree_model_get( model, &iter_child, IACTIONS_LIST_NAOBJECT_COLUMN, &iter_object, IACTIONS_LIST_LABEL_COLUMN, &iter_label, -1 );
-				ret_label = g_utf8_collate( iter_label, label );
+	select_first_row( instance );
+}
 
-				if( ret_label >= 0 ){
-					g_debug( "%s: selecting profile iter_object=%p, ret_uuid=%d, ret_label=%d", thisfn, ( void * ) iter_object, ret_uuid, ret_label );
-					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 ){
-				g_debug( "%s: selecting previous profile", thisfn );
-				gtk_tree_selection_select_iter( selection, &previous_child );
-				found = TRUE;
-			}
-		}
+GSList *
+nact_iactions_list_free_items_list( NactIActionsList *instance, GSList *items )
+{
+	g_return_val_if_fail( NACT_IS_IACTIONS_LIST( instance ), NULL );
 
-		previous = iter;
-		iterok = gtk_tree_model_iter_next( model, &iter );
-	}
+	free_items_flat_list_callback( instance, items );
 
-	if( !found ){
-		g_debug( "%s: selecting previous action", thisfn );
-		gtk_tree_selection_select_iter( selection, &previous );
-	}
+	return( NULL );
 }
 
-void
-nact_iactions_list_select_first( NactWindow *window )
+/**
+ * nact_iactions_list_get_items_count:
+ * @window: this #NactIActionsList instance.
+ *
+ * Returns: the current count of items in the list, whether they are
+ * currently visible or not.
+ */
+guint
+nact_iactions_list_get_items_count( NactIActionsList *instance )
 {
-	static const gchar *thisfn = "nact_iactions_list_select_first";
-	GtkWidget *list;
-	GtkTreeSelection *selection;
-	GtkTreeModel *model;
-	GtkTreeIter iter;
-	gboolean iterok;
+	GtkTreeView *treeview;
+	NactTreeModel *model;
 
-	g_debug( "%s: window=%p", thisfn, ( void * ) window );
+	g_return_val_if_fail( NACT_IS_IACTIONS_LIST( instance ), 0 );
 
-	list = get_actions_list_widget( window );
-	selection = gtk_tree_view_get_selection( GTK_TREE_VIEW( list ));
+	treeview = get_actions_list_treeview( instance );
 
-	model = gtk_tree_view_get_model( GTK_TREE_VIEW( list ));
-	iterok = gtk_tree_model_get_iter_first( model, &iter );
-	if( !iterok ){
-		g_debug( "%s: empty actions list: unselect all", thisfn );
-		gtk_tree_selection_unselect_all( selection );
-		on_selection_changed( selection, NACT_IACTIONS_LIST( window ));
-		return;
-	}
+	model = NACT_TREE_MODEL( gtk_tree_view_get_model( treeview ));
 
-	gtk_tree_selection_select_iter( selection, &iter );
+	g_return_val_if_fail( NACT_IS_TREE_MODEL( model ), 0 );
+
+	return( nact_tree_model_get_items_count( model ));
 }
 
 /**
- * Reset the focus on the ActionsList listbox.
+ * nact_iactions_list_get_items:
+ * @window: this #NactIActionsList instance.
+ *
+ * Returns: the current tree.
+ *
+ * The returned #GSList content is owned by the underlying tree model,
+ * and should only be g_slist_free() by the caller.
  */
-/*void
-nact_iactions_list_set_focus( NactWindow *window )
+GSList *
+nact_iactions_list_get_items( NactIActionsList *instance )
 {
-	GtkWidget *list = get_actions_list_widget( window );
-	gtk_widget_grab_focus( list );
-}*/
+	GSList *items = NULL;
+	GtkTreeView *treeview;
+	NactTreeModel *model;
 
-/**
- * Returns the currently selected action or profile.
- * TODO: remove this function
- */
-NAObject *
-nact_iactions_list_get_selected_object( NactWindow *window )
-{
-	NAObject *object = NULL;
-	GtkWidget *treeview;
-	GtkTreeSelection *selection;
-	GtkTreeModel *tm_model;
-	GtkTreeIter iter;
+	g_return_val_if_fail( NACT_IS_IACTIONS_LIST( instance ), NULL );
 
-	treeview = get_actions_list_widget( window );
-	selection = gtk_tree_view_get_selection( GTK_TREE_VIEW( treeview ));
+	treeview = get_actions_list_treeview( instance );
+	model = NACT_TREE_MODEL( gtk_tree_view_get_model( treeview ));
 
-	if( gtk_tree_selection_get_selected( selection, &tm_model, &iter )){
+	nact_tree_model_iter( model, ( FnIterOnStore ) get_item, &items );
 
-		gtk_tree_model_get( tm_model, &iter, IACTIONS_LIST_NAOBJECT_COLUMN, &object, -1 );
+	/*g_debug( "nact_iactions_list_get_modified_items: count=%d", g_slist_length( items ));*/
 
-		g_assert( object );
-		g_assert( NA_IS_OBJECT( object ));
-	}
-
-	return( object );
+	return( g_slist_reverse( items ));
 }
 
 /**
- * Returns the currently selected actions when in export mode.
+ * nact_iactions_list_get_modified_items:
+ * @window: this #NactIActionsList instance.
  *
- * The returned GSList should be freed by the caller (g_slist_free),
- * without freing not unref any of the contained objects.
- * TODO: remove this function
+ * Returns a flat list of modified items.
+ *
+ * The returned GSList should be nact_iaction_list_free_items_list()-ed.
  */
 GSList *
-nact_iactions_list_get_selected_actions( NactWindow *window )
+nact_iactions_list_get_modified_items( NactIActionsList *instance )
 {
-	return( nact_iactions_list_get_selected_items( NACT_IACTIONS_LIST( window )));
+	GSList *items = NULL;
+	GtkTreeView *treeview;
+	NactTreeModel *model;
+
+	g_return_val_if_fail( NACT_IS_IACTIONS_LIST( instance ), NULL );
+
+	treeview = get_actions_list_treeview( instance );
+	model = NACT_TREE_MODEL( gtk_tree_view_get_model( treeview ));
+
+	nact_tree_model_iter( model, ( FnIterOnStore ) is_modified_item, &items );
+
+	/*g_debug( "nact_iactions_list_get_modified_items: count=%d", g_slist_length( items ));*/
+
+	return( g_slist_reverse( items ));
 }
 
 /**
+ * nact_iactions_list_get_selected_items:
+ * @window: this #NactIActionsList instance.
+ *
  * Returns the currently selected actions when in export mode.
  *
- * The returned GSList should be g_slist_free() by the caller,
- * without freing nor unref any of the contained objects.
+ * The returned GSList should be nact_iaction_list_free_items_list()-ed.
  */
 GSList *
 nact_iactions_list_get_selected_items( NactIActionsList *instance )
 {
 	GSList *items = NULL;
-	GtkWidget *treeview;
+	GtkTreeView *treeview;
 	GtkTreeSelection *selection;
 	GtkTreeModel *model;
 	GtkTreeIter iter;
@@ -528,8 +559,8 @@ nact_iactions_list_get_selected_items( NactIActionsList *instance )
 	NAObject *object;
 	GtkTreePath *path;
 
-	treeview = get_actions_list_widget( NACT_WINDOW( instance ));
-	selection = gtk_tree_view_get_selection( GTK_TREE_VIEW( treeview ));
+	treeview = get_actions_list_treeview( instance );
+	selection = gtk_tree_view_get_selection( treeview );
 	listrows = gtk_tree_selection_get_selected_rows( selection, &model );
 
 	for( it = listrows ; it ; it = it->next ){
@@ -545,517 +576,700 @@ nact_iactions_list_get_selected_items( NactIActionsList *instance )
 	return( g_slist_reverse( items ));
 }
 
-/*void
-nact_iactions_list_set_modified( NactWindow *window, gboolean is_modified, gboolean can_save )
+/**
+ * nact_iactions_list_insert_items:
+ * @instance: this #NactIActionsList instance.
+ * @items: a list of items to be inserted (e.g. from a paste).
+ *
+ * Inserts the provided @items list in the treeview.
+ *
+ * The provided @items list is supposed to be homogeneous, i.e. it
+ * If the list is not sorted, the new item is inserted just before the
+ * current position.
+ *
+ * If new item is a #NAActionMenu or a #NAAction, it will be inserted
+ * before the current action or menu.
+ *
+ * If new item is a #NAActionProfile, it will be inserted before the
+ * current profile, or as a new profile at the beginning of the list
+ * of profiles of the current action.
+ */
+void
+nact_iactions_list_insert_items( NactIActionsList *instance, NAObject *item )
 {
-}*/
+	GtkTreeView *treeview;
+	GtkTreeSelection *selection;
+	GtkTreeModel *model;
+	GList *list_selected;
+	GtkTreePath *path = NULL;
+	NAObject *obj_selected = NULL;
+	GtkTreeIter iter;
 
-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 ));
+	g_return_if_fail( NACT_IS_IACTIONS_LIST( instance ));
+	g_return_if_fail( NA_IS_OBJECT( item ));
 
-	gboolean is_expanded = FALSE;
-	GtkTreeIter iter;
-	gboolean iterok = gtk_tree_model_get_iter_first( model, &iter );
-	NAObject *iter_object;
+	treeview = get_actions_list_treeview( instance );
+	model = gtk_tree_view_get_model( treeview );
+	g_return_if_fail( NACT_IS_TREE_MODEL( model ));
 
-	while( iterok ){
-		gtk_tree_model_get( model, &iter, IACTIONS_LIST_NAOBJECT_COLUMN, &iter_object, -1 );
+	selection = gtk_tree_view_get_selection( treeview );
+	list_selected = gtk_tree_selection_get_selected_rows( selection, NULL );
+	gtk_tree_selection_unselect_all( selection );
 
-		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;
+	/* a NAObjectItem (action or menu) is inserted just before the
+	 * beginning of the selection, at the same level that this beginning
+	 */
+	if( NA_IS_OBJECT_ITEM( item )){
+		if( g_list_length( list_selected )){
+			path = ( GtkTreePath * ) list_selected->data;
+			gtk_tree_model_get_iter( model, &iter, path );
+			gtk_tree_model_get( model, &iter, IACTIONS_LIST_NAOBJECT_COLUMN, &obj_selected, -1 );
 		}
+	}
 
-		iterok = gtk_tree_model_iter_next( model, &iter );
+	/* a NAObjectProfile is inserted just after the action if it has
+	 * only one profile (it is currently selected)
+	 * if current selection is a profile, then the insertion occurs
+	 * just before this profile
+	 */
+	if( NA_IS_OBJECT_PROFILE( item )){
+		g_return_if_fail( g_list_length( list_selected ));
+		path = ( GtkTreePath * ) list_selected->data;
+		gtk_tree_model_get_iter( model, &iter, path );
+		gtk_tree_model_get( model, &iter, IACTIONS_LIST_NAOBJECT_COLUMN, &obj_selected, -1 );
 	}
 
-	return( is_expanded );
+	nact_tree_model_insert_item( NACT_TREE_MODEL( model ), item, path, obj_selected, &iter );
+
+	if( NA_IS_OBJECT_PROFILE( item )){
+		na_object_dump( na_object_profile_get_action( NA_OBJECT_PROFILE( item )));
+	} else {
+		g_return_if_fail( NA_IS_OBJECT_ITEM( item ));
+		na_object_dump( NA_OBJECT( item ));
+	}
+
+	path = gtk_tree_model_get_path( model, &iter );
+	gtk_tree_view_expand_to_path( treeview, path );
+	gtk_tree_view_set_cursor_on_cell( treeview, path, NULL, NULL, FALSE );
+	gtk_tree_path_free( path );
+
+	if( obj_selected ){
+		g_object_unref( obj_selected );
+	}
+
+	g_list_foreach( list_selected, ( GFunc ) gtk_tree_path_free, NULL );
+	g_list_free( list_selected );
 }
 
-/*
- * Collapse / expand if actions has more than one profile
+/**
+ * nact_iactions_list_insert_item:
+ * @instance: this #NactIActionsList instance.
+ * @item: a #NAActionMenu, #NAAction or #NAActionProfile to be added.
+ *
+ * If the list is not sorted, the new item is inserted just before the
+ * current position.
+ *
+ * If new item is a #NAActionMenu or a #NAAction, it will be inserted
+ * before the current action or menu.
+ *
+ * If new item is a #NAActionProfile, it will be inserted before the
+ * current profile, or as a new profile at the beginning of the list
+ * of profiles of the current action.
  */
-void
-nact_iactions_list_toggle_collapse( NactWindow *window, const NAAction *action )
+static void
+insert_item( NactIActionsList *instance, NAObject *item )
 {
-	static const gchar *thisfn = "nact_iactions_list_toggle_collapse";
-	NAObject *iter_object;
-	GtkTreePath *path;
+	GtkTreeView *treeview;
+	GtkTreeSelection *selection;
+	GtkTreeModel *model;
+	GList *list_selected;
+	GtkTreePath *path = NULL;
+	NAObject *obj_selected = NULL;
+	GtkTreeIter iter;
 
-	GtkWidget *treeview = get_actions_list_widget( window );
-	GtkTreeModel *model = gtk_tree_view_get_model( GTK_TREE_VIEW( treeview ));
+	g_return_if_fail( NACT_IS_IACTIONS_LIST( instance ));
+	g_return_if_fail( NA_IS_OBJECT( item ));
 
-	GtkTreeIter iter;
-	gboolean iterok = gtk_tree_model_get_iter_first( model, &iter );
+	treeview = get_actions_list_treeview( instance );
+	model = gtk_tree_view_get_model( treeview );
+	g_return_if_fail( NACT_IS_TREE_MODEL( model ));
 
-	while( iterok ){
+	selection = gtk_tree_view_get_selection( treeview );
+	list_selected = gtk_tree_selection_get_selected_rows( selection, NULL );
+	gtk_tree_selection_unselect_all( selection );
 
-		gtk_tree_model_get( model, &iter, IACTIONS_LIST_NAOBJECT_COLUMN, &iter_object, -1 );
-		if( iter_object == NA_OBJECT( action )){
+	/* a NAObjectItem (action or menu) is inserted just before the
+	 * beginning of the selection, at the same level that this beginning
+	 */
+	if( NA_IS_OBJECT_ITEM( item )){
+		if( g_list_length( list_selected )){
+			path = ( GtkTreePath * ) list_selected->data;
+			gtk_tree_model_get_iter( model, &iter, path );
+			gtk_tree_model_get( model, &iter, IACTIONS_LIST_NAOBJECT_COLUMN, &obj_selected, -1 );
+		}
+	}
 
-			if( na_action_get_profiles_count( action ) > 1 ){
+	/* a NAObjectProfile is inserted just after the action if it has
+	 * only one profile (it is currently selected)
+	 * if current selection is a profile, then the insertion occurs
+	 * just before this profile
+	 */
+	if( NA_IS_OBJECT_PROFILE( item )){
+		g_return_if_fail( g_list_length( list_selected ));
+		path = ( GtkTreePath * ) list_selected->data;
+		gtk_tree_model_get_iter( model, &iter, path );
+		gtk_tree_model_get( model, &iter, IACTIONS_LIST_NAOBJECT_COLUMN, &obj_selected, -1 );
+	}
 
-				path = gtk_tree_model_get_path( model, &iter );
+	nact_tree_model_insert_item( NACT_TREE_MODEL( model ), item, path, obj_selected, &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, ( void * ) action );
+	if( NA_IS_OBJECT_PROFILE( item )){
+		na_object_dump( na_object_profile_get_action( NA_OBJECT_PROFILE( item )));
+	} else {
+		g_return_if_fail( NA_IS_OBJECT_ITEM( item ));
+		na_object_dump( NA_OBJECT( item ));
+	}
 
-				} else {
-					gtk_tree_view_expand_row( GTK_TREE_VIEW( treeview ), path, TRUE );
-					g_debug( "%s: action=%p expanded", thisfn, ( void * ) action );
-				}
+	path = gtk_tree_model_get_path( model, &iter );
+	gtk_tree_view_expand_to_path( treeview, path );
+	gtk_tree_view_set_cursor_on_cell( treeview, path, NULL, NULL, FALSE );
+	gtk_tree_path_free( path );
 
-				gtk_tree_path_free( path );
-			}
-			break;
-		}
-		iterok = gtk_tree_model_iter_next( model, &iter );
+	if( obj_selected ){
+		g_object_unref( obj_selected );
 	}
+
+	g_list_foreach( list_selected, ( GFunc ) gtk_tree_path_free, NULL );
+	g_list_free( list_selected );
 }
 
 /**
- * Update the listbox when a field has been modified in one of the tabs.
+ * nact_iactions_list_is_filling_list:
+ * @instance: this #NactIActionsList instance.
  *
- * @action: the NAAction whose one field has been modified ; the field
- * can be a profile field or an action field, whatever be the currently
- * selected row.
+ * Returns %TRUE if currently being filling the list.
+ */
+gboolean
+nact_iactions_list_is_filling_list( NactIActionsList *instance )
+{
+	return(( gboolean ) GPOINTER_TO_INT( g_object_get_data( G_OBJECT( instance ), IS_FILLING_LIST )));
+}
+
+/**
+ * nact_iactions_list_is_filling_list:
+ * @instance: this #NactIActionsList instance.
+ * @action: a #NAAction action.
  *
- * e.g. while the currently selected row is a profile, user may have
- * modified the action label or the action icon : we wish report this
- * modification on the listbox
+ * Returns %TRUE if the action is expanded (i.e. if its profiles are
+ * visible).
  */
-void
-nact_iactions_list_update_selected( NactWindow *window, NAAction *action )
+gboolean
+nact_iactions_list_is_expanded( NactIActionsList *instance, const NAObject *item )
 {
-	GtkWidget *treeview;
-	GtkTreeSelection *selection;
-	GList *listrows, *irow;
-	GtkTreeModel *tm_model;
-	GtkTreePath *path;
+	GtkTreeView *treeview;
+	GtkTreeModel *model;
+	gboolean is_expanded;
 	GtkTreeIter iter;
-	NAObject *object;
-	GtkTreeModelFilter *tmf_model;
-	GtkTreeStore *ts_model;
-	GtkTreeIter ts_iter;
-	GSList *profiles, *ip;
-
-	treeview = get_actions_list_widget( window );
-	selection = gtk_tree_view_get_selection( GTK_TREE_VIEW( treeview ));
-	listrows = gtk_tree_selection_get_selected_rows( selection, &tm_model );
-
-	for( irow = listrows ; irow ; irow = irow->next ){
-
-		path = ( GtkTreePath * ) irow->data;
-		gtk_tree_model_get_iter( tm_model, &iter, path );
-		gtk_tree_model_get( tm_model, &iter, IACTIONS_LIST_NAOBJECT_COLUMN, &object, -1 );
-		g_assert( object );
-		g_assert( NA_IS_OBJECT( object ));
+	gboolean iterok, stop;
+	NAObject *iter_object;
 
-		tmf_model = GTK_TREE_MODEL_FILTER( gtk_tree_view_get_model( GTK_TREE_VIEW( treeview )));
-		ts_model = GTK_TREE_STORE( gtk_tree_model_filter_get_model( tmf_model ));
-		gtk_tree_model_get_iter( GTK_TREE_MODEL( ts_model ), &ts_iter, path );
+	g_return_val_if_fail( NACT_IS_IACTIONS_LIST( instance ), FALSE );
+	g_return_val_if_fail( NA_IS_OBJECT_ITEM( item ), FALSE );
 
-		if( NA_IS_ACTION( object )){
-			g_assert( object == NA_OBJECT( action ));
-			/*g_debug( "nact_iactions_list_update_selected: selected action=%p", object );*/
-			setup_action( treeview, ts_model, &ts_iter, action );
+	treeview = get_actions_list_treeview( instance );
+	model = gtk_tree_view_get_model( treeview );
+	iterok = gtk_tree_model_get_iter_first( model, &iter );
+	stop = FALSE;
+	is_expanded = FALSE;
 
-		} else {
-			g_assert( NA_IS_ACTION_PROFILE( object ));
-			/*g_debug( "nact_iactions_list_update_selected: selected profile=%p", object );*/
-			profiles = na_action_get_profiles( action );
-			for( ip = profiles ; ip ; ip = ip->next ){
-				if( object == NA_OBJECT( ip->data )){
-					setup_profile( treeview, ts_model, &ts_iter, NA_ACTION_PROFILE( ip->data ));
-					break;
-				}
-			}
+	while( iterok && !stop ){
+		gtk_tree_model_get( model, &iter, IACTIONS_LIST_NAOBJECT_COLUMN, &iter_object, -1 );
 
-			if( gtk_tree_path_up( path )){
-				gtk_tree_model_get_iter( GTK_TREE_MODEL( ts_model ), &ts_iter, path );
-				setup_action( treeview, ts_model, &ts_iter, action );
-			}
+		if( iter_object == item ){
+			GtkTreePath *path = gtk_tree_model_get_path( model, &iter );
+			is_expanded = gtk_tree_view_row_expanded( treeview, path );
+			gtk_tree_path_free( path );
+			stop = TRUE;
 		}
+
+		g_object_unref( iter_object );
+		iterok = gtk_tree_model_iter_next( model, &iter );
 	}
+
+	return( is_expanded );
 }
 
 /**
- * Are we in edition mode (vs. selection only mode) ?
+ * nact_iactions_list_is_only_actions_mode:
+ * @window: this #NactIActionsList instance.
+ *
+ * Returns %TRUE if only actions should be displayed in the treeview.
  */
-void
-nact_iactions_list_set_edition_mode( NactWindow *window, gboolean edition )
+gboolean
+nact_iactions_list_is_only_actions_mode( NactIActionsList *instance )
 {
-	g_assert( NACT_IS_IACTIONS_LIST( window ));
-	g_object_set_data( G_OBJECT( window ), IS_EDITION_MODE, GINT_TO_POINTER( edition ));
+	return(( gboolean ) GPOINTER_TO_INT( g_object_get_data( G_OBJECT( instance ), SHOW_ONLY_ACTIONS_MODE )));
 }
 
 /**
- * Does the IActionsList box support multiple selection ?
+ * nact_iactions_list_select_row:
+ * @window: this #NactIActionsList instance.
+ * @path: a #GtkTreePath.
  */
 void
-nact_iactions_list_set_multiple_selection( NactWindow *window, gboolean multiple )
+nact_iactions_list_select_row( NactIActionsList *instance, GtkTreePath *path )
 {
-	GtkWidget *list;
+	GtkTreeView *treeview;
 	GtkTreeSelection *selection;
+	GtkTreeModel *model;
+	GtkTreeIter iter;
 
-	g_assert( NACT_IS_IACTIONS_LIST( window ));
-	g_object_set_data( G_OBJECT( window ), ACCEPT_MULTIPLE_SELECTION, GINT_TO_POINTER( multiple ));
+	treeview = get_actions_list_treeview( instance );
+	selection = gtk_tree_view_get_selection( treeview );
+	model = gtk_tree_view_get_model( treeview );
 
-	list = get_actions_list_widget( window );
-	selection = gtk_tree_view_get_selection( GTK_TREE_VIEW( list ));
-	gtk_tree_selection_set_mode( selection, multiple ? GTK_SELECTION_MULTIPLE : GTK_SELECTION_SINGLE );
+	if( gtk_tree_model_get_iter( model, &iter, path )){
+		gtk_tree_selection_select_iter( selection, &iter );
+	}
 }
 
 /**
- * Should the IActionsList interface trigger a 'on_selection_changed'
- * message when the ActionsList list is filled ?
+ * nact_iactions_list_set_dnd_mode:
+ * @window: this #NactIActionsList instance.
+ * @have_dnd: whether the treeview implements drag and drop ?
+ *
+ * When set to %TRUE, the corresponding tree model will implement the
+ * GtkTreeDragSource and the GtkTreeDragDest interfaces.
+ *
+ * This property defaults to %FALSE.
  */
 void
-nact_iactions_list_set_send_selection_changed_on_fill_list( NactWindow *window, gboolean send_message )
+nact_iactions_list_set_dnd_mode( NactIActionsList *instance, gboolean have_dnd )
 {
-	g_assert( NACT_IS_IACTIONS_LIST( window ));
-	g_object_set_data( G_OBJECT( window ), SEND_SELECTION_CHANGED_MESSAGE, GINT_TO_POINTER( send_message ));
+	g_object_set_data( G_OBJECT( instance ), HAVE_DND_MODE, GINT_TO_POINTER( have_dnd ));
 }
 
 /**
- * Is the IActionsList interface currently filling the ActionsList ?
+ * nact_iactions_list_set_multiple_selection_mode:
+ * @window: this #NactIActionsList instance.
+ * @multiple: whether the treeview does support multiple selection ?
+ *
+ * If %FALSE, only one item can selected at same time. Set to %TRUE to
+ * be able to have multiple items simultaneously selected.
+ *
+ * This property defaults to %FALSE.
  */
 void
-nact_iactions_list_set_is_filling_list( NactWindow *window, gboolean is_filling )
+nact_iactions_list_set_multiple_selection_mode( NactIActionsList *instance, gboolean multiple )
 {
-	g_assert( NACT_IS_IACTIONS_LIST( window ));
-	g_object_set_data( G_OBJECT( window ), IS_FILLING_LIST, GINT_TO_POINTER( is_filling ));
+	GtkTreeView *treeview;
+	GtkTreeSelection *selection;
+
+	treeview = get_actions_list_treeview( instance );
+	selection = gtk_tree_view_get_selection( treeview );
+	gtk_tree_selection_set_mode( selection, multiple ? GTK_SELECTION_MULTIPLE : GTK_SELECTION_SINGLE );
 }
 
 /**
- * Does the TreeView implements Drag&Drop ?
+ * nact_iactions_list_set_only_actions_mode:
+ * @window: this #NactIActionsList instance.
+ * @only_actions: whether the treeview must only display actions ?
+ *
+ * When @only_actions is %TRUE, then the treeview will only display the
+ * list of actions in alphabetical order of their label. In this mode,
+ * the actual value of the 'Display in alphabetical order' preference
+ * is ignored.
+ *
+ * If @only_actions is %FALSE, the the treeview display all the tree
+ * of menus, submenus, actions and profiles.
+ *
+ * This property defaults to %FALSE.
  */
 void
-nact_iactions_list_set_dnd_mode( NactWindow *window, gboolean have_dnd )
+nact_iactions_list_set_only_actions_mode( NactIActionsList *instance, gboolean only_actions )
 {
-	g_assert( NACT_IS_IACTIONS_LIST( window ));
-	g_object_set_data( G_OBJECT( window ), HAVE_DND_MODE, GINT_TO_POINTER( have_dnd ));
+	g_object_set_data( G_OBJECT( instance ), SHOW_ONLY_ACTIONS_MODE, GINT_TO_POINTER( only_actions ));
 }
 
-static GSList *
-v_get_actions( NactWindow *window )
+/*
+ * Collapse / expand if actions has more than one profile
+ */
+void
+nact_iactions_list_toggle_collapse( NactIActionsList *instance, const NAObject *item )
 {
-	NactIActionsList *instance;
-
-	g_assert( NACT_IS_IACTIONS_LIST( window ));
-	instance = NACT_IACTIONS_LIST( window );
+	static const gchar *thisfn = "nact_iactions_list_toggle_collapse";
+	GtkTreeView *treeview;
+	GtkTreeModel *model;
+	GtkTreeIter iter;
+	gboolean iterok, stop;
+	NAObject *iter_object;
 
-	if( NACT_IACTIONS_LIST_GET_INTERFACE( instance )->get_actions ){
-		return( NACT_IACTIONS_LIST_GET_INTERFACE( instance )->get_actions( window ));
-	}
+	g_return_if_fail( NACT_IS_IACTIONS_LIST( instance ));
+	g_return_if_fail( NA_IS_OBJECT_ITEM( item ));
 
-	return( NULL );
-}
+	treeview = get_actions_list_treeview( instance );
+	model = gtk_tree_view_get_model( treeview );
+	iterok = gtk_tree_model_get_iter_first( model, &iter );
+	stop = FALSE;
 
-/*static void
-v_set_sorted_actions( NactWindow *window, GSList *actions )
-{
-	g_assert( NACT_IS_IACTIONS_LIST( window ));
-	NactIActionsList *instance = NACT_IACTIONS_LIST( window );
+	while( iterok && !stop ){
 
-	if( NACT_IACTIONS_LIST_GET_INTERFACE( instance )->set_sorted_actions ){
-		NACT_IACTIONS_LIST_GET_INTERFACE( instance )->set_sorted_actions( window, actions );
-	}
-}*/
+		gtk_tree_model_get( model, &iter, IACTIONS_LIST_NAOBJECT_COLUMN, &iter_object, -1 );
+		if( iter_object == item ){
 
-static gboolean
-v_on_button_press_event( GtkWidget *widget, GdkEventButton *event, gpointer user_data )
-{
-	/*static const gchar *thisfn = "nact_iactions_list_v_on_button_pres_event";
-	g_debug( "%s: widget=%p, event=%p, user_data=%p", thisfn, widget, event, user_data );*/
+			if( na_object_get_items_count( item ) > 1 ){
 
-	gboolean stop = FALSE;
-	NactIActionsList *instance;
+				GtkTreePath *path = gtk_tree_model_get_path( model, &iter );
 
-	g_assert( NACT_IS_IACTIONS_LIST( user_data ));
-	g_assert( NACT_IS_WINDOW( user_data ));
-	instance = NACT_IACTIONS_LIST( user_data );
+				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, ( void * ) item );
 
-	if( NACT_IACTIONS_LIST_GET_INTERFACE( instance )->on_button_press_event ){
-		stop = NACT_IACTIONS_LIST_GET_INTERFACE( instance )->on_button_press_event( widget, event, user_data );
-	}
+				} else {
+					gtk_tree_view_expand_row( GTK_TREE_VIEW( treeview ), path, TRUE );
+					g_debug( "%s: action=%p expanded", thisfn, ( void * ) item );
+				}
 
-	if( !stop ){
-		if( event->type == GDK_2BUTTON_PRESS ){
-			if( NACT_IACTIONS_LIST_GET_INTERFACE( instance )->on_double_click ){
-				stop = NACT_IACTIONS_LIST_GET_INTERFACE( instance )->on_double_click( widget, event, user_data );
+				gtk_tree_path_free( path );
 			}
+			stop = TRUE;
 		}
+
+		g_object_unref( iter_object );
+		iterok = gtk_tree_model_iter_next( model, &iter );
 	}
-	return( stop );
 }
 
-static gboolean
-v_on_key_pressed_event( GtkWidget *widget, GdkEventKey *event, gpointer user_data )
+/*
+ * item modified: italic
+ * item not saveable (invalid): red
+ */
+static void
+display_label( GtkTreeViewColumn *column, GtkCellRenderer *cell, GtkTreeModel *model, GtkTreeIter *iter, NactIActionsList *instance )
 {
-	/*static const gchar *thisfn = "nact_iactions_list_v_on_key_pressed_event";
-	g_debug( "%s: widget=%p, event=%p, user_data=%p", thisfn, widget, event, user_data );*/
-
-	gboolean stop = FALSE;
-	NactIActionsList *instance;
-
-	g_assert( NACT_IS_IACTIONS_LIST( user_data ));
-	g_assert( NACT_IS_WINDOW( user_data ));
-	g_assert( event->type == GDK_KEY_PRESS );
+	NAObject *object;
+	gchar *label;
+	gboolean modified = FALSE;
+	gboolean valid = TRUE;
 
-	instance = NACT_IACTIONS_LIST( user_data );
+	gtk_tree_model_get( model, iter, IACTIONS_LIST_NAOBJECT_COLUMN, &object, -1 );
 
-	if( NACT_IACTIONS_LIST_GET_INTERFACE( instance )->on_key_pressed_event ){
-		stop = NACT_IACTIONS_LIST_GET_INTERFACE( instance )->on_key_pressed_event( widget, event, user_data );
-	}
+	if( object ){
+		g_assert( NA_IS_OBJECT( object ));
+		label = na_object_get_label( object );
+		modified = na_object_is_modified( object );
+		valid = na_object_is_valid( object );
 
-	if( !stop ){
-		if( event->keyval == GDK_Return || event->keyval == GDK_KP_Enter ){
-			if( NACT_IACTIONS_LIST_GET_INTERFACE( instance )->on_enter_key_pressed ){
-				stop = NACT_IACTIONS_LIST_GET_INTERFACE( instance )->on_enter_key_pressed( widget, event, user_data );
-			}
+		if( modified ){
+			g_object_set( cell, "style", PANGO_STYLE_ITALIC, "style-set", TRUE, NULL );
+		} else {
+			g_object_set( cell, "style-set", FALSE, NULL );
 		}
-		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 );
-			}
+		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 );
+		g_object_unref( object );
 	}
-	return( stop );
 }
 
-static gboolean
-v_is_modified_action( NactWindow *window, const NAAction *action )
+/*
+ * when expanding a selected row which has childs
+ */
+static void
+extend_selection_to_childs( NactIActionsList *instance, GtkTreeView *treeview, GtkTreeModel *model, GtkTreeIter *parent )
 {
-	if( NACT_IACTIONS_LIST_GET_INTERFACE( window )->is_modified_action ){
-		return( NACT_IACTIONS_LIST_GET_INTERFACE( window )->is_modified_action( window, action ));
+	GtkTreeSelection *selection;
+	GtkTreeIter iter;
+	gboolean ok;
+
+	selection = gtk_tree_view_get_selection( treeview );
+
+	ok = gtk_tree_model_iter_children( model, &iter, parent );
+
+	while( ok ){
+		GtkTreePath *path = gtk_tree_model_get_path( model, &iter );
+		gtk_tree_selection_select_path( selection, path );
+		gtk_tree_path_free( path );
+		ok = gtk_tree_model_iter_next( model, &iter );
 	}
+}
 
-	return( FALSE );
+static void
+free_items_flat_list_callback( NactIActionsList *instance, GSList *items )
+{
+	g_slist_foreach( items, ( GFunc ) g_object_unref, NULL );
+	g_slist_free( items );
 }
 
-static gboolean
-v_is_valid_action( NactWindow *window, const NAAction *action )
+static GtkTreeView *
+get_actions_list_treeview( NactIActionsList *instance )
 {
-	if( NACT_IACTIONS_LIST_GET_INTERFACE( window )->is_valid_action ){
-		return( NACT_IACTIONS_LIST_GET_INTERFACE( window )->is_valid_action( window, action ));
-	}
+	GtkTreeView *treeview;
 
-	return( FALSE );
+	treeview = GTK_TREE_VIEW( base_window_get_widget( BASE_WINDOW( instance ), "ActionsList" ));
+	g_assert( GTK_IS_TREE_VIEW( treeview ));
+
+	return( treeview );
 }
 
+/*
+ * builds the tree
+ */
 static gboolean
-v_is_modified_profile( NactWindow *window, const NAActionProfile *profile )
+get_item( NactTreeModel *model, GtkTreePath *path, NAObject *object, GSList **items )
 {
-	if( NACT_IACTIONS_LIST_GET_INTERFACE( window )->is_modified_profile ){
-		return( NACT_IACTIONS_LIST_GET_INTERFACE( window )->is_modified_profile( window, profile ));
+	if( gtk_tree_path_get_depth( path ) == 1 ){
+		*items = g_slist_prepend( *items, object );
 	}
 
+	/* don't stop iteration */
 	return( FALSE );
 }
 
 static gboolean
-v_is_valid_profile( NactWindow *window, const NAActionProfile *profile )
+have_dnd_mode( NactIActionsList *instance )
 {
-	if( NACT_IACTIONS_LIST_GET_INTERFACE( window )->is_valid_profile ){
-		return( NACT_IACTIONS_LIST_GET_INTERFACE( window )->is_valid_profile( window, profile ));
-	}
+	return(( gboolean ) GPOINTER_TO_INT( g_object_get_data( G_OBJECT( instance ), HAVE_DND_MODE )));
+}
+
+/*
+ * count _all_ modified rows, including profiles
+ */
+static gboolean
+is_modified_item( NactTreeModel *model, GtkTreePath *path, NAObject *object, GSList **items )
+{
+	/*if( !NA_IS_ACTION_PROFILE( object )){*/
+		if( na_object_is_modified( object )){
+			*items = g_slist_prepend( *items, g_object_ref( object ));
+		}
+	/*}*/
 
+	/* don't stop iteration */
 	return( FALSE );
 }
 
 static void
-on_selection_changed( GtkTreeSelection *selection, NactIActionsList *instance )
+iter_on_selection( NactIActionsList *instance, FnIterOnSelection fn_iter, gpointer user_data )
 {
-	gboolean send_message, is_filling;
-	GSList *selected_items;
+	GtkTreeView *treeview;
+	GtkTreeSelection *selection;
+	GtkTreeModel *model;
+	GList *listrows, *ipath;
+	GtkTreePath *path;
+	GtkTreeIter iter;
+	NAObject *object;
+	gboolean stop = FALSE;
 
-	send_message = GPOINTER_TO_INT( g_object_get_data( G_OBJECT( instance ), SEND_SELECTION_CHANGED_MESSAGE ));
-	is_filling = GPOINTER_TO_INT( g_object_get_data( G_OBJECT( instance ), IS_FILLING_LIST ));
+	treeview = get_actions_list_treeview( instance );
+	selection = gtk_tree_view_get_selection( treeview );
+	listrows = gtk_tree_selection_get_selected_rows( selection, &model );
+	listrows = g_list_reverse( listrows );
 
-	selected_items = nact_iactions_list_get_selected_items( instance );
+	for( ipath = listrows ; !stop && ipath ; ipath = ipath->next ){
 
-	if( send_message || !is_filling ){
-		if( NACT_IACTIONS_LIST_GET_INTERFACE( instance )->on_selection_changed ){
-			NACT_IACTIONS_LIST_GET_INTERFACE( instance )->on_selection_changed( instance, selected_items );
-		}
+		path = ( GtkTreePath * ) ipath->data;
+		gtk_tree_model_get_iter( model, &iter, path );
+		gtk_tree_model_get( model, &iter, IACTIONS_LIST_NAOBJECT_COLUMN, &object, -1 );
+
+		stop = fn_iter( instance, treeview, model, &iter, object, user_data );
+
+		g_object_unref( object );
 	}
+
+	g_list_foreach( listrows, ( GFunc ) gtk_tree_path_free, NULL );
+	g_list_free( listrows );
 }
 
-/*
- * action modified: italic
- * action not saveable: red
- */
-static void
-display_label( GtkTreeViewColumn *column, GtkCellRenderer *cell, GtkTreeModel *model, GtkTreeIter *iter, NactWindow *window )
+static gboolean
+on_button_press_event( GtkWidget *widget, GdkEventButton *event, NactIActionsList *instance )
 {
-	NAObject *object;
-	gchar *label;
-	gboolean modified = FALSE;
-	gboolean valid = TRUE;
-
-	gtk_tree_model_get( model, iter, IACTIONS_LIST_NAOBJECT_COLUMN, &object, -1 );
+	/*static const gchar *thisfn = "nact_iactions_list_v_on_button_pres_event";
+	g_debug( "%s: widget=%p, event=%p, user_data=%p", thisfn, widget, event, user_data );*/
 
-	if( object ){
-		g_assert( NA_IS_OBJECT( object ));
-		label = na_object_get_label( object );
+	gboolean stop = FALSE;
 
-		if( is_edition_mode( window )){
-			if( NA_IS_ACTION( object )){
-				modified = v_is_modified_action( window, NA_ACTION( object ));
-				valid = v_is_valid_action( window, NA_ACTION( object ));
+	if( event->type == GDK_2BUTTON_PRESS ){
+		toggle_collapse( instance );
+		stop = TRUE;
+	}
 
-			} 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 ));
-			}
-		}
+	return( stop );
+}
 
-		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 );
-		}
+static gboolean
+on_key_pressed_event( GtkWidget *widget, GdkEventKey *event, NactIActionsList *instance )
+{
+	/*static const gchar *thisfn = "nact_iactions_list_v_on_key_pressed_event";
+	g_debug( "%s: widget=%p, event=%p, user_data=%p", thisfn, widget, event, user_data );*/
 
-		g_object_set( cell, "text", label, NULL );
+	gboolean stop = FALSE;
 
-		g_free( label );
+	if( event->keyval == GDK_Return || event->keyval == GDK_KP_Enter ){
+		toggle_collapse( instance );
+		stop = TRUE;
 	}
+
+	return( stop );
 }
 
+/*
+ * this is our handler of "changed" signal emitted by the treeview
+ */
 static void
-setup_action( GtkWidget *treeview, GtkTreeStore *model, GtkTreeIter *iter, NAAction *action )
+on_treeview_selection_changed( GtkTreeSelection *selection, NactIActionsList *instance )
 {
-	static const gchar *thisfn = "nact_iactions_list_setup_action";
-	GtkStockItem item;
-	GdkPixbuf* icon = NULL;
-	gint width, height;
-	GError* error = NULL;
-
-	gchar *label = na_action_get_label( action );
-	gchar *iconname = na_action_get_icon( action );
-
-	/* TODO: use the same algorythm than Nautilus to find and
-	 * display an icon + move the code to NAAction class +
-	 * remove na_action_get_verified_icon_name
-	 */
-	if( iconname ){
-		if( gtk_stock_lookup( iconname, &item )){
-			icon = gtk_widget_render_icon( treeview, iconname, GTK_ICON_SIZE_MENU, NULL );
-
-		} else if( g_file_test( iconname, G_FILE_TEST_EXISTS )
-			   && g_file_test( iconname, G_FILE_TEST_IS_REGULAR )){
-
-			gtk_icon_size_lookup (GTK_ICON_SIZE_MENU, &width, &height);
-			icon = gdk_pixbuf_new_from_file_at_size( iconname, width, height, &error );
-			if( error ){
-				g_warning( "%s: iconname=%s, error=%s", thisfn, iconname, error->message );
-				g_error_free( error );
-				error = NULL;
-				icon = NULL;
-			}
-		}
-	}
+	GSList *selected_items;
 
-	gtk_tree_store_set( model, iter, IACTIONS_LIST_ICON_COLUMN, icon, IACTIONS_LIST_LABEL_COLUMN, label, -1 );
+	selected_items = nact_iactions_list_get_selected_items( instance );
 
-	g_free( iconname );
-	g_free( label );
+	if( !nact_iactions_list_is_filling_list( instance )){
+		g_signal_emit_by_name( instance, IACTIONS_LIST_SIGNAL_SELECTION_CHANGED, selected_items );
+	}
 }
 
+/*
+ * our handler for "item-updated" emitted whan an item is modified
+ * this let us transform the signal in a virtual function
+ * so that our implementors have the best of two worlds ;-)
+ */
 static void
-setup_profile( GtkWidget *treeview, GtkTreeStore *model, GtkTreeIter *iter, NAActionProfile *profile )
+on_iactions_list_item_updated( NactIActionsList *instance, GSList *updated_items )
 {
-	gchar *label = na_action_profile_get_label( profile );
-	gtk_tree_store_set( model, iter, IACTIONS_LIST_LABEL_COLUMN, label, -1);
-	g_free( label );
+	if( NACT_IACTIONS_LIST_GET_INTERFACE( instance )->item_updated ){
+		NACT_IACTIONS_LIST_GET_INTERFACE( instance )->item_updated( instance, updated_items );
+	}
 }
 
-static GtkWidget *
-get_actions_list_widget( NactWindow *window )
+/*
+ * rewind all the parent hierarchy of each modified item to update its status
+ */
+static void
+on_iactions_list_item_updated_treeview( NactIActionsList *instance, GSList *updated_items )
 {
-	return( base_window_get_widget( BASE_WINDOW( window ), "ActionsList" ));
+	GtkTreeView *treeview;
+	NactTreeModel *model;
+	GSList *it;
+
+	treeview = get_actions_list_treeview( instance );
+	model = NACT_TREE_MODEL( gtk_tree_view_get_model( treeview ));
+
+	for( it = updated_items ; it ; it=it->next ){
+		nact_tree_model_update_parent( model, NA_OBJECT( it->data ));
+	}
 }
 
-static GSList *
-get_expanded_rows( NactWindow *window )
+/*
+ * our handler for "selection-changed" emitted by the interface
+ * this let us transform the signal in a virtual function
+ * so that our implementors have the best of two worlds ;-)
+ */
+static void
+on_iactions_list_selection_changed( NactIActionsList *instance, GSList *selected_items )
 {
-	GSList *expanded = NULL;
-	GtkWidget *treeview = get_actions_list_widget( window );
-	GtkTreeModel *model = gtk_tree_view_get_model( GTK_TREE_VIEW( treeview ));
+	if( NACT_IACTIONS_LIST_GET_INTERFACE( instance )->selection_changed ){
+		NACT_IACTIONS_LIST_GET_INTERFACE( instance )->selection_changed( instance, selected_items );
+	}
+}
 
+static void
+select_first_row( NactIActionsList *instance )
+{
+	static const gchar *thisfn = "nact_iactions_list_select_first_row";
+	GtkTreeView *treeview;
+	GtkTreeSelection *selection;
+	GtkTreeModel *model;
 	GtkTreeIter iter;
-	gboolean iterok = gtk_tree_model_get_iter_first( model, &iter );
-	NAObject *object;
-	GtkTreePath *path;
-
-	while( iterok ){
-		gtk_tree_model_get( model, &iter, IACTIONS_LIST_NAOBJECT_COLUMN, &object, -1 );
+	gboolean iterok;
 
-		path = gtk_tree_model_get_path( model, &iter );
+	g_debug( "%s: instance=%p", thisfn, ( void * ) instance );
 
-		if( gtk_tree_view_row_expanded( GTK_TREE_VIEW( treeview ), path )){
-			expanded = g_slist_prepend( expanded, object );
-		}
+	treeview = get_actions_list_treeview( instance );
+	selection = gtk_tree_view_get_selection( treeview );
+	model = gtk_tree_view_get_model( treeview );
 
-		gtk_tree_path_free( path );
-
-		iterok = gtk_tree_model_iter_next( model, &iter );
+	iterok = gtk_tree_model_get_iter_first( model, &iter );
+	if( !iterok ){
+		g_debug( "%s: empty actions list: unselect all", thisfn );
+		gtk_tree_selection_unselect_all( selection );
+	} else {
+		gtk_tree_selection_select_iter( selection, &iter );
 	}
+}
 
-	return( expanded );
+static void
+set_is_filling_list( NactIActionsList *instance, gboolean is_filling )
+{
+	g_object_set_data( G_OBJECT( instance ), IS_FILLING_LIST, GINT_TO_POINTER( is_filling ));
 }
 
 static void
-expand_rows( NactWindow *window, GSList *expanded )
+toggle_collapse( NactIActionsList *instance )
 {
-	GtkWidget *treeview = get_actions_list_widget( window );
-	GtkTreeModel *model = gtk_tree_view_get_model( GTK_TREE_VIEW( treeview ));
+	int toggle = TOGGLE_UNDEFINED;
 
-	GtkTreeIter iter;
-	gboolean iterok = gtk_tree_model_get_iter_first( model, &iter );
-	NAObject *object;
-	GSList *is;
-	GtkTreePath *path;
+	iter_on_selection( instance, ( FnIterOnSelection ) toggle_collapse_iter, &toggle );
+}
 
-	while( iterok ){
-		gtk_tree_model_get( model, &iter, IACTIONS_LIST_NAOBJECT_COLUMN, &object, -1 );
+static gboolean
+toggle_collapse_iter( NactIActionsList *instance,
+						GtkTreeView *treeview,
+						GtkTreeModel *model,
+						GtkTreeIter *iter,
+						NAObject *object,
+						gpointer user_data )
+{
+	guint count;
+	guint *toggle;
 
-		for( is = expanded ; is ; is = is->next ){
-			if( object == NA_OBJECT( is->data )){
+	toggle = ( guint * ) user_data;
 
-				path = gtk_tree_model_get_path( model, &iter );
-				gtk_tree_view_expand_row( GTK_TREE_VIEW( treeview ), path, TRUE );
-				gtk_tree_path_free( path );
+	if( NA_IS_OBJECT_ITEM( object )){
 
-				break;
+		GtkTreePath *path = gtk_tree_model_get_path( model, iter );
+
+		if( NA_IS_OBJECT_ITEM( object )){
+			count = na_object_get_items_count( object );
+			if( count > 1 ){
+				toggle_collapse_row( treeview, path, toggle );
 			}
 		}
 
-		iterok = gtk_tree_model_iter_next( model, &iter );
+		gtk_tree_path_free( path );
+
+		/* do not extend selection */
+		if( *toggle == TOGGLE_EXPAND && FALSE ){
+			extend_selection_to_childs( instance, treeview, model, iter );
+		}
 	}
+
+	/* do not stop iteration */
+	return( FALSE );
 }
 
+/*
+ * toggle mode can be undefined, collapse or expand
+ * it is set on the first row
+ */
 static void
-free_expanded_list( GSList *expanded )
+toggle_collapse_row( GtkTreeView *treeview, GtkTreePath *path, guint *toggle )
 {
-	g_slist_free( expanded );
-}
+	if( *toggle == TOGGLE_UNDEFINED ){
+		*toggle = gtk_tree_view_row_expanded( treeview, path ) ? TOGGLE_COLLAPSE : TOGGLE_EXPAND;
+	}
 
-static gboolean
-is_edition_mode( NactWindow *window )
-{
-	return( GPOINTER_TO_INT( g_object_get_data( G_OBJECT( window ), IS_EDITION_MODE )));
+	if( *toggle == TOGGLE_COLLAPSE ){
+		if( gtk_tree_view_row_expanded( treeview, path )){
+			gtk_tree_view_collapse_row( treeview, path );
+		}
+	} else {
+		if( !gtk_tree_view_row_expanded( treeview, path )){
+			gtk_tree_view_expand_row( treeview, path, TRUE );
+		}
+	}
 }
diff --git a/src/nact/nact-iactions-list.h b/src/nact/nact-iactions-list.h
index 17cf327..3e4cdda 100644
--- a/src/nact/nact-iactions-list.h
+++ b/src/nact/nact-iactions-list.h
@@ -31,17 +31,7 @@
 #ifndef __NACT_IACTIONS_LIST_H__
 #define __NACT_IACTIONS_LIST_H__
 
-/*
- * NactIActionsList interface definition.
- *
- * This interface defines some API against the ActionsList listbox.
- * Our NactWindow may implement it in order to personalize the
- * behaviour of the listbox.
- */
-
-#include <gtk/gtk.h>
-
-#include "nact-window.h"
+#include <common/na-object-class.h>
 
 G_BEGIN_DECLS
 
@@ -58,42 +48,56 @@ typedef struct {
 	GTypeInterface                    parent;
 	NactIActionsListInterfacePrivate *private;
 
-	/* api */
-	GSList * ( *get_actions )          ( NactWindow *window );
-	void     ( *on_selection_changed ) ( NactIActionsList *instance, GSList *selected_items );
-	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 );
+	/**
+	 * selection_changed:
+	 * @instance: this #NactIActionsList instance.
+	 * @selected_items: currently selected items.
+	 */
+	void ( *selection_changed )( NactIActionsList *instance, GSList *selected_items );
+
+	/**
+	 * item_updated:
+	 * @instance: this #NactIActionsList instance.
+	 * @updated_items: flat list of updated items.
+	 */
+	void ( *item_updated )     ( NactIActionsList *instance, GSList *updated_items );
 }
 	NactIActionsListInterface;
 
+/* signals
+ */
+#define IACTIONS_LIST_SIGNAL_SELECTION_CHANGED			"nact-iactions-list-selection-changed"
+#define IACTIONS_LIST_SIGNAL_ITEM_UPDATED				"nact-iactions-list-item-updated"
+
 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, 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_initial_load_toplevel( NactIActionsList *instance );
+void      nact_iactions_list_runtime_init_toplevel( NactIActionsList *instance, GSList *actions );
+void      nact_iactions_list_all_widgets_showed( NactIActionsList *instance );
+void      nact_iactions_list_dispose( NactIActionsList *instance );
+
+GSList   *nact_iactions_list_delete_selection( NactIActionsList *instance, GtkTreePath **path );
+void      nact_iactions_list_fill( NactIActionsList *instance, GSList *items );
+GSList   *nact_iactions_list_free_items_list( NactIActionsList *instance, GSList *items );
+guint     nact_iactions_list_get_items_count( NactIActionsList *instance );
+GSList   *nact_iactions_list_get_items( NactIActionsList *instance );
+GSList   *nact_iactions_list_get_modified_items( NactIActionsList *instance );
 GSList   *nact_iactions_list_get_selected_items( NactIActionsList *instance );
-void      nact_iactions_list_set_selection( NactWindow *window, GType type, const gchar *uuid, const gchar *label );
-void      nact_iactions_list_select_first( NactWindow *window );
-/*void      nact_iactions_list_set_focus( 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_edition_mode( NactWindow *window, gboolean mode );
-void      nact_iactions_list_set_multiple_selection( NactWindow *window, gboolean multiple );
-void      nact_iactions_list_set_send_selection_changed_on_fill_list( NactWindow *window, gboolean send_message );
-void      nact_iactions_list_set_is_filling_list( NactWindow *window, gboolean is_filling );
-void      nact_iactions_list_set_dnd_mode( NactWindow *window, gboolean have_dnd );
+void      nact_iactions_list_insert_items( NactIActionsList *instance, GSList *items );
+gboolean  nact_iactions_list_is_expanded( NactIActionsList *instance, const NAObject *item );
+gboolean  nact_iactions_list_is_filling_list( NactIActionsList *instance );
+gboolean  nact_iactions_list_is_only_actions_mode( NactIActionsList *instance );
+void      nact_iactions_list_select_row( NactIActionsList *instance, GtkTreePath *path );
+void      nact_iactions_list_set_dnd_mode( NactIActionsList *instance, gboolean have_dnd );
+void      nact_iactions_list_set_multiple_selection_mode( NactIActionsList *instance, gboolean multiple );
+void      nact_iactions_list_set_only_actions_mode( NactIActionsList *instance, gboolean only_actions );
+void      nact_iactions_list_toggle_collapse( NactIActionsList *instance, const NAObject *item );
+
+/*
+void      nact_list_actions_insert_item( NactMainWindow *window, NAObject *item );
+void      nact_list_actions_set_selection( NactMainWindow *window, GType type, const gchar *uuid, const gchar *label );
+void      nact_list_actions_update_selected( NactMainWindow *window, NAAction *action );
+*/
 
 G_END_DECLS
 
diff --git a/src/nact/nact-iadvanced-tab.c b/src/nact/nact-iadvanced-tab.c
index 3ab23d6..031c52c 100644
--- a/src/nact/nact-iadvanced-tab.c
+++ b/src/nact/nact-iadvanced-tab.c
@@ -35,11 +35,15 @@
 #include <glib/gi18n.h>
 #include <string.h>
 
+#include <common/na-object-api.h>
+#include <common/na-obj-action-class.h>
+#include <common/na-obj-profile.h>
 #include <common/na-utils.h>
 
-#include "nact-main-window.h"
+#include "base-window.h"
+#include "base-iprefs.h"
+#include "nact-main-tab.h"
 #include "nact-iadvanced-tab.h"
-#include "nact-iprefs.h"
 
 /* private interface data
  */
@@ -56,29 +60,30 @@ enum {
 	SCHEMES_N_COLUMN
 };
 
-static GType            register_type( void );
-static void             interface_base_init( NactIAdvancedTabInterface *klass );
-static void             interface_base_finalize( NactIAdvancedTabInterface *klass );
-
-static NAActionProfile *v_get_edited_profile( NactWindow *window );
-static void             v_field_modified( NactWindow *window );
-
-static void             on_scheme_selection_toggled( GtkCellRendererToggle *renderer, gchar *path, gpointer user_data );
-static void             on_scheme_keyword_edited( GtkCellRendererText *renderer, const gchar *path, const gchar *text, gpointer user_data );
-static void             on_scheme_desc_edited( GtkCellRendererText *renderer, const gchar *path, const gchar *text, gpointer user_data );
-static void             on_scheme_list_selection_changed( GtkTreeSelection *selection, gpointer user_data );
-static void             on_add_scheme_clicked( GtkButton *button, gpointer user_data );
-static void             on_remove_scheme_clicked( GtkButton *button, gpointer user_data );
-static void             scheme_cell_edited( NactWindow *window, const gchar *path_string, const gchar *text, gint column, gboolean *state, gchar **old_text );
-static GtkTreeView     *get_schemes_tree_view( NactWindow *window );
-static GtkTreeModel    *get_schemes_tree_model( NactWindow *window );
-static void             create_schemes_selection_list( NactWindow *window );
-static gboolean         get_action_schemes_list( GtkTreeModel* scheme_model, GtkTreePath *path, GtkTreeIter* iter, gpointer data );
-static GSList          *get_schemes_default_list( NactWindow *window );
-static gboolean         reset_schemes_list( GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data );
-static void             set_action_schemes( gchar *scheme, GtkTreeModel *model );
-static GtkButton       *get_add_button( NactWindow *window );
-static GtkButton       *get_remove_button( NactWindow *window );
+static GType         register_type( void );
+static void          interface_base_init( NactIAdvancedTabInterface *klass );
+static void          interface_base_finalize( NactIAdvancedTabInterface *klass );
+
+static void          initial_load_create_schemes_selection_list( NactIAdvancedTab *instance );
+static void          runtime_init_connect_signals( NactIAdvancedTab *instance, GtkTreeView *listview );
+static void          runtime_init_setup_values( NactIAdvancedTab *instance, GtkTreeView *listview );
+static void          on_tab_updatable_selection_updated( NactIAdvancedTab *instance, gint count_selected );
+static gboolean      get_action_schemes_list( GtkTreeModel* scheme_model, GtkTreePath *path, GtkTreeIter* iter, GSList **schemes_list );
+static GtkButton    *get_add_button( NactIAdvancedTab *instance );
+static GtkButton    *get_button( NactIAdvancedTab *instance, const gchar *name );
+static GtkButton    *get_remove_button( NactIAdvancedTab *instance );
+static GSList       *get_schemes_default_list( NactIAdvancedTab *instance );
+static GtkTreeModel *get_schemes_tree_model( NactIAdvancedTab *instance );
+static GtkTreeView  *get_schemes_tree_view( NactIAdvancedTab *instance );
+static void          on_add_scheme_clicked( GtkButton *button, NactIAdvancedTab *instance );
+static void          on_remove_scheme_clicked( GtkButton *button, NactIAdvancedTab *instance );
+static void          on_scheme_desc_edited( GtkCellRendererText *renderer, const gchar *path, const gchar *text, NactIAdvancedTab *instance );
+static void          on_scheme_keyword_edited( GtkCellRendererText *renderer, const gchar *path, const gchar *text, NactIAdvancedTab *instance );
+static void          on_scheme_list_selection_changed( GtkTreeSelection *selection, NactIAdvancedTab *instance );
+static void          on_scheme_selection_toggled( GtkCellRendererToggle *renderer, gchar *path, NactIAdvancedTab *instance );
+static gboolean      reset_schemes_list( GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data );
+static void          scheme_cell_edited( NactIAdvancedTab *instance, const gchar *path_string, const gchar *text, gint column, gboolean *state, gchar **old_text );
+static void          set_action_schemes( gchar *scheme, GtkTreeModel *model );
 
 GType
 nact_iadvanced_tab_get_type( void )
@@ -114,7 +119,7 @@ register_type( void )
 
 	type = g_type_register_static( G_TYPE_INTERFACE, "NactIAdvancedTab", &info, 0 );
 
-	g_type_interface_add_prerequisite( type, G_TYPE_OBJECT );
+	g_type_interface_add_prerequisite( type, BASE_WINDOW_TYPE );
 
 	return( type );
 }
@@ -130,9 +135,6 @@ interface_base_init( NactIAdvancedTabInterface *klass )
 
 		klass->private = g_new0( NactIAdvancedTabInterfacePrivate, 1 );
 
-		klass->get_edited_profile = NULL;
-		klass->field_modified = NULL;
-
 		initialized = TRUE;
 	}
 }
@@ -153,240 +155,340 @@ interface_base_finalize( NactIAdvancedTabInterface *klass )
 }
 
 void
-nact_iadvanced_tab_initial_load( NactWindow *dialog )
+nact_iadvanced_tab_initial_load_toplevel( NactIAdvancedTab *instance )
 {
-	static const gchar *thisfn = "nact_iadvanced_tab_initial_load";
+	static const gchar *thisfn = "nact_iadvanced_tab_initial_load_toplevel";
+
+	g_debug( "%s: instance=%p", thisfn, ( void * ) instance );
+
+	initial_load_create_schemes_selection_list( instance );
+}
+
+/*
+ * create the listview
+ * initializes it with default values
+ */
+static void
+initial_load_create_schemes_selection_list( NactIAdvancedTab *instance )
+{
+	static const char *thisfn = "nact_iadvanced_tab_initial_load_create_schemes_selection_list";
+	GtkTreeView *listview;
+	GtkListStore *model;
+	GtkCellRenderer *toggled_cell;
+	GtkTreeViewColumn *column;
+	GtkCellRenderer *text_cell;
+
+	g_debug( "%s: instance=%p", thisfn, ( void * ) instance );
+
+	model = gtk_list_store_new( SCHEMES_N_COLUMN, G_TYPE_BOOLEAN, G_TYPE_STRING, G_TYPE_STRING );
+	listview = get_schemes_tree_view( instance );
+	gtk_tree_view_set_model( listview, GTK_TREE_MODEL( model ));
+	g_object_unref( model );
+
+	toggled_cell = gtk_cell_renderer_toggle_new();
+	column = gtk_tree_view_column_new_with_attributes(
+			"scheme-selected",
+			toggled_cell,
+			"active", SCHEMES_CHECKBOX_COLUMN,
+			NULL );
+	gtk_tree_view_append_column( listview, column );
 
-	g_debug( "%s: dialog=%p", thisfn, ( void * ) dialog );
+	text_cell = gtk_cell_renderer_text_new();
+	g_object_set( G_OBJECT( text_cell ), "editable", TRUE, NULL );
+	column = gtk_tree_view_column_new_with_attributes(
+			"scheme-code",
+			text_cell,
+			"text", SCHEMES_KEYWORD_COLUMN,
+			NULL );
+	gtk_tree_view_append_column( listview, column );
 
-	create_schemes_selection_list( dialog );
+	text_cell = gtk_cell_renderer_text_new();
+	g_object_set( G_OBJECT( text_cell ), "editable", TRUE, NULL );
+	column = gtk_tree_view_column_new_with_attributes(
+			"scheme-description",
+			text_cell,
+			"text", SCHEMES_DESC_COLUMN,
+			NULL );
+	gtk_tree_view_append_column( listview, column );
 }
 
 void
-nact_iadvanced_tab_runtime_init( NactWindow *dialog )
+nact_iadvanced_tab_runtime_init_toplevel( NactIAdvancedTab *instance )
 {
-	static const gchar *thisfn = "nact_iadvanced_tab_runtime_init";
-	GtkTreeView *scheme_widget;
+	static const gchar *thisfn = "nact_iadvanced_tab_runtime_init_toplevel";
+	GtkTreeView *listview;
+
+	g_debug( "%s: instance=%p", thisfn, ( void * ) instance );
+
+	listview = get_schemes_tree_view( instance );
+
+	runtime_init_connect_signals( instance, listview );
+
+	runtime_init_setup_values( instance, listview );
+}
+
+static void
+runtime_init_connect_signals( NactIAdvancedTab *instance, GtkTreeView *listview )
+{
+	static const gchar *thisfn = "nact_iadvanced_tab_runtime_init_connect_signals";
 	GtkTreeViewColumn *column;
 	GList *renderers;
 	GtkButton *add_button, *remove_button;
 
-	g_debug( "%s: dialog=%p", thisfn, ( void * ) dialog );
-
-	scheme_widget = get_schemes_tree_view( dialog );
+	g_debug( "%s: instance=%p, listview=%p", thisfn, ( void * ) instance, ( void * ) listview );
 
-	column = gtk_tree_view_get_column( scheme_widget, SCHEMES_CHECKBOX_COLUMN );
+	column = gtk_tree_view_get_column( listview, SCHEMES_CHECKBOX_COLUMN );
 	renderers = gtk_tree_view_column_get_cell_renderers( column );
-	nact_window_signal_connect( dialog, G_OBJECT( renderers->data ), "toggled", G_CALLBACK( on_scheme_selection_toggled ));
+	g_signal_connect(
+			G_OBJECT( renderers->data ),
+			"toggled",
+			G_CALLBACK( on_scheme_selection_toggled ),
+			instance );
 
-	column = gtk_tree_view_get_column( scheme_widget, SCHEMES_KEYWORD_COLUMN );
+	column = gtk_tree_view_get_column( listview, SCHEMES_KEYWORD_COLUMN );
 	renderers = gtk_tree_view_column_get_cell_renderers( column );
-	nact_window_signal_connect( dialog, G_OBJECT( renderers->data ), "edited", G_CALLBACK( on_scheme_keyword_edited ));
+	g_signal_connect(
+			G_OBJECT( renderers->data ),
+			"edited",
+			G_CALLBACK( on_scheme_keyword_edited ),
+			instance );
 
-	column = gtk_tree_view_get_column( scheme_widget, SCHEMES_DESC_COLUMN );
+	column = gtk_tree_view_get_column( listview, SCHEMES_DESC_COLUMN );
 	renderers = gtk_tree_view_column_get_cell_renderers( column );
-	nact_window_signal_connect( dialog, G_OBJECT( renderers->data ), "edited", G_CALLBACK( on_scheme_desc_edited ));
+	g_signal_connect(
+			G_OBJECT( renderers->data ),
+			"edited",
+			G_CALLBACK( on_scheme_desc_edited ),
+			instance );
+
+	add_button = get_add_button( instance );
+	g_signal_connect(
+			G_OBJECT( add_button ),
+			"clicked",
+			G_CALLBACK( on_add_scheme_clicked ),
+			instance );
+
+	remove_button = get_remove_button( instance );
+	g_signal_connect(
+			G_OBJECT( remove_button ),
+			"clicked",
+			G_CALLBACK( on_remove_scheme_clicked ),
+			instance );
+
+	g_signal_connect(
+			G_OBJECT( gtk_tree_view_get_selection( listview )),
+			"changed",
+			G_CALLBACK( on_scheme_list_selection_changed ),
+			instance );
+
+	g_signal_connect(
+			G_OBJECT( instance ),
+			TAB_UPDATABLE_SIGNAL_SELECTION_UPDATED,
+			G_CALLBACK( on_tab_updatable_selection_updated ),
+			instance );
+}
+
+static void
+runtime_init_setup_values( NactIAdvancedTab *instance, GtkTreeView *listview )
+{
+	static const gchar *thisfn = "nact_iadvanced_tab_runtime_init_setup_values";
+	GtkListStore *model;
+	GSList *schemes_list;
+	GSList *iter;
+	GtkTreeIter row;
+	gchar **tokens;
 
-	add_button = get_add_button( dialog );
-	nact_window_signal_connect( dialog, G_OBJECT( add_button ), "clicked", G_CALLBACK( on_add_scheme_clicked ));
-	remove_button = get_remove_button( dialog );
-	nact_window_signal_connect( dialog, G_OBJECT( remove_button ), "clicked", G_CALLBACK( on_remove_scheme_clicked ));
+	g_debug( "%s: instance=%p, listview=%p", thisfn, ( void * ) instance, ( void * ) listview );
 
-	nact_window_signal_connect( dialog, G_OBJECT( gtk_tree_view_get_selection( scheme_widget )), "changed", G_CALLBACK( on_scheme_list_selection_changed ));
+	model = GTK_LIST_STORE( gtk_tree_view_get_model( listview ));
+
+	schemes_list = get_schemes_default_list( instance );
+
+	for( iter = schemes_list ; iter ; iter = iter->next ){
+
+		tokens = g_strsplit(( gchar * ) iter->data, "|", 2 );
+		gtk_list_store_append( model, &row );
+		gtk_list_store_set( model, &row,
+				SCHEMES_CHECKBOX_COLUMN, FALSE,
+				SCHEMES_KEYWORD_COLUMN, tokens[0],
+				SCHEMES_DESC_COLUMN, tokens[1],
+				-1 );
+		g_strfreev( tokens );
+	}
+
+	na_utils_free_string_list( schemes_list );
 }
 
 void
-nact_iadvanced_tab_all_widgets_showed( NactWindow *dialog )
+nact_iadvanced_tab_all_widgets_showed( NactIAdvancedTab *instance )
 {
 	static const gchar *thisfn = "nact_iadvanced_tab_all_widgets_showed";
 
-	g_debug( "%s: dialog=%p", thisfn, ( void * ) dialog );
+	g_debug( "%s: instance=%p", thisfn, ( void * ) instance );
 }
 
 void
-nact_iadvanced_tab_dispose( NactWindow *dialog )
+nact_iadvanced_tab_dispose( NactIAdvancedTab *instance )
 {
 	static const gchar *thisfn = "nact_iadvanced_tab_dispose";
 
-	g_debug( "%s: dialog=%p", thisfn, ( void * ) dialog );
+	g_debug( "%s: instance=%p", thisfn, ( void * ) instance );
 }
 
-void
-nact_iadvanced_tab_set_profile( NactWindow *dialog, NAActionProfile *profile )
+/**
+ * Returns selected schemes as a list of strings.
+ * The caller should call na_utils_free_string_list after use.
+ */
+GSList *
+nact_iadvanced_tab_get_schemes( NactIAdvancedTab *instance )
 {
-	static const gchar *thisfn = "nact_iadvanced_tab_set_profile";
+	GSList *list = NULL;
+	GtkTreeModel* scheme_model;
+
+	scheme_model = get_schemes_tree_model( instance );
+	gtk_tree_model_foreach( scheme_model, ( GtkTreeModelForeachFunc ) get_action_schemes_list, &list );
+
+	return( list );
+}
+
+static void
+on_tab_updatable_selection_updated( NactIAdvancedTab *instance, gint count_selected )
+{
+	static const gchar *thisfn = "nact_iadvanced_tab_on_tab_updatable_selection_updated";
+	NAObjectProfile *profile = NULL;
 	GtkTreeModel *scheme_model;
 	GSList *schemes;
-	GtkTreeView *scheme_widget;
+	GtkTreeView *listview;
 	GtkButton *add, *remove;
 
-	g_debug( "%s: dialog=%p, profile=%p", thisfn, ( void * ) dialog, ( void * ) profile );
+	g_debug( "%s: instance=%p, count_selected=%d", thisfn, ( void * ) instance, count_selected );
 
-	scheme_model = get_schemes_tree_model( dialog );
+	scheme_model = get_schemes_tree_model( instance );
 	gtk_tree_model_foreach( scheme_model, ( GtkTreeModelForeachFunc ) reset_schemes_list, NULL );
 
+	g_object_get(
+			G_OBJECT( instance ),
+			TAB_UPDATABLE_PROP_EDITED_PROFILE, &profile,
+			NULL );
+
 	if( profile ){
-		schemes = na_action_profile_get_schemes( profile );
+		schemes = na_object_profile_get_schemes( profile );
 		g_slist_foreach( schemes, ( GFunc ) set_action_schemes, scheme_model );
 	}
 
-	scheme_widget = get_schemes_tree_view( dialog );
-	gtk_widget_set_sensitive( GTK_WIDGET( scheme_widget ), profile != NULL );
+	listview = get_schemes_tree_view( instance );
+	gtk_widget_set_sensitive( GTK_WIDGET( listview ), profile != NULL );
 
-	add = get_add_button( dialog );
+	add = get_add_button( instance );
 	gtk_widget_set_sensitive( GTK_WIDGET( add ), profile != NULL );
 
-	remove = get_remove_button( dialog );
+	remove = get_remove_button( instance );
 	gtk_widget_set_sensitive( GTK_WIDGET( remove ), profile != NULL );
 }
 
-/**
- * Returns selected schemes as a list of strings.
- * The caller should call na_utils_free_string_list after use.
+/*
+ * CommandExampleLabel is updated each time a field is modified
+ * And at each time, we need the list of selected schemes
  */
-GSList *
-nact_iadvanced_tab_get_schemes( NactWindow *window )
+static gboolean
+get_action_schemes_list( GtkTreeModel* scheme_model, GtkTreePath *path, GtkTreeIter* iter, GSList **schemes_list )
 {
-	GSList *list = NULL;
-	GtkTreeModel* scheme_model;
-
-	scheme_model = get_schemes_tree_model( window );
-	gtk_tree_model_foreach( scheme_model, ( GtkTreeModelForeachFunc ) get_action_schemes_list, &list );
+	/*static const char *thisfn = "nact_iadvanced_tab_get_action_schemes_list";*/
 
-	return( list );
-}
+	gboolean toggle_state;
+	gchar* scheme;
 
-static NAActionProfile *
-v_get_edited_profile( NactWindow *window )
-{
-	g_assert( NACT_IS_IADVANCED_TAB( window ));
+	gtk_tree_model_get( scheme_model, iter, SCHEMES_CHECKBOX_COLUMN, &toggle_state, SCHEMES_KEYWORD_COLUMN, &scheme, -1 );
 
-	if( NACT_IADVANCED_TAB_GET_INTERFACE( window )->get_edited_profile ){
-		return( NACT_IADVANCED_TAB_GET_INTERFACE( window )->get_edited_profile( window ));
+	if( toggle_state ){
+		/*g_debug( "%s: adding '%s' scheme", thisfn, scheme );*/
+		( *schemes_list ) = g_slist_append(( *schemes_list ), scheme );
 	}
 
-	return( NULL );
+	 /* don't stop looping */
+	return( FALSE );
 }
 
-static void
-v_field_modified( NactWindow *window )
+static GtkButton *
+get_add_button( NactIAdvancedTab *instance )
 {
-	g_assert( NACT_IS_IADVANCED_TAB( window ));
-
-	if( NACT_IADVANCED_TAB_GET_INTERFACE( window )->field_modified ){
-		NACT_IADVANCED_TAB_GET_INTERFACE( window )->field_modified( window );
-	}
+	return( get_button( instance, "AddSchemeButton" ));
 }
 
-static void
-on_scheme_selection_toggled( GtkCellRendererToggle *renderer, gchar *path, gpointer user_data )
+static GtkButton *
+get_button( NactIAdvancedTab *instance, const gchar *name )
 {
-	/*static const gchar *thisfn = "nact_iadvanced_tab_on_scheme_selection_toggled";*/
-	/*g_debug( "%s: renderer=%p, path=%s, user_data=%p", thisfn, renderer, path, user_data );*/
-
-	NactWindow *dialog;
-	NAActionProfile *edited;
-	GtkTreeModel *model;
-	GtkTreeIter iter;
-	GtkTreePath *tree_path;
-	gboolean state;
-	gchar *scheme;
-
-	g_assert( NACT_IS_WINDOW( user_data ));
-	dialog = NACT_WINDOW( user_data );
-
-	edited = NA_ACTION_PROFILE( v_get_edited_profile( dialog ));
-	if( edited ){
-		model = get_schemes_tree_model( dialog );
-
-		tree_path = gtk_tree_path_new_from_string( path );
-		gtk_tree_model_get_iter( model, &iter, tree_path );
-		gtk_tree_path_free( tree_path );
-		gtk_tree_model_get( model, &iter, SCHEMES_CHECKBOX_COLUMN, &state, SCHEMES_KEYWORD_COLUMN, &scheme, -1 );
-
-		/* gtk_tree_model_get: returns the previous state
-		g_debug( "%s: gtk_tree_model_get returns keyword=%s state=%s", thisfn, scheme, state ? "True":"False" );*/
-
-		gtk_list_store_set( GTK_LIST_STORE( model ), &iter, SCHEMES_CHECKBOX_COLUMN, !state, -1 );
-
-		na_action_profile_set_scheme( edited, scheme, !state );
+	GtkWidget *button;
 
-		g_free( scheme );
+	button = base_window_get_widget( BASE_WINDOW( instance ), name );
+	g_assert( GTK_IS_BUTTON( button ));
 
-		v_field_modified( dialog );
-	}
+	return( GTK_BUTTON( button ));
 }
 
-static void
-on_scheme_keyword_edited( GtkCellRendererText *renderer, const gchar *path, const gchar *text, gpointer user_data )
+static GtkButton *
+get_remove_button( NactIAdvancedTab *instance )
 {
-	/*static const gchar *thisfn = "nact_iadvanced_tab_on_scheme_keyword_edited";*/
-	/*g_debug( "%s: renderer=%p, path=%s, text=%s, user_data=%p", thisfn, renderer, path, text, user_data );*/
-
-	NactWindow *dialog;
-	gboolean state = FALSE;
-	gchar *old_text = NULL;
-	NAActionProfile *edited;
-
-	g_assert( NACT_IS_WINDOW( user_data ));
-	dialog = NACT_WINDOW( user_data );
+	return( get_button( instance, "RemoveSchemeButton" ));
+}
 
-	scheme_cell_edited( dialog, path, text, SCHEMES_KEYWORD_COLUMN, &state, &old_text );
+/*
+ * return default schemes list
+ * the returned list must be released with na_utils_free_string_list()
+ */
+static GSList *
+get_schemes_default_list( NactIAdvancedTab *instance )
+{
+	GSList *list = NULL;
 
-	if( state ){
-		/*g_debug( "%s: old_scheme=%s", thisfn, old_text );*/
-		edited = NA_ACTION_PROFILE( v_get_edited_profile( dialog ));
-		na_action_profile_set_scheme( edited, old_text, FALSE );
-		na_action_profile_set_scheme( edited, text, TRUE );
-	}
+	/* i18n notes : description of 'file' scheme */
+	list = g_slist_append( list, g_strdup_printf( "file|%s", _( "Local files")));
+	/* i18n notes : description of 'sftp' scheme */
+	list = g_slist_append( list, g_strdup_printf( "sftp|%s", _( "SSH files")));
+	/* i18n notes : description of 'smb' scheme */
+	list = g_slist_append( list, g_strdup_printf( "smb|%s", _( "Windows files")));
+	/* i18n notes : description of 'ftp' scheme */
+	list = g_slist_append( list, g_strdup_printf( "ftp|%s", _( "FTP files")));
+	/* i18n notes : description of 'dav' scheme */
+	list = g_slist_append( list, g_strdup_printf( "dav|%s", _( "WebDAV files")));
 
-	g_free( old_text );
-	v_field_modified( dialog );
+	return( list );
 }
 
-static void
-on_scheme_desc_edited( GtkCellRendererText *renderer, const gchar *path, const gchar *text, gpointer user_data )
+static GtkTreeModel *
+get_schemes_tree_model( NactIAdvancedTab *instance )
 {
-	/*static const gchar *thisfn = "nact_iadvanced_tab_on_scheme_desc_edited";
-	g_debug( "%s: renderer=%p, path=%s, text=%s, user_data=%p", thisfn, renderer, path, text, user_data );*/
-
-	NactWindow *dialog;
+	GtkTreeView *listview;
+	GtkTreeModel *model;
 
-	g_assert( NACT_IS_WINDOW( user_data ));
-	dialog = NACT_WINDOW( user_data );
+	listview = get_schemes_tree_view( instance );
+	model = gtk_tree_view_get_model( listview );
 
-	scheme_cell_edited( dialog, path, text, SCHEMES_DESC_COLUMN, NULL, NULL );
+	return( model );
 }
 
-static void
-on_scheme_list_selection_changed( GtkTreeSelection *selection, gpointer user_data )
+static GtkTreeView *
+get_schemes_tree_view( NactIAdvancedTab *instance )
 {
-	/*static const gchar *thisfn = "nact_iadvanced_tab_on_scheme_list_selection_changed";
-	g_debug( "%s: selection=%p, user_data=%p", thisfn, selection, user_data );*/
-
-	NactWindow *dialog;
-	GtkWidget *button;
-
-	g_assert( NACT_IS_WINDOW( user_data ));
-	dialog = NACT_WINDOW( user_data );
+	GtkWidget *treeview;
 
-	button = GTK_WIDGET( get_remove_button( dialog ));
+	treeview = base_window_get_widget( BASE_WINDOW( instance ), "SchemesTreeView" );
+	g_assert( GTK_IS_TREE_VIEW( treeview ));
 
-	if( gtk_tree_selection_count_selected_rows( selection )){
-		gtk_widget_set_sensitive( button, TRUE );
-	} else {
-		gtk_widget_set_sensitive( button, FALSE );
-	}
+	return( GTK_TREE_VIEW( treeview ));
 }
 
 /* TODO: set the selection on the newly created scheme */
 static void
-on_add_scheme_clicked( GtkButton *button, gpointer user_data )
+on_add_scheme_clicked( GtkButton *button, NactIAdvancedTab *instance )
 {
-	GtkTreeModel *model = get_schemes_tree_model( NACT_WINDOW( user_data ));
+	GtkTreeModel *model = get_schemes_tree_model( instance );
 	GtkTreeIter row;
 
-	gtk_list_store_append( GTK_LIST_STORE( model ), &row );
+	gtk_list_store_append(
+			GTK_LIST_STORE( model ),
+			&row );
+
 	gtk_list_store_set(
 			GTK_LIST_STORE( model ),
 			&row,
@@ -398,9 +500,9 @@ on_add_scheme_clicked( GtkButton *button, gpointer user_data )
 }
 
 static void
-on_remove_scheme_clicked( GtkButton *button, gpointer user_data )
+on_remove_scheme_clicked( GtkButton *button, NactIAdvancedTab *instance )
 {
-	NactWindow *dialog;
+	NAObjectProfile *edited;
 	GtkTreeView *listview;
 	GtkTreeSelection *selection;
 	GtkTreeModel *model;
@@ -411,12 +513,9 @@ on_remove_scheme_clicked( GtkButton *button, gpointer user_data )
 	gboolean toggle_state;
 	gchar *scheme;
 
-	g_assert( NACT_IS_WINDOW( user_data ));
-	dialog = NACT_WINDOW( user_data );
-
-	listview = get_schemes_tree_view( dialog );
+	listview = get_schemes_tree_view( instance );
 	selection = gtk_tree_view_get_selection( listview );
-	model = get_schemes_tree_model( dialog );
+	model = get_schemes_tree_model( instance );
 
 	selected_values_path = gtk_tree_selection_get_selected_rows( selection, &model );
 
@@ -427,159 +526,113 @@ on_remove_scheme_clicked( GtkButton *button, gpointer user_data )
 		gtk_list_store_remove( GTK_LIST_STORE( model ), &iter );
 
 		if( toggle_state ){
-			NAActionProfile *edited = NA_ACTION_PROFILE( v_get_edited_profile( dialog ));
-			na_action_profile_set_scheme( edited, scheme, FALSE );
+			g_object_get(
+					G_OBJECT( instance ),
+					TAB_UPDATABLE_PROP_EDITED_PROFILE, &edited,
+					NULL );
+			na_object_profile_set_scheme( edited, scheme, FALSE );
 		}
+
+		g_free( scheme );
 	}
 
 	g_list_foreach( selected_values_path, ( GFunc ) gtk_tree_path_free, NULL );
 	g_list_free( selected_values_path );
 
-	v_field_modified( dialog );
+	/*g_signal_emit_by_name( G_OBJECT( window ), NACT_SIGNAL_MODIFIED_FIELD );*/
 }
 
 static void
-scheme_cell_edited( NactWindow *window, const gchar *path_string, const gchar *text, gint column, gboolean *state, gchar **old_text )
+on_scheme_desc_edited( GtkCellRendererText *renderer, const gchar *path, const gchar *text, NactIAdvancedTab *instance )
 {
-	GtkTreeModel *model = get_schemes_tree_model( window );
-	GtkTreeIter iter;
-	GtkTreePath *path;
+	/*static const gchar *thisfn = "nact_iadvanced_tab_on_scheme_desc_edited";
+	g_debug( "%s: renderer=%p, path=%s, text=%s, user_data=%p", thisfn, renderer, path, text, user_data );*/
 
-	path = gtk_tree_path_new_from_string( path_string );
-	gtk_tree_model_get_iter( model, &iter, path );
-	gtk_tree_path_free( path );
+	scheme_cell_edited( instance, path, text, SCHEMES_DESC_COLUMN, NULL, NULL );
+}
 
-	if( state && old_text ){
-		gtk_tree_model_get( model, &iter, SCHEMES_CHECKBOX_COLUMN, state, SCHEMES_KEYWORD_COLUMN, old_text, -1 );
-	}
+static void
+on_scheme_keyword_edited( GtkCellRendererText *renderer, const gchar *path, const gchar *text, NactIAdvancedTab *instance )
+{
+	/*static const gchar *thisfn = "nact_iadvanced_tab_on_scheme_keyword_edited";*/
+	/*g_debug( "%s: renderer=%p, path=%s, text=%s, user_data=%p", thisfn, renderer, path, text, user_data );*/
 
-	gtk_list_store_set( GTK_LIST_STORE( model ), &iter, column, g_strdup( text ), -1 );
+	gboolean state = FALSE;
+	gchar *old_text = NULL;
+	NAObjectProfile *edited;
 
-}
+	scheme_cell_edited( instance, path, text, SCHEMES_KEYWORD_COLUMN, &state, &old_text );
 
-static GtkTreeView *
-get_schemes_tree_view( NactWindow *window )
-{
-	return( GTK_TREE_VIEW( base_window_get_widget( BASE_WINDOW( window ), "SchemesTreeView" )));
-}
+	if( state ){
+		/*g_debug( "%s: old_scheme=%s", thisfn, old_text );*/
+		g_object_get(
+				G_OBJECT( instance ),
+				TAB_UPDATABLE_PROP_EDITED_PROFILE, &edited,
+				NULL );
+		na_object_profile_set_scheme( edited, old_text, FALSE );
+		na_object_profile_set_scheme( edited, text, TRUE );
+	}
 
-static GtkTreeModel *
-get_schemes_tree_model( NactWindow *window )
-{
-	GtkTreeView *schemes_view = get_schemes_tree_view( window );
-	return( gtk_tree_view_get_model( schemes_view ));
+	g_free( old_text );
+
+	/*g_signal_emit_by_name( G_OBJECT( window ), NACT_SIGNAL_MODIFIED_FIELD );*/
 }
 
 static void
-create_schemes_selection_list( NactWindow *window )
+on_scheme_list_selection_changed( GtkTreeSelection *selection, NactIAdvancedTab *instance )
 {
-	static const char *thisfn = "nact_iadvanced_tab_create_schemes_selection_list";
-	GtkWidget *listview;
-	GSList *schemes_list;
-	GtkListStore *model;
-	GSList *iter;
-	GtkTreeIter row;
-	gchar **tokens;
-	GtkCellRenderer *toggled_cell;
-	GtkTreeViewColumn *column;
-	GtkCellRenderer *text_cell;
-
-	g_debug( "%s: window=%p", thisfn, ( void * ) window );
-	g_assert( NACT_IS_IADVANCED_TAB( window ));
+	/*static const gchar *thisfn = "nact_iadvanced_tab_on_scheme_list_selection_changed";
+	g_debug( "%s: selection=%p, user_data=%p", thisfn, selection, user_data );*/
 
-	listview = GTK_WIDGET( get_schemes_tree_view( window ));
-	schemes_list = get_schemes_default_list( window );
-	model = gtk_list_store_new( SCHEMES_N_COLUMN, G_TYPE_BOOLEAN, G_TYPE_STRING, G_TYPE_STRING );
+	GtkButton *button;
 
-	for( iter = schemes_list ; iter ; iter = iter->next ){
+	button = get_remove_button( instance );
 
-		tokens = g_strsplit(( gchar * ) iter->data, "|", 2 );
-		gtk_list_store_append( model, &row );
-		gtk_list_store_set( model, &row,
-				SCHEMES_CHECKBOX_COLUMN, FALSE,
-				SCHEMES_KEYWORD_COLUMN, tokens[0],
-				SCHEMES_DESC_COLUMN, tokens[1],
-				-1 );
-		g_strfreev( tokens );
+	if( gtk_tree_selection_count_selected_rows( selection )){
+		gtk_widget_set_sensitive( GTK_WIDGET( button ), TRUE );
+	} else {
+		gtk_widget_set_sensitive( GTK_WIDGET( button ), FALSE );
 	}
+}
 
-	na_utils_free_string_list( schemes_list );
+static void
+on_scheme_selection_toggled( GtkCellRendererToggle *renderer, gchar *path, NactIAdvancedTab *instance )
+{
+	/*static const gchar *thisfn = "nact_iadvanced_tab_on_scheme_selection_toggled";*/
+	/*g_debug( "%s: renderer=%p, path=%s, user_data=%p", thisfn, renderer, path, user_data );*/
 
-	gtk_tree_view_set_model( GTK_TREE_VIEW( listview ), GTK_TREE_MODEL( model ));
-	g_object_unref( model );
+	NAObjectProfile *edited;
+	GtkTreeModel *model;
+	GtkTreeIter iter;
+	GtkTreePath *tree_path;
+	gboolean state;
+	gchar *scheme;
 
-	toggled_cell = gtk_cell_renderer_toggle_new();
-	column = gtk_tree_view_column_new_with_attributes(
-			"scheme-selected",
-			toggled_cell,
-			"active", SCHEMES_CHECKBOX_COLUMN,
+	g_object_get(
+			G_OBJECT( instance ),
+			TAB_UPDATABLE_PROP_EDITED_PROFILE, &edited,
 			NULL );
-	gtk_tree_view_append_column( GTK_TREE_VIEW( listview ), column );
-	/*g_debug( "%s: toggled_cell=%p", thisfn, toggled_cell );*/
 
-	text_cell = gtk_cell_renderer_text_new();
-	g_object_set( G_OBJECT( text_cell ), "editable", TRUE, NULL );
-	column = gtk_tree_view_column_new_with_attributes(
-			"scheme-code",
-			text_cell,
-			"text", SCHEMES_KEYWORD_COLUMN,
-			NULL );
-	gtk_tree_view_append_column( GTK_TREE_VIEW( listview ), column );
+	if( edited ){
+		model = get_schemes_tree_model( instance );
 
-	text_cell = gtk_cell_renderer_text_new();
-	g_object_set( G_OBJECT( text_cell ), "editable", TRUE, NULL );
-	column = gtk_tree_view_column_new_with_attributes(
-			"scheme-description",
-			text_cell,
-			"text", SCHEMES_DESC_COLUMN,
-			NULL );
-	gtk_tree_view_append_column( GTK_TREE_VIEW( listview ), column );
-}
+		tree_path = gtk_tree_path_new_from_string( path );
+		gtk_tree_model_get_iter( model, &iter, tree_path );
+		gtk_tree_path_free( tree_path );
 
-/*
- * CommandExampleLabel is updated each time a field is modified
- * And at each time, we need the list of selected schemes
- */
-static gboolean
-get_action_schemes_list( GtkTreeModel* scheme_model, GtkTreePath *path, GtkTreeIter* iter, gpointer data )
-{
-	/*static const char *thisfn = "nact_iadvanced_tab_get_action_schemes_list";*/
+		gtk_tree_model_get( model, &iter, SCHEMES_CHECKBOX_COLUMN, &state, SCHEMES_KEYWORD_COLUMN, &scheme, -1 );
 
-	GSList** list = data;
-	gboolean toggle_state;
-	gchar* scheme;
+		/* gtk_tree_model_get: returns the previous state
+		g_debug( "%s: gtk_tree_model_get returns keyword=%s state=%s", thisfn, scheme, state ? "True":"False" );*/
 
-	gtk_tree_model_get( scheme_model, iter, SCHEMES_CHECKBOX_COLUMN, &toggle_state, SCHEMES_KEYWORD_COLUMN, &scheme, -1 );
+		gtk_list_store_set( GTK_LIST_STORE( model ), &iter, SCHEMES_CHECKBOX_COLUMN, !state, -1 );
 
-	if( toggle_state ){
-		/*g_debug( "%s: adding '%s' scheme", thisfn, scheme );*/
-		( *list ) = g_slist_append(( *list ), scheme );
+		na_object_profile_set_scheme( edited, scheme, !state );
 
-	} else {
 		g_free( scheme );
-	}
-
-	 /* don't stop looping */
-	return( FALSE );
-}
-
-static GSList *
-get_schemes_default_list( NactWindow *window )
-{
-	GSList *list = NULL;
-
-	/* i18n notes : description of 'file' scheme */
-	list = g_slist_append( list, g_strdup_printf( "file|%s", _( "Local files")));
-	/* i18n notes : description of 'sftp' scheme */
-	list = g_slist_append( list, g_strdup_printf( "sftp|%s", _( "SSH files")));
-	/* i18n notes : description of 'smb' scheme */
-	list = g_slist_append( list, g_strdup_printf( "smb|%s", _( "Windows files")));
-	/* i18n notes : description of 'ftp' scheme */
-	list = g_slist_append( list, g_strdup_printf( "ftp|%s", _( "FTP files")));
-	/* i18n notes : description of 'dav' scheme */
-	list = g_slist_append( list, g_strdup_printf( "dav|%s", _( "WebDAV files")));
 
-	return( list );
+		/*g_signal_emit_by_name( G_OBJECT( window ), NACT_SIGNAL_MODIFIED_FIELD );*/
+	}
 }
 
 static gboolean
@@ -591,6 +644,24 @@ reset_schemes_list( GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, g
 }
 
 static void
+scheme_cell_edited( NactIAdvancedTab *instance, const gchar *path_string, const gchar *text, gint column, gboolean *state, gchar **old_text )
+{
+	GtkTreeModel *model = get_schemes_tree_model( instance );
+	GtkTreeIter iter;
+	GtkTreePath *path;
+
+	path = gtk_tree_path_new_from_string( path_string );
+	gtk_tree_model_get_iter( model, &iter, path );
+	gtk_tree_path_free( path );
+
+	if( state && old_text ){
+		gtk_tree_model_get( model, &iter, SCHEMES_CHECKBOX_COLUMN, state, SCHEMES_KEYWORD_COLUMN, old_text, -1 );
+	}
+
+	gtk_list_store_set( GTK_LIST_STORE( model ), &iter, column, text, -1 );
+}
+
+static void
 set_action_schemes( gchar *scheme, GtkTreeModel *model )
 {
 	GtkTreeIter iter;
@@ -623,15 +694,3 @@ set_action_schemes( gchar *scheme, GtkTreeModel *model )
 				-1 );
 	}
 }
-
-static GtkButton *
-get_add_button( NactWindow *window )
-{
-	return( GTK_BUTTON( base_window_get_widget( BASE_WINDOW( window ), "AddSchemeButton" )));
-}
-
-static GtkButton *
-get_remove_button( NactWindow *window )
-{
-	return( GTK_BUTTON( base_window_get_widget( BASE_WINDOW( window ), "RemoveSchemeButton" )));
-}
diff --git a/src/nact/nact-iadvanced-tab.h b/src/nact/nact-iadvanced-tab.h
index 7e50656..5a5bb4d 100644
--- a/src/nact/nact-iadvanced-tab.h
+++ b/src/nact/nact-iadvanced-tab.h
@@ -38,7 +38,7 @@
  * conditions for the action.
  */
 
-#include "nact-window.h"
+#include <glib-object.h>
 
 G_BEGIN_DECLS
 
@@ -54,22 +54,17 @@ typedef struct NactIAdvancedTabInterfacePrivate NactIAdvancedTabInterfacePrivate
 typedef struct {
 	GTypeInterface                    parent;
 	NactIAdvancedTabInterfacePrivate *private;
-
-	/* api */
-	NAActionProfile * ( *get_edited_profile )( NactWindow *window );
-	void              ( *field_modified )    ( NactWindow *window );
 }
 	NactIAdvancedTabInterface;
 
 GType   nact_iadvanced_tab_get_type( void );
 
-void    nact_iadvanced_tab_initial_load( NactWindow *dialog );
-void    nact_iadvanced_tab_runtime_init( NactWindow *dialog );
-void    nact_iadvanced_tab_all_widgets_showed( NactWindow *dialog );
-void    nact_iadvanced_tab_dispose( NactWindow *dialog );
+void    nact_iadvanced_tab_initial_load_toplevel( NactIAdvancedTab *instance );
+void    nact_iadvanced_tab_runtime_init_toplevel( NactIAdvancedTab *instance );
+void    nact_iadvanced_tab_all_widgets_showed( NactIAdvancedTab *instance );
+void    nact_iadvanced_tab_dispose( NactIAdvancedTab *instance );
 
-void    nact_iadvanced_tab_set_profile( NactWindow *window, NAActionProfile *profile );
-GSList *nact_iadvanced_tab_get_schemes( NactWindow *window );
+GSList *nact_iadvanced_tab_get_schemes( NactIAdvancedTab *instance );
 
 G_END_DECLS
 
diff --git a/src/nact/nact-icommand-tab.c b/src/nact/nact-icommand-tab.c
index 09bd250..3dcfa84 100644
--- a/src/nact/nact-icommand-tab.c
+++ b/src/nact/nact-icommand-tab.c
@@ -35,12 +35,18 @@
 #include <glib/gi18n.h>
 #include <string.h>
 
+#include <common/na-object-api.h>
+#include <common/na-obj-profile.h>
 #include <common/na-utils.h>
 
+#include "base-window.h"
+#include "base-iprefs.h"
 #include "nact-application.h"
-#include "nact-statusbar.h"
-#include "nact-iprefs.h"
+#include "nact-main-statusbar.h"
+#include "nact-main-tab.h"
 #include "nact-icommand-tab.h"
+#include "nact-iconditions-tab.h"
+#include "nact-iadvanced-tab.h"
 
 /* private interface data
  */
@@ -50,42 +56,37 @@ 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				"icommand-legend-dialog"
+#define IPREFS_COMMAND_CHOOSER				"icommand-command-chooser"
+#define IPREFS_FOLDER_URI					"icommand-folder-uri"
 
 /* a data set in the LegendDialog GObject
  */
-#define LEGEND_DIALOG_IS_VISIBLE			"iconditions-legend-dialog-visible"
-
-#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 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 );
-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 void             set_label_label( NactWindow *window, const gchar *color );
-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 );
-static GtkWidget       *get_path_entry( NactWindow *window );
-static GtkButton       *get_path_button( NactWindow *window );
-static void             on_parameters_changed( GtkEntry *entry, gpointer user_data );
-static GtkWidget       *get_parameters_entry( NactWindow *window );
-static void             update_example_label( NactWindow *window );
-static gchar           *parse_parameters( NactWindow *window );
-static void             on_legend_clicked( GtkButton *button, gpointer user_data );
-static void             show_legend_dialog( NactWindow *window );
-static void             hide_legend_dialog( NactWindow *window );
-static GtkButton       *get_legend_button( NactWindow *window );
-static GtkWindow       *get_legend_dialog( NactWindow *window );
+#define LEGEND_DIALOG_IS_VISIBLE			"nact-icommand-tab-legend-dialog-visible"
+#define PROP_ICOMMAND_TAB_STATUS_CONTEXT	"nact-icommand-tab-status-context"
+
+static GType      register_type( void );
+static void       interface_base_init( NactICommandTabInterface *klass );
+static void       interface_base_finalize( NactICommandTabInterface *klass );
+
+static void       on_tab_updatable_selection_updated( NactICommandTab *instance, gint count_selected );
+static void       check_for_label( NactICommandTab *instance, GtkEntry *entry, const gchar *label );
+static GtkWidget *get_label_entry( NactICommandTab *instance );
+static GtkButton *get_legend_button( NactICommandTab *instance );
+static GtkWindow *get_legend_dialog( NactICommandTab *instance );
+static GtkWidget *get_parameters_entry( NactICommandTab *instance );
+static GtkButton *get_path_button( NactICommandTab *instance );
+static GtkWidget *get_path_entry( NactICommandTab *instance );
+static void       legend_dialog_show( NactICommandTab *instance );
+static void       legend_dialog_hide( NactICommandTab *instance );
+static void       on_label_changed( GtkEntry *entry, NactICommandTab *instance );
+static void       on_legend_clicked( GtkButton *button, NactICommandTab *instance );
+static void       on_parameters_changed( GtkEntry *entry, NactICommandTab *instance );
+static void       on_path_browse( GtkButton *button, NactICommandTab *instance );
+static void       on_path_changed( GtkEntry *entry, NactICommandTab *instance );
+static gchar     *parse_parameters( NactICommandTab *instance );
+static void       set_label_label( NactICommandTab *instance, const gchar *color );
+static void       update_example_label( NactICommandTab *instance, NAObjectProfile *profile );
 
 GType
 nact_icommand_tab_get_type( void )
@@ -121,7 +122,7 @@ register_type( void )
 
 	type = g_type_register_static( G_TYPE_INTERFACE, "NactICommandTab", &info, 0 );
 
-	g_type_interface_add_prerequisite( type, G_TYPE_OBJECT );
+	g_type_interface_add_prerequisite( type, BASE_WINDOW_TYPE );
 
 	return( type );
 }
@@ -137,9 +138,6 @@ interface_base_init( NactICommandTabInterface *klass )
 
 		klass->private = g_new0( NactICommandTabInterfacePrivate, 1 );
 
-		klass->get_edited_profile = NULL;
-		klass->field_modified = NULL;
-
 		initialized = TRUE;
 	}
 }
@@ -159,241 +157,314 @@ interface_base_finalize( NactICommandTabInterface *klass )
 	}
 }
 
+/**
+ * nact_icommand_tab_initial_load:
+ * @window: this #NactICommandTab instance.
+ *
+ * Initializes the tab widget at initial load.
+ */
 void
-nact_icommand_tab_initial_load( NactWindow *dialog )
+nact_icommand_tab_initial_load_toplevel( NactICommandTab *instance )
 {
-	static const gchar *thisfn = "nact_icommand_tab_initial_load";
+	static const gchar *thisfn = "nact_icommand_tab_initial_load_toplevel";
 
-	g_debug( "%s: dialog=%p", thisfn, ( void * ) dialog );
+	g_debug( "%s: instance=%p", thisfn, ( void * ) instance );
 }
 
+/**
+ * nact_icommand_tab_runtime_init:
+ * @window: this #NactICommandTab instance.
+ *
+ * Initializes the tab widget at each time the widget will be displayed.
+ * Connect signals and setup runtime values.
+ */
 void
-nact_icommand_tab_runtime_init( NactWindow *dialog )
+nact_icommand_tab_runtime_init_toplevel( NactICommandTab *instance )
 {
-	static const gchar *thisfn = "nact_icommand_tab_runtime_init";
+	static const gchar *thisfn = "nact_icommand_tab_runtime_init_toplevel";
 	GtkWidget *label_entry, *path_entry, *parameters_entry;
 	GtkButton *path_button, *legend_button;
 
-	g_debug( "%s: dialog=%p", thisfn, ( void * ) dialog );
-
-	label_entry = get_label_entry( dialog );
-	nact_window_signal_connect( dialog, G_OBJECT( label_entry ), "changed", G_CALLBACK( on_label_changed ));
-
-	path_entry = get_path_entry( dialog );
-	nact_window_signal_connect( dialog, G_OBJECT( path_entry ), "changed", G_CALLBACK( on_path_changed ));
-
-	path_button = get_path_button( dialog );
-	nact_window_signal_connect( dialog, G_OBJECT( path_button ), "clicked", G_CALLBACK( on_path_browse ));
-
-	parameters_entry = get_parameters_entry( dialog );
-	nact_window_signal_connect( dialog, G_OBJECT( parameters_entry ), "changed", G_CALLBACK( on_parameters_changed ));
-
-	legend_button = get_legend_button( dialog );
-	nact_window_signal_connect( dialog, G_OBJECT( legend_button ), "clicked", G_CALLBACK( on_legend_clicked ));
+	g_debug( "%s: instance=%p", thisfn, ( void * ) instance );
+
+	label_entry = get_label_entry( instance );
+	g_signal_connect(
+			G_OBJECT( label_entry ),
+			"changed",
+			G_CALLBACK( on_label_changed ),
+			instance );
+
+	path_entry = get_path_entry( instance );
+	g_signal_connect(
+			G_OBJECT( path_entry ),
+			"changed",
+			G_CALLBACK( on_path_changed ),
+			instance );
+
+	path_button = get_path_button( instance );
+	g_signal_connect(
+			G_OBJECT( path_button ),
+			"clicked",
+			G_CALLBACK( on_path_browse ),
+			instance );
+
+	parameters_entry = get_parameters_entry( instance );
+	g_signal_connect(
+			G_OBJECT( parameters_entry ),
+			"changed",
+			G_CALLBACK( on_parameters_changed ),
+			instance );
+
+	legend_button = get_legend_button( instance );
+	g_signal_connect(
+			G_OBJECT( legend_button ),
+			"clicked",
+			G_CALLBACK( on_legend_clicked ),
+			instance );
+
+	g_signal_connect(
+			G_OBJECT( instance ),
+			TAB_UPDATABLE_SIGNAL_SELECTION_UPDATED,
+			G_CALLBACK( on_tab_updatable_selection_updated ),
+			instance );
 }
 
-/**
- * A good place to set focus to the first visible field.
- */
 void
-nact_icommand_tab_all_widgets_showed( NactWindow *dialog )
+nact_icommand_tab_all_widgets_showed( NactICommandTab *instance )
 {
 	static const gchar *thisfn = "nact_icommand_tab_all_widgets_showed";
 
-	g_debug( "%s: dialog=%p", thisfn, ( void * ) dialog );
+	g_debug( "%s: instance=%p", thisfn, ( void * ) instance );
 }
 
+/**
+ * nact_icommand_tab_dispose:
+ * @window: this #NactICommandTab instance.
+ *
+ * Called at instance_dispose time.
+ */
 void
-nact_icommand_tab_dispose( NactWindow *dialog )
+nact_icommand_tab_dispose( NactICommandTab *instance )
 {
 	static const gchar *thisfn = "nact_icommand_tab_dispose";
 
-	g_debug( "%s: dialog=%p", thisfn, ( void * ) dialog );
+	g_debug( "%s: instance=%p", thisfn, ( void * ) instance );
 
-	hide_legend_dialog( dialog );
+	legend_dialog_hide( instance );
 }
 
-void
-nact_icommand_tab_set_profile( NactWindow *dialog, const NAActionProfile *profile )
+/**
+ * A profile can only be saved if it has at least a label.
+ * Returns TRUE if the label of the profile is not empty.
+ */
+gboolean
+nact_icommand_tab_has_label( NactICommandTab *instance )
 {
-	static const gchar *thisfn = "nact_icommand_tab_set_profile";
+	GtkWidget *label_entry = get_label_entry( instance );
+	const gchar *label = gtk_entry_get_text( GTK_ENTRY( label_entry ));
+	return( g_utf8_strlen( label, -1 ) > 0 );
+}
+
+static void
+on_tab_updatable_selection_updated( NactICommandTab *instance, gint count_selected )
+{
+	static const gchar *thisfn = "nact_icommand_tab_on_tab_updatable_selection_updated";
+	NAObjectProfile *profile = NULL;
 	GtkWidget *label_entry, *path_entry, *parameters_entry;
 	gchar *label, *path, *parameters;
 	GtkButton *path_button, *legend_button;
 
-	g_debug( "%s: dialog=%p, profile=%p", thisfn, ( void * ) dialog, ( void * ) profile );
+	g_debug( "%s: instance=%p, count_selected=%d", thisfn, ( void * ) instance, count_selected );
+
+	g_object_get(
+			G_OBJECT( instance ),
+			TAB_UPDATABLE_PROP_EDITED_PROFILE, &profile,
+			NULL );
 
-	label_entry = get_label_entry( dialog );
-	label = profile ? na_action_profile_get_label( profile ) : g_strdup( "" );
+	label_entry = get_label_entry( instance );
+	label = profile ? na_object_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 );
+	check_for_label( instance, GTK_ENTRY( label_entry ), label );
 	g_free( label );
 
-	path_entry = get_path_entry( dialog );
-	path = profile ? na_action_profile_get_path( profile ) : g_strdup( "" );
+	path_entry = get_path_entry( instance );
+	path = profile ? na_object_profile_get_path( profile ) : g_strdup( "" );
 	gtk_entry_set_text( GTK_ENTRY( path_entry ), path );
 	gtk_widget_set_sensitive( path_entry, profile != NULL );
 	g_free( path );
 
-	parameters_entry = get_parameters_entry( dialog );
-	parameters = profile ? na_action_profile_get_parameters( profile ) : g_strdup( "" );
+	parameters_entry = get_parameters_entry( instance );
+	parameters = profile ? na_object_profile_get_parameters( profile ) : g_strdup( "" );
 	gtk_entry_set_text( GTK_ENTRY( parameters_entry ), parameters );
 	gtk_widget_set_sensitive( parameters_entry, profile != NULL );
 	g_free( parameters );
 
-	path_button = get_path_button( dialog );
+	path_button = get_path_button( instance );
 	gtk_widget_set_sensitive( GTK_WIDGET( path_button ), profile != NULL );
 
-	legend_button = get_legend_button( dialog );
+	legend_button = get_legend_button( instance );
 	gtk_widget_set_sensitive( GTK_WIDGET( legend_button ), profile != NULL );
 }
 
-/**
- * A profile can only be saved if it has at least a label.
- * Returns TRUE if the label of the profile is not empty.
- */
-gboolean
-nact_icommand_tab_has_label( NactWindow *window )
+static void
+check_for_label( NactICommandTab *instance, GtkEntry *entry, const gchar *label )
 {
-	GtkWidget *label_entry = get_label_entry( window );
-	const gchar *label = gtk_entry_get_text( GTK_ENTRY( label_entry ));
-	return( g_utf8_strlen( label, -1 ) > 0 );
-}
+	NAObjectProfile *edited;
 
-static NAActionProfile *
-v_get_edited_profile( NactWindow *window )
-{
-	g_assert( NACT_IS_ICOMMAND_TAB( window ));
+	nact_main_statusbar_hide_status(
+			NACT_MAIN_WINDOW( instance ),
+			PROP_ICOMMAND_TAB_STATUS_CONTEXT );
 
-	if( NACT_ICOMMAND_TAB_GET_INTERFACE( window )->get_edited_profile ){
-		return( NACT_ICOMMAND_TAB_GET_INTERFACE( window )->get_edited_profile( window ));
-	}
+	set_label_label( instance, "black" );
 
-	return( NULL );
-}
+	g_object_get(
+			G_OBJECT( instance ),
+			TAB_UPDATABLE_PROP_EDITED_PROFILE, &edited,
+			NULL );
 
-static void
-v_field_modified( NactWindow *window )
-{
-	g_assert( NACT_IS_ICOMMAND_TAB( window ));
+	if( edited && g_utf8_strlen( label, -1 ) == 0 ){
+
+		/* i18n: status bar message when the profile label is empty */
+		nact_main_statusbar_display_status(
+				NACT_MAIN_WINDOW( instance ),
+				PROP_ICOMMAND_TAB_STATUS_CONTEXT,
+				_( "Caution: a label is mandatory for the profile." ));
 
-	if( NACT_ICOMMAND_TAB_GET_INTERFACE( window )->field_modified ){
-		NACT_ICOMMAND_TAB_GET_INTERFACE( window )->field_modified( window );
+		set_label_label( instance, "red" );
 	}
 }
 
-static void
-v_get_isfiledir( NactWindow *window, gboolean *isfile, gboolean *isdir )
+static GtkWidget *
+get_label_entry( NactICommandTab *instance )
 {
-	g_assert( NACT_IS_ICOMMAND_TAB( window ));
-	g_assert( isfile );
-	g_assert( isdir );
-	*isfile = FALSE;
-	*isdir = FALSE;
-
-	if( NACT_ICOMMAND_TAB_GET_INTERFACE( window )->get_isfiledir ){
-		NACT_ICOMMAND_TAB_GET_INTERFACE( window )->get_isfiledir( window, isfile, isdir );
-	}
+	return( base_window_get_widget( BASE_WINDOW( instance ), "ProfileLabelEntry" ));
 }
 
-static gboolean
-v_get_multiple( NactWindow *window )
+static GtkButton *
+get_legend_button( NactICommandTab *instance )
 {
-	g_assert( NACT_IS_ICOMMAND_TAB( window ));
-
-	if( NACT_ICOMMAND_TAB_GET_INTERFACE( window )->get_multiple ){
-		return( NACT_ICOMMAND_TAB_GET_INTERFACE( window )->get_multiple( window ));
-	}
+	return( GTK_BUTTON( base_window_get_widget( BASE_WINDOW( instance ), "CommandLegendButton" )));
+}
 
-	return( FALSE );
+static GtkWindow *
+get_legend_dialog( NactICommandTab *instance )
+{
+	return( base_window_get_toplevel( BASE_WINDOW( instance ), "LegendDialog" ));
 }
 
-static GSList *
-v_get_schemes( NactWindow *window )
+static GtkWidget *
+get_parameters_entry( NactICommandTab *instance )
 {
-	g_assert( NACT_IS_ICOMMAND_TAB( window ));
+	return( base_window_get_widget( BASE_WINDOW( instance ), "CommandParametersEntry" ));
+}
 
-	if( NACT_ICOMMAND_TAB_GET_INTERFACE( window )->get_schemes ){
-		return( NACT_ICOMMAND_TAB_GET_INTERFACE( window )->get_schemes( window ));
-	}
+static GtkButton *
+get_path_button( NactICommandTab *instance )
+{
+	return( GTK_BUTTON( base_window_get_widget( BASE_WINDOW( instance ), "CommandPathButton" )));
+}
 
-	return( NULL );
+static GtkWidget *
+get_path_entry( NactICommandTab *instance )
+{
+	return( base_window_get_widget( BASE_WINDOW( instance ), "CommandPathEntry" ));
 }
 
 static void
-on_label_changed( GtkEntry *entry, gpointer user_data )
+legend_dialog_hide( NactICommandTab *instance )
 {
-	NactWindow *dialog;
-	NAActionProfile *edited;
-	const gchar *label;
+	GtkWindow *legend_dialog;
+	GtkButton *legend_button;
+	gboolean is_visible;
+
+	legend_dialog = get_legend_dialog( instance );
+	is_visible = ( gboolean ) GPOINTER_TO_INT(
+			g_object_get_data( G_OBJECT( legend_dialog ), LEGEND_DIALOG_IS_VISIBLE ));
 
-	g_assert( NACT_IS_WINDOW( user_data ));
-	dialog = NACT_WINDOW( user_data );
+	if( is_visible ){
+		g_assert( GTK_IS_WINDOW( legend_dialog ));
+		base_iprefs_save_named_window_position( BASE_WINDOW( instance ), legend_dialog, IPREFS_LEGEND_DIALOG );
+		gtk_widget_hide( GTK_WIDGET( legend_dialog ));
 
-	edited = v_get_edited_profile( dialog );
+		/* set the legend button state consistent for when the dialog is
+		 * hidden by another mean (eg. close the edit profile dialog)
+		 */
+		legend_button = get_legend_button( instance );
+		gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( legend_button ), FALSE );
 
-	if( edited ){
-		label = gtk_entry_get_text( entry );
-		na_action_profile_set_label( edited, label );
-		v_field_modified( dialog );
-		check_for_label( dialog, entry, label );
+		g_object_set_data( G_OBJECT( legend_dialog ), LEGEND_DIALOG_IS_VISIBLE, GINT_TO_POINTER( FALSE ));
 	}
 }
 
 static void
-check_for_label( NactWindow *window, GtkEntry *entry, const gchar *label )
+legend_dialog_show( NactICommandTab *instance )
 {
-	NAActionProfile *edited;
+	GtkWindow *legend_dialog;
+	GtkWindow *toplevel;
 
-	nact_statusbar_hide_status( NACT_MAIN_WINDOW( window ), PROP_ICOMMAND_TAB_STATUS_CONTEXT );
-	set_label_label( window, "black" );
+	legend_dialog = get_legend_dialog( instance );
+	gtk_window_set_deletable( legend_dialog, FALSE );
 
-	edited = v_get_edited_profile( window );
+	toplevel = base_window_get_toplevel_window( BASE_WINDOW( instance ));
+	gtk_window_set_transient_for( GTK_WINDOW( legend_dialog ), toplevel );
 
-	if( edited && g_utf8_strlen( label, -1 ) == 0 ){
-		/* i18n: status bar message when the profile label is empty */
-		nact_statusbar_display_status( NACT_MAIN_WINDOW( window ), PROP_ICOMMAND_TAB_STATUS_CONTEXT, _( "Caution: a label is mandatory for the profile." ));
-		set_label_label( window, "red" );
-	}
+	base_iprefs_position_named_window( BASE_WINDOW( instance ), legend_dialog, IPREFS_LEGEND_DIALOG );
+	gtk_widget_show( GTK_WIDGET( legend_dialog ));
+
+	g_object_set_data( G_OBJECT( legend_dialog ), LEGEND_DIALOG_IS_VISIBLE, GINT_TO_POINTER( TRUE ));
 }
 
 static void
-set_label_label( NactWindow *window, const gchar *color )
+on_label_changed( GtkEntry *entry, NactICommandTab *instance )
 {
-	GtkWidget *label = base_window_get_widget( BASE_WINDOW( window ), "ProfileLabelLabel" );
-	/* i18n: label in front of the GtkEntry where user enters the profile label */
-	gchar *text = g_markup_printf_escaped( "<span color=\"%s\">%s</span>", color, _( "_Label :" ));
-	gtk_label_set_markup_with_mnemonic( GTK_LABEL( label ), text );
+	NAObjectProfile *edited;
+	const gchar *label;
+
+	g_object_get(
+			G_OBJECT( instance ),
+			TAB_UPDATABLE_PROP_EDITED_PROFILE, &edited,
+			NULL );
+
+	if( edited ){
+		label = gtk_entry_get_text( entry );
+		na_object_set_label( edited, label );
+		/*g_signal_emit_by_name( G_OBJECT( window ), NACT_SIGNAL_MODIFIED_FIELD );*/
+		check_for_label( instance, entry, label );
+	}
 }
 
-static GtkWidget *
-get_label_entry( NactWindow *window )
+static void
+on_legend_clicked( GtkButton *button, NactICommandTab *instance )
 {
-	return( base_window_get_widget( BASE_WINDOW( window ), "ProfileLabelEntry" ));
+	if( gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON( button ))){
+		legend_dialog_show( instance );
+
+	} else {
+		legend_dialog_hide( instance );
+	}
 }
 
 static void
-on_path_changed( GtkEntry *entry, gpointer user_data )
+on_parameters_changed( GtkEntry *entry, NactICommandTab *instance )
 {
-	NactWindow *dialog;
-	NAActionProfile *edited;
-
-	g_assert( NACT_IS_WINDOW( user_data ));
-	dialog = NACT_WINDOW( user_data );
+	NAObjectProfile *edited;
 
-	edited = NA_ACTION_PROFILE( v_get_edited_profile( dialog ));
+	g_object_get(
+			G_OBJECT( instance ),
+			TAB_UPDATABLE_PROP_EDITED_PROFILE, &edited,
+			NULL );
 
 	if( edited ){
-		na_action_profile_set_path( edited, gtk_entry_get_text( entry ));
-		v_field_modified( dialog );
+		na_object_profile_set_parameters( edited, gtk_entry_get_text( entry ));
+		/*g_signal_emit_by_name( G_OBJECT( window ), NACT_SIGNAL_MODIFIED_FIELD );*/
 	}
 
-	update_example_label( dialog );
+	update_example_label( instance, edited );
 }
 
 static void
-on_path_browse( GtkButton *button, gpointer user_data )
+on_path_browse( GtkButton *button, NactICommandTab *instance )
 {
 	gboolean set_current_location = FALSE;
 	gchar *uri = NULL;
@@ -402,8 +473,6 @@ on_path_browse( GtkButton *button, gpointer user_data )
 	const gchar *path;
 	gchar *filename;
 
-	g_assert( NACT_IS_ICOMMAND_TAB( user_data ));
-
 	dialog = gtk_file_chooser_dialog_new(
 			_( "Choosing a command" ),
 			NULL,
@@ -413,16 +482,16 @@ on_path_browse( GtkButton *button, gpointer user_data )
 			NULL
 			);
 
-	nact_iprefs_position_named_window( NACT_WINDOW( user_data ), GTK_WINDOW( dialog ), IPREFS_COMMAND_CHOOSER );
+	base_iprefs_position_named_window( BASE_WINDOW( instance ), GTK_WINDOW( dialog ), IPREFS_COMMAND_CHOOSER );
 
-	path_entry = get_path_entry( NACT_WINDOW( user_data ));
+	path_entry = get_path_entry( instance );
 	path = gtk_entry_get_text( GTK_ENTRY( path_entry ));
 
 	if( path && strlen( path )){
 		set_current_location = gtk_file_chooser_set_filename( GTK_FILE_CHOOSER( dialog ), path );
 
 	} else {
-		uri = nact_iprefs_get_iconditions_folder_uri( NACT_WINDOW( user_data ));
+		uri = base_iprefs_get_string( BASE_WINDOW( instance ), IPREFS_FOLDER_URI );
 		gtk_file_chooser_set_current_folder_uri( GTK_FILE_CHOOSER( dialog ), uri );
 		g_free( uri );
 	}
@@ -434,78 +503,30 @@ on_path_browse( GtkButton *button, gpointer user_data )
 	  }
 
 	uri = gtk_file_chooser_get_current_folder_uri( GTK_FILE_CHOOSER( dialog ));
-	nact_iprefs_save_iconditions_folder_uri( NACT_WINDOW( user_data ), uri );
+	base_iprefs_set_string( BASE_WINDOW( instance ), IPREFS_FOLDER_URI, uri );
 	g_free( uri );
 
-	nact_iprefs_save_named_window_position( NACT_WINDOW( user_data ), GTK_WINDOW( dialog ), IPREFS_COMMAND_CHOOSER );
+	base_iprefs_save_named_window_position( BASE_WINDOW( instance ), GTK_WINDOW( dialog ), IPREFS_COMMAND_CHOOSER );
 
 	gtk_widget_destroy( dialog );
 }
 
-static GtkWidget *
-get_path_entry( NactWindow *window )
-{
-	return( base_window_get_widget( BASE_WINDOW( window ), "CommandPathEntry" ));
-}
-
-static GtkButton *
-get_path_button( NactWindow *window )
-{
-	return( GTK_BUTTON( base_window_get_widget( BASE_WINDOW( window ), "CommandPathButton" )));
-}
-
 static void
-on_parameters_changed( GtkEntry *entry, gpointer user_data )
+on_path_changed( GtkEntry *entry, NactICommandTab *instance )
 {
-	NactWindow *dialog;
-	NAActionProfile *edited;
-
-	g_assert( NACT_IS_WINDOW( user_data ));
-	dialog = NACT_WINDOW( user_data );
+	NAObjectProfile *edited;
 
-	edited = NA_ACTION_PROFILE( v_get_edited_profile( dialog ));
+	g_object_get(
+			G_OBJECT( instance ),
+			TAB_UPDATABLE_PROP_EDITED_PROFILE, &edited,
+			NULL );
 
 	if( edited ){
-		na_action_profile_set_parameters( edited, gtk_entry_get_text( entry ));
-		v_field_modified( dialog );
+		na_object_profile_set_path( edited, gtk_entry_get_text( entry ));
+		/*g_signal_emit_by_name( G_OBJECT( window ), NACT_SIGNAL_MODIFIED_FIELD );*/
 	}
 
-	update_example_label( dialog );
-}
-
-static GtkWidget *
-get_parameters_entry( NactWindow *window )
-{
-	return( base_window_get_widget( BASE_WINDOW( window ), "CommandParametersEntry" ));
-}
-
-static void
-update_example_label( NactWindow *window )
-{
-	/*static const char *thisfn = "nact_iconditions_update_example_label";*/
-
-	static const gchar *original_label = N_( "<i><b><span size=\"small\">e.g., %s</span></b></i>" );
-
-	GtkWidget *example_widget = base_window_get_widget( BASE_WINDOW( window ), "CommandExampleLabel" );
-	gchar *newlabel, *parameters;
-
-	if( v_get_edited_profile( window )){
-
-		parameters = parse_parameters( window );
-
-		/* convert special xml chars (&, <, >,...) to avoid warnings
-		 * generated by Pango parser
-		 */
-		newlabel = g_markup_printf_escaped( original_label, parameters );
-
-		g_free( parameters );
-
-	} else {
-		newlabel = g_strdup( "" );
-	}
-
-	gtk_label_set_label( GTK_LABEL( example_widget ), newlabel );
-	g_free( newlabel );
+	update_example_label( instance, edited );
 }
 
 /*
@@ -524,49 +545,48 @@ update_example_label( NactWindow *window )
  * %% : a percent sign
  */
 static gchar *
-parse_parameters( NactWindow *window )
+parse_parameters( NactICommandTab *instance )
 {
-	GString* tmp_string = g_string_new( "" );
+	GString *tmp_string = g_string_new( "" );
 
 	/* i18n notes: example strings for the command preview */
-	gchar* ex_path = _( "/path/to" );
-	gchar* ex_files[] = { N_( "file1.txt" ), N_( "file2.txt" ), NULL };
-	gchar* ex_dirs[] = { N_(" folder1" ), N_( "folder2" ), NULL };
-	gchar* ex_mixed[] = { N_(" file1.txt" ), N_( "folder1" ), NULL };
-	gchar* ex_scheme_default = "file";
-	gchar* ex_host_default = _( "test.example.net" );
-	gchar* ex_one_file = _( "file.txt" );
-	gchar* ex_one_dir = _( "folder" );
-	gchar* ex_port_default = _( "8080" );
-	gchar* ex_one = NULL;
-	gchar* ex_list = NULL;
-	gchar* ex_path_list = NULL;
-	gchar* ex_uri_file1 = _( "file:///path/to/file1.text" );
-	gchar* ex_uri_file2 = _( "file:///path/to/file2.text" );
-	gchar* ex_uri_folder1 = _( "file:///path/to/a/dir" );
-	gchar* ex_uri_folder2 = _( "file:///path/to/another/dir" );
-	gchar* ex_uri_list = NULL;
-	gchar* ex_scheme;
-	gchar* ex_host;
+	gchar *ex_path = _( "/path/to" );
+	gchar *ex_files[] = { N_( "file1.txt" ), N_( "file2.txt" ), NULL };
+	gchar *ex_dirs[] = { N_(" folder1" ), N_( "folder2" ), NULL };
+	gchar *ex_mixed[] = { N_(" file1.txt" ), N_( "folder1" ), NULL };
+	gchar *ex_scheme_default = "file";
+	gchar *ex_host_default = _( "test.example.net" );
+	gchar *ex_one_file = _( "file.txt" );
+	gchar *ex_one_dir = _( "folder" );
+	gchar *ex_port_default = _( "8080" );
+	gchar *ex_one = NULL;
+	gchar *ex_list = NULL;
+	gchar *ex_path_list = NULL;
+	gchar *ex_uri_file1 = _( "file:///path/to/file1.text" );
+	gchar *ex_uri_file2 = _( "file:///path/to/file2.text" );
+	gchar *ex_uri_folder1 = _( "file:///path/to/a/dir" );
+	gchar *ex_uri_folder2 = _( "file:///path/to/another/dir" );
+	gchar *ex_uri_list = NULL;
+	gchar *ex_scheme;
+	gchar *ex_host;
 	gboolean is_file, is_dir;
 	gboolean accept_multiple;
 	GSList *scheme_list;
 
-	const gchar* command = gtk_entry_get_text( GTK_ENTRY( get_path_entry( window )));
-	const gchar* param_template = gtk_entry_get_text( GTK_ENTRY( get_parameters_entry( window )));
+	const gchar *command = gtk_entry_get_text( GTK_ENTRY( get_path_entry( instance )));
+	const gchar *param_template = gtk_entry_get_text( GTK_ENTRY( get_parameters_entry( instance )));
 
-	gchar* iter = g_strdup( param_template );
-	gchar* old_iter = iter;
-	gchar* tmp;
-	gchar* separator;
-	gchar* start;
+	gchar *iter = g_strdup( param_template );
+	gchar *old_iter = iter;
+	gchar *tmp;
+	gchar *separator;
+	gchar *start;
 
 	g_string_append_printf( tmp_string, "%s ", command );
 
-	v_get_isfiledir( window, &is_file, &is_dir );
-
-	accept_multiple = v_get_multiple( window );
-	scheme_list = v_get_schemes( window );
+	nact_iconditions_tab_get_isfiledir( NACT_ICONDITIONS_TAB( instance ), &is_file, &is_dir );
+	accept_multiple = nact_iconditions_tab_get_multiple( NACT_ICONDITIONS_TAB( instance ));
+	scheme_list = nact_iadvanced_tab_get_schemes( NACT_IADVANCED_TAB( instance ));
 
 	separator = g_strdup_printf( " %s/", ex_path );
 	start = g_strdup_printf( "%s/", ex_path );
@@ -689,66 +709,40 @@ parse_parameters( NactWindow *window )
 }
 
 static void
-on_legend_clicked( GtkButton *button, gpointer user_data )
+set_label_label( NactICommandTab *instance, const gchar *color )
 {
-	g_assert( NACT_IS_ICOMMAND_TAB( user_data ));
-
-	if( gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON( button ))){
-		show_legend_dialog( NACT_WINDOW( user_data ));
-
-	} else {
-		hide_legend_dialog( NACT_WINDOW( user_data ));
-	}
+	GtkWidget *label = base_window_get_widget( BASE_WINDOW( instance ), "ProfileLabelLabel" );
+	/* i18n: label in front of the GtkEntry where user enters the profile label */
+	gchar *text = g_markup_printf_escaped( "<span color=\"%s\">%s</span>", color, _( "_Label :" ));
+	gtk_label_set_markup_with_mnemonic( GTK_LABEL( label ), text );
 }
 
 static void
-show_legend_dialog( NactWindow *window )
+update_example_label( NactICommandTab *instance, NAObjectProfile *profile )
 {
-	GtkWindow *legend_dialog;
-	GtkWindow *toplevel;
-
-	legend_dialog = get_legend_dialog( window );
-	gtk_window_set_deletable( legend_dialog, FALSE );
-
-	toplevel = base_window_get_toplevel_dialog( BASE_WINDOW( window ));
-	gtk_window_set_transient_for( GTK_WINDOW( legend_dialog ), toplevel );
-
-	nact_iprefs_position_named_window( window, legend_dialog, IPREFS_LEGEND_DIALOG );
-	gtk_widget_show( GTK_WIDGET( legend_dialog ));
-
-	g_object_set_data( G_OBJECT( legend_dialog ), LEGEND_DIALOG_IS_VISIBLE, GINT_TO_POINTER( TRUE ));
-}
+	/*static const char *thisfn = "nact_iconditions_update_example_label";*/
+	gchar *newlabel;
+	gchar *parameters;
+	GtkWidget *example_widget;
 
-static void
-hide_legend_dialog( NactWindow *window )
-{
-	GtkWindow *legend_dialog = get_legend_dialog( window );
-	gboolean is_visible = GPOINTER_TO_INT( g_object_get_data( G_OBJECT( legend_dialog ), LEGEND_DIALOG_IS_VISIBLE ));
-	GtkButton *legend_button;
+	example_widget = base_window_get_widget( BASE_WINDOW( instance ), "CommandExampleLabel" );
 
-	if( is_visible ){
-		g_assert( GTK_IS_WINDOW( legend_dialog ));
-		nact_iprefs_save_named_window_position( window, legend_dialog, IPREFS_LEGEND_DIALOG );
-		gtk_widget_hide( GTK_WIDGET( legend_dialog ));
+	if( profile ){
+		parameters = parse_parameters( instance );
 
-		/* set the legend button state consistent for when the dialog is
-		 * hidden by another mean (eg. close the edit profile dialog)
+		/* convert special xml chars (&, <, >,...) to avoid warnings
+		 * generated by Pango parser
 		 */
-		legend_button = get_legend_button( window );
-		gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( legend_button ), FALSE );
+		/* i18n: command-line example: e.g., /bin/ls file1.txt file2.txt */
+		newlabel = g_markup_printf_escaped(
+				"<i><b><span size=\"small\">%s %s</span></b></i>", _( "e.g.," ), parameters );
 
-		g_object_set_data( G_OBJECT( legend_dialog ), LEGEND_DIALOG_IS_VISIBLE, GINT_TO_POINTER( FALSE ));
-	}
-}
+		g_free( parameters );
 
-static GtkButton *
-get_legend_button( NactWindow *window )
-{
-	return( GTK_BUTTON( base_window_get_widget( BASE_WINDOW( window ), "CommandLegendButton" )));
-}
+	} else {
+		newlabel = g_strdup( "" );
+	}
 
-static GtkWindow *
-get_legend_dialog( NactWindow *window )
-{
-	return( base_window_get_dialog( BASE_WINDOW( window ), "LegendDialog" ));
+	gtk_label_set_label( GTK_LABEL( example_widget ), newlabel );
+	g_free( newlabel );
 }
diff --git a/src/nact/nact-icommand-tab.h b/src/nact/nact-icommand-tab.h
index 18895c3..98e7203 100644
--- a/src/nact/nact-icommand-tab.h
+++ b/src/nact/nact-icommand-tab.h
@@ -37,7 +37,7 @@
  * This interface implements the "Nautilus Menu Item" box.
  */
 
-#include "nact-window.h"
+#include <glib-object.h>
 
 G_BEGIN_DECLS
 
@@ -53,25 +53,17 @@ typedef struct NactICommandTabInterfacePrivate NactICommandTabInterfacePrivate;
 typedef struct {
 	GTypeInterface                   parent;
 	NactICommandTabInterfacePrivate *private;
-
-	/* api */
-	NAActionProfile * ( *get_edited_profile )( NactWindow *window );
-	void              ( *field_modified )    ( NactWindow *window );
-	void              ( *get_isfiledir )     ( NactWindow *window, gboolean *is_file, gboolean *is_dir );
-	gboolean          ( *get_multiple )      ( NactWindow *window );
-	GSList *          ( *get_schemes )       ( NactWindow *window );
 }
 	NactICommandTabInterface;
 
 GType    nact_icommand_tab_get_type( void );
 
-void     nact_icommand_tab_initial_load( NactWindow *window );
-void     nact_icommand_tab_runtime_init( NactWindow *window );
-void     nact_icommand_tab_all_widgets_showed( NactWindow *window );
-void     nact_icommand_tab_dispose( NactWindow *window );
+void     nact_icommand_tab_initial_load_toplevel( NactICommandTab *instance );
+void     nact_icommand_tab_runtime_init_toplevel( NactICommandTab *instance );
+void     nact_icommand_tab_all_widgets_showed( NactICommandTab *instance );
+void     nact_icommand_tab_dispose( NactICommandTab *instance );
 
-void     nact_icommand_tab_set_profile( NactWindow *window, const NAActionProfile *profile );
-gboolean nact_icommand_tab_has_label( NactWindow *window );
+gboolean nact_icommand_tab_has_label( NactICommandTab *instance );
 
 G_END_DECLS
 
diff --git a/src/nact/nact-iconditions-tab.c b/src/nact/nact-iconditions-tab.c
index ffb1cac..d72936b 100644
--- a/src/nact/nact-iconditions-tab.c
+++ b/src/nact/nact-iconditions-tab.c
@@ -35,11 +35,15 @@
 #include <glib/gi18n.h>
 #include <string.h>
 
+#include <common/na-object-api.h>
+#include <common/na-obj-action-class.h>
+#include <common/na-obj-profile.h>
 #include <common/na-utils.h>
 
-#include "nact-main-window.h"
+#include "base-iprefs.h"
+#include "base-window.h"
+#include "nact-main-tab.h"
 #include "nact-iconditions-tab.h"
-#include "nact-iprefs.h"
 
 /* private interface data
  */
@@ -47,26 +51,24 @@ struct NactIConditionsTabInterfacePrivate {
 	void *empty;						/* so that gcc -pedantic is happy */
 };
 
-static GType            register_type( void );
-static void             interface_base_init( NactIConditionsTabInterface *klass );
-static void             interface_base_finalize( NactIConditionsTabInterface *klass );
-
-static NAActionProfile *v_get_edited_profile( NactWindow *window );
-static void             v_field_modified( NactWindow *window );
-
-static void             on_basenames_changed( GtkEntry *entry, gpointer user_data );
-static GtkWidget       *get_basenames_entry( NactWindow *window );
-static void             on_matchcase_toggled( GtkToggleButton *button, gpointer user_data );
-static GtkButton       *get_matchcase_button( NactWindow *window );
-static void             on_mimetypes_changed( GtkEntry *entry, gpointer user_data );
-static GtkWidget       *get_mimetypes_entry( NactWindow *window );
-static void             on_isfiledir_toggled( GtkToggleButton *button, gpointer user_data );
-static void             set_isfiledir( NactWindow *window, gboolean isfile, gboolean isdir );
-static GtkButton       *get_isfile_button( NactWindow *window );
-static GtkButton       *get_isdir_button( NactWindow *window );
-static GtkButton       *get_both_button( NactWindow *window );
-static void             on_multiple_toggled( GtkToggleButton *button, gpointer user_data );
-static GtkButton       *get_multiple_button( NactWindow *window );
+static GType      register_type( void );
+static void       interface_base_init( NactIConditionsTabInterface *klass );
+static void       interface_base_finalize( NactIConditionsTabInterface *klass );
+
+static void       on_tab_updatable_selection_updated( NactIConditionsTab *instance, gint count_selected );
+static GtkWidget *get_basenames_entry( NactIConditionsTab *instance );
+static GtkButton *get_both_button( NactIConditionsTab *instance );
+static GtkButton *get_isdir_button( NactIConditionsTab *instance );
+static GtkButton *get_isfile_button( NactIConditionsTab *instance );
+static GtkButton *get_matchcase_button( NactIConditionsTab *instance );
+static GtkWidget *get_mimetypes_entry( NactIConditionsTab *instance );
+static GtkButton *get_multiple_button( NactIConditionsTab *instance );
+static void       on_basenames_changed( GtkEntry *entry, NactIConditionsTab *instance );
+static void       on_isfiledir_toggled( GtkToggleButton *button, NactIConditionsTab *instance );
+static void       on_matchcase_toggled( GtkToggleButton *button, NactIConditionsTab *instance );
+static void       on_mimetypes_changed( GtkEntry *entry, NactIConditionsTab *instance );
+static void       on_multiple_toggled( GtkToggleButton *button, NactIConditionsTab *instance );
+static void       set_isfiledir( NactIConditionsTab *instance, gboolean isfile, gboolean isdir );
 
 GType
 nact_iconditions_tab_get_type( void )
@@ -102,7 +104,7 @@ register_type( void )
 
 	type = g_type_register_static( G_TYPE_INTERFACE, "NactIConditionsTab", &info, 0 );
 
-	g_type_interface_add_prerequisite( type, G_TYPE_OBJECT );
+	g_type_interface_add_prerequisite( type, BASE_WINDOW_TYPE );
 
 	return( type );
 }
@@ -118,9 +120,6 @@ interface_base_init( NactIConditionsTabInterface *klass )
 
 		klass->private = g_new0( NactIConditionsTabInterfacePrivate, 1 );
 
-		klass->get_edited_profile = NULL;
-		klass->field_modified = NULL;
-
 		initialized = TRUE;
 	}
 }
@@ -141,65 +140,127 @@ interface_base_finalize( NactIConditionsTabInterface *klass )
 }
 
 void
-nact_iconditions_tab_initial_load( NactWindow *dialog )
+nact_iconditions_tab_initial_load_toplevel( NactIConditionsTab *instance )
 {
-	static const gchar *thisfn = "nact_iconditions_tab_initial_load";
+	static const gchar *thisfn = "nact_iconditions_tab_initial_load_toplevel";
 
-	g_debug( "%s: dialog=%p", thisfn, ( void * ) dialog );
+	g_debug( "%s: instance=%p", thisfn, ( void * ) instance );
 }
 
 void
-nact_iconditions_tab_runtime_init( NactWindow *dialog )
+nact_iconditions_tab_runtime_init_toplevel( NactIConditionsTab *instance )
 {
-	static const gchar *thisfn = "nact_iconditions_tab_runtime_init";
+	static const gchar *thisfn = "nact_iconditions_tab_runtime_init_toplevel";
 	GtkWidget *basenames_widget;
 	GtkButton *matchcase_button;
 	GtkWidget *mimetypes_widget;
 	GtkButton *isfile_button, *isdir_button, *both_button;
 	GtkButton *multiple_button;
 
-	g_debug( "%s: dialog=%p", thisfn, ( void * ) dialog );
-
-	basenames_widget = get_basenames_entry( dialog );
-	nact_window_signal_connect( dialog, G_OBJECT( basenames_widget ), "changed", G_CALLBACK( on_basenames_changed ));
-
-	matchcase_button = get_matchcase_button( dialog );
-	nact_window_signal_connect( dialog, G_OBJECT( matchcase_button ), "toggled", G_CALLBACK( on_matchcase_toggled ));
-
-	mimetypes_widget = get_mimetypes_entry( dialog );
-	nact_window_signal_connect( dialog, G_OBJECT( mimetypes_widget ), "changed", G_CALLBACK( on_mimetypes_changed ));
-
-	isfile_button = get_isfile_button( dialog );
-	nact_window_signal_connect( dialog, G_OBJECT( isfile_button ), "toggled", G_CALLBACK( on_isfiledir_toggled ));
-	isdir_button = get_isdir_button( dialog );
-	nact_window_signal_connect( dialog, G_OBJECT( isdir_button ), "toggled", G_CALLBACK( on_isfiledir_toggled ));
-	both_button = get_both_button( dialog );
-	nact_window_signal_connect( dialog, G_OBJECT( both_button ), "toggled", G_CALLBACK( on_isfiledir_toggled ));
-
-	multiple_button = get_multiple_button( dialog );
-	nact_window_signal_connect( dialog, G_OBJECT( multiple_button ), "toggled", G_CALLBACK( on_multiple_toggled ));
+	g_debug( "%s: instance=%p", thisfn, ( void * ) instance );
+
+	basenames_widget = get_basenames_entry( instance );
+	g_signal_connect(
+			G_OBJECT( basenames_widget ),
+			"changed",
+			G_CALLBACK( on_basenames_changed ),
+			instance );
+
+	matchcase_button = get_matchcase_button( instance );
+	g_signal_connect(
+			G_OBJECT( matchcase_button ),
+			"toggled",
+			G_CALLBACK( on_matchcase_toggled ),
+			instance );
+
+	mimetypes_widget = get_mimetypes_entry( instance );
+	g_signal_connect(
+			G_OBJECT( mimetypes_widget ),
+			"changed",
+			G_CALLBACK( on_mimetypes_changed ),
+			instance );
+
+	isfile_button = get_isfile_button( instance );
+	g_signal_connect(
+			G_OBJECT( isfile_button ),
+			"toggled",
+			G_CALLBACK( on_isfiledir_toggled ),
+			instance );
+
+	isdir_button = get_isdir_button( instance );
+	g_signal_connect(
+			G_OBJECT( isdir_button ),
+			"toggled",
+			G_CALLBACK( on_isfiledir_toggled ),
+			instance );
+
+	both_button = get_both_button( instance );
+	g_signal_connect(
+			G_OBJECT( both_button ),
+			"toggled",
+			G_CALLBACK( on_isfiledir_toggled ),
+			instance );
+
+	multiple_button = get_multiple_button( instance );
+	g_signal_connect(
+			G_OBJECT( multiple_button ),
+			"toggled",
+			G_CALLBACK( on_multiple_toggled ),
+			instance );
+
+	g_signal_connect(
+			G_OBJECT( instance ),
+			TAB_UPDATABLE_SIGNAL_SELECTION_UPDATED,
+			G_CALLBACK( on_tab_updatable_selection_updated ),
+			instance );
 }
 
 void
-nact_iconditions_tab_all_widgets_showed( NactWindow *dialog )
+nact_iconditions_tab_all_widgets_showed( NactIConditionsTab *instance )
 {
 	static const gchar *thisfn = "nact_iconditions_tab_all_widgets_showed";
 
-	g_debug( "%s: dialog=%p", thisfn, ( void * ) dialog );
+	g_debug( "%s: instance=%p", thisfn, ( void * ) instance );
 }
 
 void
-nact_iconditions_tab_dispose( NactWindow *dialog )
+nact_iconditions_tab_dispose( NactIConditionsTab *instance )
 {
 	static const gchar *thisfn = "nact_iconditions_tab_dispose";
 
-	g_debug( "%s: dialog=%p", thisfn, ( void * ) dialog );
+	g_debug( "%s: instance=%p", thisfn, ( void * ) instance );
 }
 
 void
-nact_iconditions_tab_set_profile( NactWindow *dialog, NAActionProfile *profile )
+nact_iconditions_tab_get_isfiledir( NactIConditionsTab *instance, gboolean *isfile, gboolean *isdir )
 {
-	static const gchar *thisfn = "nact_iconditions_tab_set_profile";
+	gboolean both;
+
+	g_assert( isfile );
+	g_assert( isdir );
+
+	both = gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON( get_both_button( instance )));
+	if( both ){
+		*isfile = TRUE;
+		*isdir = TRUE;
+	} else {
+		*isfile = gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON( get_isfile_button( instance )));
+		*isdir = gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON( get_isdir_button( instance )));
+	}
+}
+
+gboolean
+nact_iconditions_tab_get_multiple( NactIConditionsTab *instance )
+{
+	GtkButton *button = get_multiple_button( instance );
+	return( gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON( button )));
+}
+
+static void
+on_tab_updatable_selection_updated( NactIConditionsTab *instance, gint count_selected )
+{
+	static const gchar *thisfn = "nact_iconditions_tab_on_tab_updatable_selection_updated";
+	NAObjectProfile *profile;
 	GtkWidget *basenames_widget, *mimetypes_widget;
 	GSList *basenames, *mimetypes;
 	gchar *basenames_text, *mimetypes_text;
@@ -210,251 +271,204 @@ nact_iconditions_tab_set_profile( NactWindow *dialog, NAActionProfile *profile )
 	GtkButton *multiple_button;
 	gboolean multiple;
 
-	g_debug( "%s: dialog=%p, profile=%p", thisfn, ( void * ) dialog, ( void * ) profile );
+	g_debug( "%s: instance=%p, count_selected=%d", thisfn, ( void * ) instance, count_selected );
+
+	g_object_get(
+			G_OBJECT( instance ),
+			TAB_UPDATABLE_PROP_EDITED_PROFILE, &profile,
+			NULL );
 
-	basenames_widget = get_basenames_entry( dialog );
-	basenames = profile ? na_action_profile_get_basenames( profile ) : NULL;
+	basenames_widget = get_basenames_entry( instance );
+	basenames = profile ? na_object_profile_get_basenames( profile ) : NULL;
 	basenames_text = profile ? na_utils_string_list_to_text( basenames ) : g_strdup( "" );
 	gtk_entry_set_text( GTK_ENTRY( basenames_widget ), basenames_text );
 	g_free( basenames_text );
 	na_utils_free_string_list( basenames );
 	gtk_widget_set_sensitive( basenames_widget, profile != NULL );
 
-	matchcase_button = get_matchcase_button( dialog );
-	matchcase = profile ? na_action_profile_get_matchcase( profile ) : FALSE;
+	matchcase_button = get_matchcase_button( instance );
+	matchcase = profile ? na_object_profile_get_matchcase( profile ) : FALSE;
 	gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( matchcase_button ), matchcase );
 	gtk_widget_set_sensitive( GTK_WIDGET( matchcase_button ), profile != NULL );
 
-	mimetypes_widget = get_mimetypes_entry( dialog );
-	mimetypes = profile ? na_action_profile_get_mimetypes( profile ) : NULL;
+	mimetypes_widget = get_mimetypes_entry( instance );
+	mimetypes = profile ? na_object_profile_get_mimetypes( profile ) : NULL;
 	mimetypes_text = profile ? na_utils_string_list_to_text( mimetypes ) : g_strdup( "" );
 	gtk_entry_set_text( GTK_ENTRY( mimetypes_widget ), mimetypes_text );
 	g_free( mimetypes_text );
 	na_utils_free_string_list( mimetypes );
 	gtk_widget_set_sensitive( mimetypes_widget, profile != NULL );
 
-	isfile = profile ? na_action_profile_get_is_file( profile ) : FALSE;
-	isdir = profile ? na_action_profile_get_is_dir( profile ) : FALSE;
-	set_isfiledir( dialog, isfile, isdir );
-	files_button = get_isfile_button( dialog );
+	isfile = profile ? na_object_profile_get_is_file( profile ) : FALSE;
+	isdir = profile ? na_object_profile_get_is_dir( profile ) : FALSE;
+	set_isfiledir( instance, isfile, isdir );
+	files_button = get_isfile_button( instance );
 	gtk_widget_set_sensitive( GTK_WIDGET( files_button ), profile != NULL );
-	dir_button = get_isdir_button( dialog );
+	dir_button = get_isdir_button( instance );
 	gtk_widget_set_sensitive( GTK_WIDGET( dir_button ), profile != NULL );
-	both_button = get_both_button( dialog );
+	both_button = get_both_button( instance );
 	gtk_widget_set_sensitive( GTK_WIDGET( both_button ), profile != NULL );
 
-	multiple_button = get_multiple_button( dialog );
-	multiple = profile ? na_action_profile_get_multiple( profile ) : FALSE;
+	multiple_button = get_multiple_button( instance );
+	multiple = profile ? na_object_profile_get_multiple( profile ) : FALSE;
 	gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( multiple_button ), multiple );
 	gtk_widget_set_sensitive( GTK_WIDGET( multiple_button ), profile != NULL );
 }
 
-void
-nact_iconditions_tab_get_isfiledir( NactWindow *window, gboolean *isfile, gboolean *isdir )
+static GtkWidget *
+get_basenames_entry( NactIConditionsTab *instance )
 {
-	gboolean both;
-
-	g_assert( isfile );
-	g_assert( isdir );
-
-	both = gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON( get_both_button( window )));
-	if( both ){
-		*isfile = TRUE;
-		*isdir = TRUE;
-	} else {
-		*isfile = gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON( get_isfile_button( window )));
-		*isdir = gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON( get_isdir_button( window )));
-	}
+	return( base_window_get_widget( BASE_WINDOW( instance ), "ConditionsFilenamesEntry" ));
 }
 
-gboolean
-nact_iconditions_tab_get_multiple( NactWindow *window )
+static GtkButton *
+get_both_button( NactIConditionsTab *instance )
 {
-	GtkButton *button = get_multiple_button( window );
-	return( gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON( button )));
+	return( GTK_BUTTON( base_window_get_widget( BASE_WINDOW( instance ), "ConditionsBothButton" )));
 }
 
-static NAActionProfile *
-v_get_edited_profile( NactWindow *window )
+static GtkButton *
+get_isdir_button( NactIConditionsTab *instance )
 {
-	g_assert( NACT_IS_ICONDITIONS_TAB( window ));
-
-	if( NACT_ICONDITIONS_TAB_GET_INTERFACE( window )->get_edited_profile ){
-		return( NACT_ICONDITIONS_TAB_GET_INTERFACE( window )->get_edited_profile( window ));
-	}
-
-	return( NULL );
+	return( GTK_BUTTON( base_window_get_widget( BASE_WINDOW( instance ), "ConditionsOnlyFoldersButton" )));
 }
 
-static void
-v_field_modified( NactWindow *window )
+static GtkButton *
+get_isfile_button( NactIConditionsTab *instance )
 {
-	g_assert( NACT_IS_ICONDITIONS_TAB( window ));
-
-	if( NACT_ICONDITIONS_TAB_GET_INTERFACE( window )->field_modified ){
-		NACT_ICONDITIONS_TAB_GET_INTERFACE( window )->field_modified( window );
-	}
+	return( GTK_BUTTON( base_window_get_widget( BASE_WINDOW( instance ), "ConditionsOnlyFilesButton" )));
 }
 
-static void
-on_basenames_changed( GtkEntry *entry, gpointer user_data )
+static GtkButton *
+get_matchcase_button( NactIConditionsTab *instance )
 {
-	NactWindow *dialog;
-	NAActionProfile *edited;
-	const gchar *text;
-	GSList *basenames;
-
-	g_assert( NACT_IS_WINDOW( user_data ));
-	dialog = NACT_WINDOW( user_data );
-
-	edited = NA_ACTION_PROFILE( v_get_edited_profile( dialog ));
-
-	if( edited ){
-		text = gtk_entry_get_text( entry );
-		basenames = na_utils_text_to_string_list( text );
-		na_action_profile_set_basenames( edited, basenames );
-		na_utils_free_string_list( basenames );
-		v_field_modified( dialog );
-	}
+	return( GTK_BUTTON( base_window_get_widget( BASE_WINDOW( instance ), "ConditionsMatchcaseButton" )));
 }
 
 static GtkWidget *
-get_basenames_entry( NactWindow *window )
-{
-	return( base_window_get_widget( BASE_WINDOW( window ), "ConditionsFilenamesEntry" ));
-}
-
-static void
-on_matchcase_toggled( GtkToggleButton *button, gpointer user_data )
+get_mimetypes_entry( NactIConditionsTab *instance )
 {
-	NactWindow *dialog;
-	NAActionProfile *edited;
-	gboolean matchcase;
-
-	g_assert( NACT_IS_WINDOW( user_data ));
-	dialog = NACT_WINDOW( user_data );
-
-	edited = NA_ACTION_PROFILE( v_get_edited_profile( dialog ));
-
-	if( edited ){
-		matchcase = gtk_toggle_button_get_active( button );
-		na_action_profile_set_matchcase( edited, matchcase );
-		v_field_modified( dialog );
-	}
+	return( base_window_get_widget( BASE_WINDOW( instance ), "ConditionsMimetypesEntry" ));
 }
 
 static GtkButton *
-get_matchcase_button( NactWindow *window )
+get_multiple_button( NactIConditionsTab *instance )
 {
-	return( GTK_BUTTON( base_window_get_widget( BASE_WINDOW( window ), "ConditionsMatchcaseButton" )));
+	return( GTK_BUTTON( base_window_get_widget( BASE_WINDOW( instance ), "ConditionsMultipleButton" )));
 }
 
 static void
-on_mimetypes_changed( GtkEntry *entry, gpointer user_data )
+on_basenames_changed( GtkEntry *entry, NactIConditionsTab *instance )
 {
-	NactWindow *dialog;
-	NAActionProfile *edited;
+	NAObjectProfile *edited;
 	const gchar *text;
-	GSList *mimetypes;
-
-	g_assert( NACT_IS_WINDOW( user_data ));
-	dialog = NACT_WINDOW( user_data );
+	GSList *basenames;
 
-	edited = NA_ACTION_PROFILE( v_get_edited_profile( dialog ));
+	g_object_get(
+			G_OBJECT( instance ),
+			TAB_UPDATABLE_PROP_EDITED_PROFILE, &edited,
+			NULL );
 
 	if( edited ){
 		text = gtk_entry_get_text( entry );
-		mimetypes = na_utils_text_to_string_list( text );
-		na_action_profile_set_mimetypes( edited, mimetypes );
-		na_utils_free_string_list( mimetypes );
-		v_field_modified( dialog );
+		basenames = na_utils_text_to_string_list( text );
+		na_object_profile_set_basenames( edited, basenames );
+		na_utils_free_string_list( basenames );
+		/*g_signal_emit_by_name( G_OBJECT( instance ), NACT_SIGNAL_MODIFIED_FIELD );*/
 	}
 }
 
-static GtkWidget *
-get_mimetypes_entry( NactWindow *window )
-{
-	return( base_window_get_widget( BASE_WINDOW( window ), "ConditionsMimetypesEntry" ));
-}
-
 /*
  * Note that this callback is triggered twice: first, for the
  * deactivated button, then a second time for the newly activated one.
  * I don't know what to do to be triggered only once..?
  */
 static void
-on_isfiledir_toggled( GtkToggleButton *button, gpointer user_data )
+on_isfiledir_toggled( GtkToggleButton *button, NactIConditionsTab *instance )
 {
 	/*static const gchar *thisfn = "nact_iconditions_tab_on_isfiledir_toggled";*/
-	NactWindow *dialog;
-	NAActionProfile *edited;
+	NAObjectProfile *edited;
 	gboolean isfile, isdir;
 
-	g_assert( NACT_IS_WINDOW( user_data ));
-	dialog = NACT_WINDOW( user_data );
-
-	edited = NA_ACTION_PROFILE( v_get_edited_profile( dialog ));
+	g_object_get(
+			G_OBJECT( instance ),
+			TAB_UPDATABLE_PROP_EDITED_PROFILE, &edited,
+			NULL );
 
 	if( edited ){
-		nact_iconditions_tab_get_isfiledir( dialog, &isfile, &isdir );
-		na_action_profile_set_isfiledir( edited, isfile, isdir );
-		v_field_modified( dialog );
+		nact_iconditions_tab_get_isfiledir( instance, &isfile, &isdir );
+		na_object_profile_set_isfiledir( edited, isfile, isdir );
+		/*g_signal_emit_by_name( G_OBJECT( instance ), NACT_SIGNAL_MODIFIED_FIELD );*/
 	}
 }
 
 static void
-set_isfiledir( NactWindow *window, gboolean isfile, gboolean isdir )
+on_matchcase_toggled( GtkToggleButton *button, NactIConditionsTab *instance )
 {
-	if( isfile && isdir ){
-		gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( get_both_button( window )), TRUE );
+	NAObjectProfile *edited;
+	gboolean matchcase;
 
-	} else if( isfile ){
-		gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( get_isfile_button( window )), TRUE );
+	g_object_get(
+			G_OBJECT( instance ),
+			TAB_UPDATABLE_PROP_EDITED_PROFILE, &edited,
+			NULL );
 
-	} else if( isdir ){
-		gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( get_isdir_button( window )), TRUE );
+	if( edited ){
+		matchcase = gtk_toggle_button_get_active( button );
+		na_object_profile_set_matchcase( edited, matchcase );
+		/*g_signal_emit_by_name( G_OBJECT( instance ), NACT_SIGNAL_MODIFIED_FIELD );*/
 	}
 }
 
-static GtkButton *
-get_isfile_button( NactWindow *window )
+static void
+on_mimetypes_changed( GtkEntry *entry, NactIConditionsTab *instance )
 {
-	return( GTK_BUTTON( base_window_get_widget( BASE_WINDOW( window ), "ConditionsOnlyFilesButton" )));
-}
+	NAObjectProfile *edited;
+	const gchar *text;
+	GSList *mimetypes;
 
-static GtkButton *
-get_isdir_button( NactWindow *window )
-{
-	return( GTK_BUTTON( base_window_get_widget( BASE_WINDOW( window ), "ConditionsOnlyFoldersButton" )));
-}
+	g_object_get(
+			G_OBJECT( instance ),
+			TAB_UPDATABLE_PROP_EDITED_PROFILE, &edited,
+			NULL );
 
-static GtkButton *
-get_both_button( NactWindow *window )
-{
-	return( GTK_BUTTON( base_window_get_widget( BASE_WINDOW( window ), "ConditionsBothButton" )));
+	if( edited ){
+		text = gtk_entry_get_text( entry );
+		mimetypes = na_utils_text_to_string_list( text );
+		na_object_profile_set_mimetypes( edited, mimetypes );
+		na_utils_free_string_list( mimetypes );
+		/*g_signal_emit_by_name( G_OBJECT( instance ), NACT_SIGNAL_MODIFIED_FIELD );*/
+	}
 }
 
 static void
-on_multiple_toggled( GtkToggleButton *button, gpointer user_data )
+on_multiple_toggled( GtkToggleButton *button, NactIConditionsTab *instance )
 {
-	NactWindow *dialog;
-	NAActionProfile *edited;
+	NAObjectProfile *edited;
 	gboolean multiple;
 
-	g_assert( NACT_IS_WINDOW( user_data ));
-	dialog = NACT_WINDOW( user_data );
-
-	edited = NA_ACTION_PROFILE( v_get_edited_profile( dialog ));
+	g_object_get(
+			G_OBJECT( instance ),
+			TAB_UPDATABLE_PROP_EDITED_PROFILE, &edited,
+			NULL );
 
 	if( edited ){
 		multiple = gtk_toggle_button_get_active( button );
-		na_action_profile_set_multiple( edited, multiple );
-		v_field_modified( dialog );
+		na_object_profile_set_multiple( edited, multiple );
+		/*g_signal_emit_by_name( G_OBJECT( instance ), NACT_SIGNAL_MODIFIED_FIELD );*/
 	}
 }
 
-static GtkButton *
-get_multiple_button( NactWindow *window )
+static void
+set_isfiledir( NactIConditionsTab *instance, gboolean isfile, gboolean isdir )
 {
-	return( GTK_BUTTON( base_window_get_widget( BASE_WINDOW( window ), "ConditionsMultipleButton" )));
+	if( isfile && isdir ){
+		gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( get_both_button( instance )), TRUE );
+
+	} else if( isfile ){
+		gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( get_isfile_button( instance )), TRUE );
+
+	} else if( isdir ){
+		gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( get_isdir_button( instance )), TRUE );
+	}
 }
diff --git a/src/nact/nact-iconditions-tab.h b/src/nact/nact-iconditions-tab.h
index 664d245..e060bab 100644
--- a/src/nact/nact-iconditions-tab.h
+++ b/src/nact/nact-iconditions-tab.h
@@ -38,7 +38,7 @@
  * conditions for the action.
  */
 
-#include "nact-window.h"
+#include <glib-object.h>
 
 G_BEGIN_DECLS
 
@@ -54,23 +54,18 @@ typedef struct NactIConditionsTabInterfacePrivate NactIConditionsTabInterfacePri
 typedef struct {
 	GTypeInterface                       parent;
 	NactIConditionsTabInterfacePrivate *private;
-
-	/* api */
-	NAActionProfile * ( *get_edited_profile )( NactWindow *window );
-	void              ( *field_modified )    ( NactWindow *window );
 }
 	NactIConditionsTabInterface;
 
 GType    nact_iconditions_tab_get_type( void );
 
-void     nact_iconditions_tab_initial_load( NactWindow *dialog );
-void     nact_iconditions_tab_runtime_init( NactWindow *dialog );
-void     nact_iconditions_tab_all_widgets_showed( NactWindow *dialog );
-void     nact_iconditions_tab_dispose( NactWindow *dialog );
+void     nact_iconditions_tab_initial_load_toplevel( NactIConditionsTab *instance );
+void     nact_iconditions_tab_runtime_init_toplevel( NactIConditionsTab *instance );
+void     nact_iconditions_tab_all_widgets_showed( NactIConditionsTab *instance );
+void     nact_iconditions_tab_dispose( NactIConditionsTab *instance );
 
-void     nact_iconditions_tab_set_profile( NactWindow *window, NAActionProfile *profile );
-void     nact_iconditions_tab_get_isfiledir( NactWindow *window, gboolean *isfile, gboolean *isdir );
-gboolean nact_iconditions_tab_get_multiple( NactWindow *window );
+void     nact_iconditions_tab_get_isfiledir( NactIConditionsTab *instance, gboolean *isfile, gboolean *isdir );
+gboolean nact_iconditions_tab_get_multiple( NactIConditionsTab *instance );
 
 G_END_DECLS
 
diff --git a/src/nact/nact-main-menubar.c b/src/nact/nact-main-menubar.c
new file mode 100644
index 0000000..826ae35
--- /dev/null
+++ b/src/nact/nact-main-menubar.c
@@ -0,0 +1,682 @@
+/*
+ * 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 <common/na-about.h>
+#include <common/na-object-api.h>
+#include <common/na-obj-action.h>
+#include <common/na-obj-menu.h>
+#include <common/na-ipivot-consumer.h>
+
+#include "nact-application.h"
+#include "nact-assistant-export.h"
+#include "nact-assistant-import.h"
+#include "nact-preferences-editor.h"
+#include "nact-iactions-list.h"
+#include "nact-clipboard.h"
+#include "nact-main-statusbar.h"
+#include "nact-main-tab.h"
+#include "nact-main-menubar.h"
+
+#define MENUBAR_PROP_STATUS_CONTEXT		"nact-menubar-status-context"
+#define MENUBAR_PROP_UI_MANAGER			"nact-menubar-ui-manager"
+#define MENUBAR_PROP_ACTIONS_GROUP		"nact-menubar-actions-group"
+
+static void     on_tab_updatable_selection_updated( NactMainWindow *window, gint count_selected );
+
+static void     on_new_menu_activated( GtkAction *action, NactMainWindow *window );
+static void     on_new_action_activated( GtkAction *action, NactMainWindow *window );
+static void     on_new_profile_activated( GtkAction *action, NactMainWindow *window );
+static void     on_save_activated( GtkAction *action, NactMainWindow *window );
+static void     save_object_item( NactMainWindow *window, NAPivot *pivot, NAObjectItem *object );
+static void     on_quit_activated( GtkAction *action, NactMainWindow *window );
+
+static void     on_cut_activated( GtkAction *action, NactMainWindow *window );
+static void     on_copy_activated( GtkAction *action, NactMainWindow *window );
+static void     on_paste_activated( GtkAction *action, NactMainWindow *window );
+static void     on_duplicate_activated( GtkAction *action, NactMainWindow *window );
+static void     on_delete_activated( GtkAction *action, NactMainWindow *window );
+static void     on_reload_activated( GtkAction *action, NactMainWindow *window );
+static void     on_preferences_activated( GtkAction *action, NactMainWindow *window );
+
+static void     on_import_activated( GtkAction *action, NactMainWindow *window );
+static void     on_export_activated( GtkAction *action, NactMainWindow *window );
+
+static void     on_help_activated( GtkAction *action, NactMainWindow *window );
+static void     on_about_activated( GtkAction *action, NactMainWindow *window );
+
+static void     enable_item( NactMainWindow *window, const gchar *name, gboolean enabled );
+static gboolean on_delete_event( GtkWidget *toplevel, GdkEvent *event, NactMainWindow *window );
+static void     on_destroy_callback( gpointer data );
+static void     on_menu_item_selected( GtkMenuItem *proxy, NactMainWindow *window );
+static void     on_menu_item_deselected( GtkMenuItem *proxy, NactMainWindow *window );
+static void     on_proxy_connect( GtkActionGroup *action_group, GtkAction *action, GtkWidget *proxy, NactMainWindow *window );
+static void     on_proxy_disconnect( GtkActionGroup *action_group, GtkAction *action, GtkWidget *proxy, NactMainWindow *window );
+static void     refresh_actions_sensitivity_with_count( NactMainWindow *window, gint count_selected );
+
+static const GtkActionEntry entries[] = {
+
+		{ "FileMenu", NULL, N_( "_File" ) },
+		{ "EditMenu", NULL, N_( "_Edit" ) },
+		{ "ToolsMenu", NULL, N_( "_Tools" ) },
+		{ "HelpMenu", NULL, N_( "_Help" ) },
+
+		{ "NewMenuItem", NULL, N_( "New _menu" ), "<Ctrl>M",
+				/* i18n: tooltip displayed in the status bar when selecting the 'New menu' item */
+				N_( "Insert a new menu at the current position" ),
+				G_CALLBACK( on_new_menu_activated ) },
+		{ "NewActionItem", GTK_STOCK_NEW, N_( "_New action" ), NULL,
+				/* i18n: tooltip displayed in the status bar when selecting the 'New action' item */
+				N_( "Define a new action" ),
+				G_CALLBACK( on_new_action_activated ) },
+		{ "NewProfileItem", NULL, N_( "New _profile" ), NULL,
+				/* i18n: tooltip displayed in the status bar when selecting the 'New profile' item */
+				N_( "Define a new profile attached to the current action" ),
+				G_CALLBACK( on_new_profile_activated ) },
+		{ "SaveItem", GTK_STOCK_SAVE, NULL, NULL,
+				/* i18n: tooltip displayed in the status bar when selecting 'Save' item */
+				N_( "Record all the modified actions. Invalid actions will be silently ignored" ),
+				G_CALLBACK( on_save_activated ) },
+		{ "QuitItem", GTK_STOCK_QUIT, NULL, NULL,
+				/* i18n: tooltip displayed in the status bar when selecting 'Quit' item */
+				N_( "Quit the application" ),
+				G_CALLBACK( on_quit_activated ) },
+		{ "CutItem" , GTK_STOCK_CUT, NULL, NULL,
+				/* i18n: tooltip displayed in the status bar when selecting the Cut item */
+				N_( "Cut the selected item(s) to the clipboard" ),
+				G_CALLBACK( on_cut_activated ) },
+		{ "CopyItem" , GTK_STOCK_COPY, NULL, NULL,
+				/* i18n: tooltip displayed in the status bar when selecting the Copy item */
+				N_( "Copy the selected item(s) to the clipboard" ),
+				G_CALLBACK( on_copy_activated ) },
+		{ "PasteItem" , GTK_STOCK_PASTE, NULL, NULL,
+				/* i18n: tooltip displayed in the status bar when selecting the Paste item */
+				N_( "Insert the content of the clipboard at the current position" ),
+				G_CALLBACK( on_paste_activated ) },
+		{ "DuplicateItem" , NULL, N_( "D_uplicate" ), "",
+				/* i18n: tooltip displayed in the status bar when selecting the Duplicate item */
+				N_( "Duplicate the selected item(s)" ),
+				G_CALLBACK( on_duplicate_activated ) },
+		{ "DeleteItem", GTK_STOCK_DELETE, NULL, "Delete",
+				/* i18n: tooltip displayed in the status bar when selecting the Delete item */
+				N_( "Delete the selected item(s)" ),
+				G_CALLBACK( on_delete_activated ) },
+		{ "ReloadActionsItem", NULL, N_( "_Reload the list of actions" ), "<Ctrl>R",
+				/* i18n: tooltip displayed in the status bar when selecting the 'Reload' item */
+				N_( "Cancel your current modifications and reload the list of actions" ),
+				G_CALLBACK( on_reload_activated ) },
+		{ "PreferencesItem", GTK_STOCK_PREFERENCES, NULL, NULL,
+				/* i18n: tooltip displayed in the status bar when selecting the 'Preferences' item */
+				N_( "Edit your preferences" ),
+				G_CALLBACK( on_preferences_activated ) },
+		{ "ImportItem" , GTK_STOCK_CONVERT, N_( "_Import assistant.." ), "",
+				/* i18n: tooltip displayed in the status bar when selecting the Import item */
+				N_( "Import one or more actions from external (XML) files into your configuration" ),
+				G_CALLBACK( on_import_activated ) },
+		{ "ExportItem", NULL, N_( "E_xport assistant.." ), NULL,
+				/* i18n: tooltip displayed in the status bar when selecting the Export item */
+				N_( "Export one or more actions from your configuration to external XML files" ),
+				G_CALLBACK( on_export_activated ) },
+		{ "HelpItem" , GTK_STOCK_HELP, NULL, NULL,
+				/* i18n: tooltip displayed in the status bar when selecting the Help item */
+				N_( "Display help about this program" ),
+				G_CALLBACK( on_help_activated ) },
+		{ "AboutItem", GTK_STOCK_ABOUT, NULL, NULL,
+				/* i18n: tooltip displayed in the status bar when selecting the About item */
+				N_( "Display informations about this program" ),
+				G_CALLBACK( on_about_activated ) },
+};
+
+/**
+ * nact_main_menubar_runtime_init:
+ * @window: the #NactMainWindow to which the menubar is attached.
+ *
+ * Creates the menubar.
+ */
+void
+nact_main_menubar_runtime_init( NactMainWindow *window )
+{
+	static const gchar *thisfn = "nact_main_menubar_init";
+	GtkActionGroup *action_group;
+	GtkUIManager *ui_manager;
+	GError *error = NULL;
+	guint merge_id;
+	GtkWindow *wnd;
+	GtkAccelGroup *accel_group;
+	GtkWidget *menubar, *vbox;
+	GtkWindow *toplevel;
+
+	g_debug( "%s: window=%p", thisfn, ( void * ) window );
+
+	/* create the menubar:
+	 * - create action group, and insert list of actions in it
+	 * - create ui_manager, and insert action group in it
+	 * - merge inserted actions group with ui xml definition
+	 * - install accelerators in the main window
+	 * - pack menu bar in the main window
+	 */
+	ui_manager = gtk_ui_manager_new();
+	g_object_set_data_full( G_OBJECT( window ), MENUBAR_PROP_UI_MANAGER, ui_manager, ( GDestroyNotify ) on_destroy_callback  );
+	g_debug( "%s: ui_manager=%p", thisfn, ( void * ) ui_manager );
+
+	base_window_signal_connect(
+			BASE_WINDOW( window ),
+			G_OBJECT( ui_manager ),
+			"connect-proxy",
+			G_CALLBACK( on_proxy_connect ));
+
+	base_window_signal_connect(
+			BASE_WINDOW( window ),
+			G_OBJECT( ui_manager ),
+			"disconnect-proxy",
+			G_CALLBACK( on_proxy_disconnect ));
+
+	action_group = gtk_action_group_new( "MenubarActions" );
+	g_object_set_data_full( G_OBJECT( window ), MENUBAR_PROP_ACTIONS_GROUP, action_group, ( GDestroyNotify ) on_destroy_callback );
+	g_debug( "%s: action_group=%p", thisfn, ( void * ) action_group );
+
+	gtk_action_group_set_translation_domain( action_group, GETTEXT_PACKAGE );
+	gtk_action_group_add_actions( action_group, entries, G_N_ELEMENTS( entries ), window );
+	gtk_ui_manager_insert_action_group( ui_manager, action_group, 0 );
+
+	merge_id = gtk_ui_manager_add_ui_from_file( ui_manager, PKGDATADIR "/nautilus-actions-config-tool.actions", &error );
+	if( merge_id == 0 || error ){
+		g_warning( "%s: error=%s", thisfn, error->message );
+		g_error_free( error );
+	}
+
+	wnd = base_window_get_toplevel_window( BASE_WINDOW( window ));
+	accel_group = gtk_ui_manager_get_accel_group( ui_manager );
+	gtk_window_add_accel_group( wnd, accel_group );
+
+	menubar = gtk_ui_manager_get_widget( ui_manager, "/ui/MainMenubar" );
+	vbox = base_window_get_widget( BASE_WINDOW( window ), "MenubarVBox" );
+	gtk_box_pack_start( GTK_BOX( vbox ), menubar, FALSE, FALSE, 0 );
+
+	toplevel = base_window_get_toplevel_window( BASE_WINDOW( window ));
+	base_window_signal_connect(
+			BASE_WINDOW( window ),
+			G_OBJECT( toplevel ),
+			"delete-event",
+			G_CALLBACK( on_delete_event ));
+
+	base_window_signal_connect(
+			BASE_WINDOW( window ),
+			G_OBJECT( window ),
+			TAB_UPDATABLE_SIGNAL_SELECTION_UPDATED,
+			G_CALLBACK( on_tab_updatable_selection_updated ));
+}
+
+/**
+ * nact_main_menubar_refresh_actions_sensitivity:
+ *
+ * Sensitivity of items in the menubar is primarily refreshed when
+ * "tab-updatable-selection-updated" signal is received.
+ * This signal itself is sent on new selection in IActionsList.
+ * E.g in "cut" action, this happens before having stored the items
+ * in the clipboard.
+ * We so have to refresh the menubar items on demand.
+ */
+void
+nact_main_menubar_refresh_actions_sensitivity( NactMainWindow *window )
+{
+	GSList *selected;
+	guint count;
+
+	g_return_if_fail( NACT_MAIN_WINDOW( window ));
+	g_return_if_fail( NACT_IS_IACTIONS_LIST( window ));
+
+	selected = nact_iactions_list_get_selected_items( NACT_IACTIONS_LIST( window ));
+	count = g_slist_length( selected );
+	nact_iactions_list_free_items_list( NACT_IACTIONS_LIST( window ), selected );
+	refresh_actions_sensitivity_with_count( window, count );
+}
+
+static void
+on_tab_updatable_selection_updated( NactMainWindow *window, gint count_selected )
+{
+	refresh_actions_sensitivity_with_count( window, count_selected );
+}
+
+static void
+on_new_menu_activated( GtkAction *gtk_action, NactMainWindow *window )
+{
+	NAObjectMenu *menu;
+	GSList *items = NULL;
+
+	g_return_if_fail( GTK_IS_ACTION( gtk_action ));
+	g_return_if_fail( NACT_IS_MAIN_WINDOW( window ));
+
+	menu = na_object_menu_new();
+	na_object_check_edition_status( menu );
+	items = g_slist_prepend( items, menu );
+	nact_iactions_list_insert_items( NACT_IACTIONS_LIST( window ), items );
+
+	/*updates = g_slist_prepend( updates, g_object_ref( menu ));
+	g_signal_emit_by_name( window, IACTIONS_LIST_SIGNAL_ITEM_UPDATED, updates );*/
+
+	na_object_free_items( items );
+}
+
+static void
+on_new_action_activated( GtkAction *gtk_action, NactMainWindow *window )
+{
+	NAObjectAction *action;
+	GSList *items = NULL;
+
+	g_return_if_fail( GTK_IS_ACTION( gtk_action ));
+	g_return_if_fail( NACT_IS_MAIN_WINDOW( window ));
+
+	action = na_object_action_new_with_profile();
+	na_object_check_edition_status( action );
+	/*na_object_check_edition_status( na_object_action_get_profiles( action )->data );*/
+	items = g_slist_prepend( items, action );
+	nact_iactions_list_insert_items( NACT_IACTIONS_LIST( window ), items );
+
+	/*updates = g_slist_prepend( updates, g_object_ref( action ));
+	g_signal_emit_by_name( window, IACTIONS_LIST_SIGNAL_ITEM_UPDATED, updates );*/
+
+	na_object_free_items( items );
+}
+
+static void
+on_new_profile_activated( GtkAction *gtk_action, NactMainWindow *window )
+{
+	NAObjectAction *action;
+	NAObjectProfile *profile;
+	gchar *name;
+	GSList *items = NULL;
+
+	g_return_if_fail( GTK_IS_ACTION( gtk_action ));
+	g_return_if_fail( NACT_IS_MAIN_WINDOW( window ));
+
+	g_object_get(
+			G_OBJECT( window ),
+			TAB_UPDATABLE_PROP_EDITED_ACTION, &action,
+			NULL );
+
+	profile = na_object_profile_new();
+	name = na_object_action_get_new_profile_name( action );
+
+	na_object_action_attach_profile( action, profile );
+	na_object_set_id( profile, name );
+	na_object_check_edition_status( NA_OBJECT( profile ));
+	/*na_object_check_edited_status( NA_OBJECT( action ));*/
+	items = g_slist_prepend( items, profile );
+	nact_iactions_list_insert_items( NACT_IACTIONS_LIST( window ), items );
+
+	/*updates = g_slist_prepend( updates, g_object_ref( profile ));
+	g_signal_emit_by_name( window, IACTIONS_LIST_SIGNAL_ITEM_UPDATED, updates );*/
+
+	na_object_free_items( items );
+	g_free( name );
+}
+
+/*
+ * saving is not only saving modified items, but also saving hierarchy
+ * (and order if alpha order is not set)
+ */
+static void
+on_save_activated( GtkAction *gtk_action, NactMainWindow *window )
+{
+	GSList *items;
+	GSList *it;
+	NactApplication *application;
+	NAPivot *pivot;
+
+	g_return_if_fail( GTK_IS_ACTION( gtk_action ));
+	g_return_if_fail( NACT_IS_MAIN_WINDOW( window ));
+	g_return_if_fail( NACT_IS_WINDOW( window ));
+
+	items = nact_iactions_list_get_items( NACT_IACTIONS_LIST( window ));
+	nact_window_write_level_zero( NACT_WINDOW( window ), items );
+
+	/* recursively save the valid modified items
+	 */
+	application = NACT_APPLICATION( base_window_get_application( BASE_WINDOW( window )));
+	pivot = nact_application_get_pivot( application );
+
+	for( it = items ; it ; it = it->next ){
+		g_return_if_fail( NA_IS_OBJECT_ITEM( it->data ));
+		save_object_item( window, pivot, NA_OBJECT_ITEM( it->data ));
+	}
+
+	g_slist_free( items );
+
+	/* delete the removed actions
+	 */
+	nact_main_window_remove_deleted( window );
+
+	na_ipivot_consumer_delay_notify( NA_IPIVOT_CONSUMER( window ));
+}
+
+/*
+ * recursively saving an object item
+ * - add a duplicate of this action to pivot or update the origin
+ * - set the duplicate as the origin of this action
+ * - reset the status
+ */
+static void
+save_object_item( NactMainWindow *window, NAPivot *pivot, NAObjectItem *object )
+{
+	GSList *items, *it;
+
+	if( na_object_is_modified( NA_OBJECT( object )) &&
+		na_object_is_valid( NA_OBJECT( object )) &&
+		nact_window_save_object_item( NACT_WINDOW( window ), object )){
+
+			NAObjectItem *origin = NA_OBJECT_ITEM( na_object_get_origin( NA_OBJECT( object )));
+
+			if( origin ){
+				na_object_copy( NA_OBJECT( origin ), NA_OBJECT( object ));
+
+			} else {
+				NAObjectItem *dup_pivot = NA_OBJECT_ITEM( na_object_duplicate( NA_OBJECT( object )));
+				na_object_set_origin( NA_OBJECT( dup_pivot ), NULL );
+				na_object_set_origin( NA_OBJECT( object ), NA_OBJECT( dup_pivot ));
+				na_pivot_add_item( pivot, NA_OBJECT( dup_pivot ));
+			}
+
+			na_object_check_edition_status( NA_OBJECT( object ));
+	}
+
+	/* Profiles are saved with their actions
+	 * so we only have to take care of menus
+	 */
+	if( NA_IS_OBJECT_MENU( object )){
+		items = na_object_get_items( NA_OBJECT_MENU( object ));
+		for( it = items ; it ; it = it->next ){
+			g_return_if_fail( NA_IS_OBJECT_ITEM( it->data ));
+			save_object_item( window, pivot, NA_OBJECT_ITEM( it->data ));
+		}
+		na_object_free_items( items );
+	}
+}
+
+static void
+on_quit_activated( GtkAction *gtk_action, NactMainWindow *window )
+{
+	static const gchar *thisfn = "nact_main_menubar_on_quit_activated";
+	gint count;
+
+	g_debug( "%s: item=%p, window=%p", thisfn, ( void * ) gtk_action, ( void * ) window );
+	g_return_if_fail( GTK_IS_ACTION( gtk_action ) || gtk_action == NULL );
+	g_return_if_fail( NACT_IS_MAIN_WINDOW( window ));
+
+	count = nact_main_window_get_modified_items_count( window );
+	if( !count || nact_window_warn_count_modified( NACT_WINDOW( window ), count )){
+		g_object_unref( window );
+	}
+}
+
+static void
+on_cut_activated( GtkAction *gtk_action, NactMainWindow *window )
+{
+	GSList *items;
+
+	g_return_if_fail( GTK_IS_ACTION( gtk_action ));
+	g_return_if_fail( NACT_IS_MAIN_WINDOW( window ));
+
+	items = nact_main_window_delete_selection( window );
+	nact_clipboard_set( items );
+	nact_iactions_list_free_items_list( NACT_IACTIONS_LIST( window ), items );
+
+	/* the selection is modified before updating the clipboard, so we
+	 * need a manual refresh of actions sensitivity
+	 */
+	nact_main_menubar_refresh_actions_sensitivity( window );
+}
+
+static void
+on_copy_activated( GtkAction *gtk_action, NactMainWindow *window )
+{
+	GSList *items;
+
+	g_return_if_fail( GTK_IS_ACTION( gtk_action ));
+	g_return_if_fail( NACT_IS_MAIN_WINDOW( window ));
+
+	items = nact_iactions_list_get_selected_items( NACT_IACTIONS_LIST( window ));
+	nact_clipboard_set( items );
+	nact_iactions_list_free_items_list( NACT_IACTIONS_LIST( window ), items );
+
+	/* selection is not even modified, so a manuel refresh is needed
+	 */
+	nact_main_menubar_refresh_actions_sensitivity( window );
+}
+
+static void
+on_paste_activated( GtkAction *gtk_action, NactMainWindow *window )
+{
+	GSList *items;
+
+	items = nact_clipboard_get();
+	nact_iactions_list_free_items_list( NACT_IACTIONS_LIST( window ), items );
+
+	g_signal_emit_by_name( window, IACTIONS_LIST_SIGNAL_ITEM_UPDATED, NULL );
+}
+
+static void
+on_duplicate_activated( GtkAction *gtk_action, NactMainWindow *window )
+{
+	g_signal_emit_by_name( window, IACTIONS_LIST_SIGNAL_ITEM_UPDATED, NULL );
+}
+
+static void
+on_delete_activated( GtkAction *gtk_action, NactMainWindow *window )
+{
+	GSList *items;
+
+	g_return_if_fail( GTK_IS_ACTION( gtk_action ));
+	g_return_if_fail( NACT_IS_MAIN_WINDOW( window ));
+
+	items = nact_main_window_delete_selection( window );
+	nact_iactions_list_free_items_list( NACT_IACTIONS_LIST( window ), items );
+
+	g_signal_emit_by_name( window, IACTIONS_LIST_SIGNAL_ITEM_UPDATED, NULL );
+}
+
+static void
+on_reload_activated( GtkAction *gtk_action, NactMainWindow *window )
+{
+}
+
+static void
+on_preferences_activated( GtkAction *gtk_action, NactMainWindow *window )
+{
+	nact_preferences_editor_run( BASE_WINDOW( window ));
+}
+
+static void
+on_import_activated( GtkAction *gtk_action, NactMainWindow *window )
+{
+	nact_assistant_import_run( BASE_WINDOW( window ));
+}
+
+static void
+on_export_activated( GtkAction *gtk_action, NactMainWindow *window )
+{
+	nact_assistant_export_run( BASE_WINDOW( window ));
+}
+
+static void
+on_help_activated( GtkAction *gtk_action, NactMainWindow *window )
+{
+}
+
+static void
+on_about_activated( GtkAction *gtk_action, NactMainWindow *window )
+{
+	GtkWindow *toplevel;
+
+	toplevel = base_window_get_toplevel_window( BASE_WINDOW( window ));
+
+	na_about_display( G_OBJECT( toplevel ));
+}
+
+static void
+enable_item( NactMainWindow *window, const gchar *name, gboolean enabled )
+{
+	GtkActionGroup *group;
+	GtkAction *action;
+
+	group = g_object_get_data( G_OBJECT( window ), MENUBAR_PROP_ACTIONS_GROUP );
+	action = gtk_action_group_get_action( group, name );
+	gtk_action_set_sensitive( action, enabled );
+}
+
+static gboolean
+on_delete_event( GtkWidget *toplevel, GdkEvent *event, NactMainWindow *window )
+{
+	static const gchar *thisfn = "nact_main_menubar_on_delete_event";
+
+	g_debug( "%s: toplevel=%p, event=%p, window=%p",
+			thisfn, ( void * ) toplevel, ( void * ) event, ( void * ) window );
+
+	on_quit_activated( NULL, window );
+
+	return( TRUE );
+}
+
+/*
+ * this callback is declared when attaching ui_manager and actions_group
+ * as data to the window ; it is so triggered on NactMainWindow::finalize()
+ */
+static void
+on_destroy_callback( gpointer data )
+{
+	g_debug( "nact_main_menubar_on_destroy_callback: data=%p", ( void * ) data );
+	g_object_unref( G_OBJECT( data ));
+}
+
+static void
+on_menu_item_selected( GtkMenuItem *proxy, NactMainWindow *window )
+{
+	GtkAction *action;
+	const gchar *tooltip;
+
+	action = gtk_activatable_get_related_action( GTK_ACTIVATABLE( proxy ));
+	if( !action ){
+		return;
+	}
+
+	tooltip = gtk_action_get_tooltip( action );
+	if( !tooltip ){
+		return;
+	}
+
+	nact_main_statusbar_display_status( window, MENUBAR_PROP_STATUS_CONTEXT, tooltip );
+}
+
+static void
+on_menu_item_deselected( GtkMenuItem *proxy, NactMainWindow *window )
+{
+	nact_main_statusbar_hide_status( window, MENUBAR_PROP_STATUS_CONTEXT );
+}
+
+static void
+on_proxy_connect( GtkActionGroup *action_group, GtkAction *action, GtkWidget *proxy, NactMainWindow *window )
+{
+	g_debug( "on_proxy_connect: action_group=%p, action=%p, proxy=%p, window=%p",
+			( void * ) action_group, ( void * ) action, ( void * ) proxy, ( void * ) window );
+
+	if( GTK_IS_MENU_ITEM( proxy )){
+
+		base_window_signal_connect(
+				BASE_WINDOW( window ),
+				G_OBJECT( proxy ),
+				"select",
+				G_CALLBACK( on_menu_item_selected ));
+
+		base_window_signal_connect(
+				BASE_WINDOW( window ),
+				G_OBJECT( proxy ),
+				"deselect",
+				G_CALLBACK( on_menu_item_deselected ));
+	}
+}
+
+static void
+on_proxy_disconnect( GtkActionGroup *action_group, GtkAction *action, GtkWidget *proxy, NactMainWindow *window )
+{
+	/* signal handlers will be automagically disconnected on NactWindow::dispose */
+}
+
+static void
+refresh_actions_sensitivity_with_count( NactMainWindow *window, gint count_selected )
+{
+	static const gchar *thisfn = "nact_main_menubar_refresh_actions_sensitivity_with_count";
+	NAObjectItem *item;
+	NAObjectProfile *profile;
+	guint count_all;
+	guint count_modified;
+	gboolean is_clipboard_empty;
+
+	g_debug( "%s: window=%p, count_selected=%d", thisfn, ( void * ) window, count_selected );
+	g_return_if_fail( NACT_IS_MAIN_WINDOW( window ));
+
+	g_object_get(
+			G_OBJECT( window ),
+			TAB_UPDATABLE_PROP_EDITED_ACTION, &item,
+			TAB_UPDATABLE_PROP_EDITED_PROFILE, &profile,
+			NULL );
+
+	count_all = nact_main_window_get_all_items_count( window );
+	count_modified = nact_main_window_get_modified_items_count( window );
+	is_clipboard_empty = nact_clipboard_is_empty();
+
+	/* new menu always enabled */
+	/* new action always enabled */
+	/* new profile enabled if selection is relative to only one action */
+	enable_item( window, "NewProfileItem", item != NULL && !NA_IS_OBJECT_MENU( item ));
+	/* save enabled if at least one item has been modified */
+	enable_item( window, "SaveItem", count_modified > 0 );
+	/* quit always enabled */
+	/* cut/copy enabled if selection not empty */
+	enable_item( window, "CutItem", count_selected > 0 );
+	enable_item( window, "CopyItem", count_selected > 0 );
+	/* paste enabled if clipboard not empty */
+	enable_item( window, "PasteItem", !is_clipboard_empty );
+	/* duplicate/delete enabled if selection not empty */
+	enable_item( window, "DuplicateItem", count_selected > 0 );
+	enable_item( window, "DeleteItem", count_selected > 0 );
+	/* reload items always enabled */
+	/* preferences always enabled */
+	/* import item always enabled */
+	/* export item enabled if IActionsList not empty */
+	enable_item( window, "ExportItem", count_all > 0 );
+	/* TODO: help temporarily disabled */
+	enable_item( window, "HelpItem", FALSE );
+	/* about always enabled */
+}
diff --git a/src/nact/nact-statusbar.h b/src/nact/nact-main-menubar.h
similarity index 80%
copy from src/nact/nact-statusbar.h
copy to src/nact/nact-main-menubar.h
index 6d8221a..8559bbb 100644
--- a/src/nact/nact-statusbar.h
+++ b/src/nact/nact-main-menubar.h
@@ -28,16 +28,22 @@
  *   ... and many others (see AUTHORS)
  */
 
-#ifndef __NACT_STATUSBAR_H__
-#define __NACT_STATUSBAR_H__
+#ifndef __NACT_MAIN_MENUBAR_H__
+#define __NACT_MAIN_MENUBAR_H__
+
+/*
+ * Menu bar management.
+ */
+
+#include <gtk/gtk.h>
 
 #include "nact-main-window.h"
 
 G_BEGIN_DECLS
 
-void  nact_statusbar_display_status( NactMainWindow *window, const gchar *context, const gchar *status );
-void  nact_statusbar_hide_status( NactMainWindow *window, const gchar *context );
+void  nact_main_menubar_runtime_init( NactMainWindow *window );
+void  nact_main_menubar_refresh_actions_sensitivity( NactMainWindow *window );
 
 G_END_DECLS
 
-#endif /* __NACT_STATUSBAR_H__ */
+#endif /* __NACT_NACT_MENUBAR_H__ */
diff --git a/src/nact/nact-statusbar.c b/src/nact/nact-main-statusbar.c
similarity index 68%
rename from src/nact/nact-statusbar.c
rename to src/nact/nact-main-statusbar.c
index ee59c8f..51e7895 100644
--- a/src/nact/nact-statusbar.c
+++ b/src/nact/nact-main-statusbar.c
@@ -32,12 +32,21 @@
 #include <config.h>
 #endif
 
-#include "nact-statusbar.h"
+#include "nact-main-statusbar.h"
+
+static GtkStatusbar *get_statusbar( const NactMainWindow *window );
 
 void
-nact_statusbar_display_status( NactMainWindow *window, const gchar *context, const gchar *status )
+nact_main_statusbar_display_status( NactMainWindow *window, const gchar *context, const gchar *status )
 {
-	GtkStatusbar *bar = nact_main_window_get_statusbar( window );
+	GtkStatusbar *bar;
+
+	if( !status || !g_utf8_strlen( status, -1 )){
+		return;
+	}
+
+	bar = get_statusbar( window );
+
 	if( bar ){
 		guint context_id = gtk_statusbar_get_context_id( bar, context );
 		gtk_statusbar_push( bar, context_id, status );
@@ -45,11 +54,27 @@ nact_statusbar_display_status( NactMainWindow *window, const gchar *context, con
 }
 
 void
-nact_statusbar_hide_status( NactMainWindow *window, const gchar *context )
+nact_main_statusbar_hide_status( NactMainWindow *window, const gchar *context )
 {
-	GtkStatusbar *bar = nact_main_window_get_statusbar( window );
+	GtkStatusbar *bar;
+
+	bar = get_statusbar( window );
+
 	if( bar ){
 		guint context_id = gtk_statusbar_get_context_id( bar, context );
 		gtk_statusbar_pop( bar, context_id );
 	}
 }
+
+/**
+ * Returns the status bar widget
+ */
+static GtkStatusbar *
+get_statusbar( const NactMainWindow *window )
+{
+	GtkWidget *statusbar;
+
+	statusbar = base_window_get_widget( BASE_WINDOW( window ), "StatusBar" );
+
+	return( GTK_STATUSBAR( statusbar ));
+}
diff --git a/src/nact/nact-selection.h b/src/nact/nact-main-statusbar.h
similarity index 78%
rename from src/nact/nact-selection.h
rename to src/nact/nact-main-statusbar.h
index 0ac54c6..8b2e36f 100644
--- a/src/nact/nact-selection.h
+++ b/src/nact/nact-main-statusbar.h
@@ -28,18 +28,16 @@
  *   ... and many others (see AUTHORS)
  */
 
-#ifndef __NACT_DND_H__
-#define __NACT_DND_H__
+#ifndef __NACT_MAIN_STATUSBAR_H__
+#define __NACT_MAIN_STATUSBAR_H__
 
-#include <glib.h>
+#include "nact-main-window.h"
 
 G_BEGIN_DECLS
 
-char *nact_selection_get_data_for_intern_use( GSList *selected_items );
-char *nact_selection_get_data_for_extern_use( GSList *selected_items );
-
-void  nact_selection_export_items( const gchar *uri, GSList *items );
+void  nact_main_statusbar_display_status( NactMainWindow *window, const gchar *context, const gchar *status );
+void  nact_main_statusbar_hide_status( NactMainWindow *window, const gchar *context );
 
 G_END_DECLS
 
-#endif /* __NACT_DND_H__ */
+#endif /* __NACT_MAIN_STATUSBAR_H__ */
diff --git a/src/nact/nact-main-tab.c b/src/nact/nact-main-tab.c
new file mode 100644
index 0000000..a80a21b
--- /dev/null
+++ b/src/nact/nact-main-tab.c
@@ -0,0 +1,162 @@
+/*
+ * 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 "nact-window.h"
+#include "nact-itab-updatable.h"
+
+/* private interface data
+ */
+struct NactITabUpdatableInterfacePrivate {
+	void *empty;						/* so that gcc -pedantic is happy */
+};
+
+/* signals
+ */
+enum {
+	SELECTION_UPDATED,
+	LAST_SIGNAL
+};
+
+static gint  st_signals[ LAST_SIGNAL ] = { 0 };
+
+static GType register_type( void );
+static void  interface_base_init( NactITabUpdatableInterface *klass );
+static void  interface_base_finalize( NactITabUpdatableInterface *klass );
+
+GType
+nact_itab_updatable_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_itab_updatable_register_type";
+	GType type;
+
+	static const GTypeInfo info = {
+		sizeof( NactITabUpdatableInterface ),
+		( GBaseInitFunc ) interface_base_init,
+		( GBaseFinalizeFunc ) interface_base_finalize,
+		NULL,
+		NULL,
+		NULL,
+		0,
+		0,
+		NULL
+	};
+
+	g_debug( "%s", thisfn );
+
+	type = g_type_register_static( G_TYPE_INTERFACE, "NactITabUpdatable", &info, 0 );
+
+	g_type_interface_add_prerequisite( type, NACT_WINDOW_TYPE );
+
+	return( type );
+}
+
+static void
+interface_base_init( NactITabUpdatableInterface *klass )
+{
+	static const gchar *thisfn = "nact_itab_updatable_interface_base_init";
+	static gboolean initialized = FALSE;
+
+	if( !initialized ){
+		g_debug( "%s: klass=%p", thisfn, ( void * ) klass );
+
+		klass->private = g_new0( NactITabUpdatableInterfacePrivate, 1 );
+
+		/**
+		 * "nact-tab-updatable-selection-updated":
+		 *
+		 * This signal is emitted to inform updatable tabs that a new
+		 * item has been selected, and the displays should reflect it.
+		 *
+		 * NactMainWindow emits this signal with user_data = count_selected.
+		 */
+		st_signals[ SELECTION_UPDATED ] = g_signal_new(
+				ITAB_UPDATABLE_SIGNAL_SELECTION_UPDATED,
+				G_TYPE_OBJECT,
+				G_SIGNAL_RUN_LAST,
+				0,					/* no default handler */
+				NULL,
+				NULL,
+				g_cclosure_marshal_VOID__POINTER,
+				G_TYPE_NONE,
+				1,
+				G_TYPE_POINTER );
+
+		initialized = TRUE;
+	}
+}
+
+static void
+interface_base_finalize( NactITabUpdatableInterface *klass )
+{
+	static const gchar *thisfn = "nact_itab_updatable_interface_base_finalize";
+	static gboolean finalized = FALSE ;
+
+	if( !finalized ){
+		g_debug( "%s: klass=%p", thisfn, ( void * ) klass );
+
+		g_free( klass->private );
+
+		finalized = TRUE;
+	}
+}
+
+/*void
+nact_itab_updatable_update_selection( NactITabUpdatable *instance )
+{
+	v_selection_updated( instance );
+}
+
+static void
+v_selection_updated( NactITabUpdatable *instance )
+{
+	static const gchar *thisfn = "nact_itab_updatable_v_selection_updated";
+
+	g_debug( "%s: instance=%p", thisfn, ( void * ) instance );
+
+	if( NACT_ITAB_UPDATABLE_GET_INTERFACE( instance )->selection_updated ){
+		NACT_ITAB_UPDATABLE_GET_INTERFACE( instance )->selection_updated( instance );
+	}
+}*/
diff --git a/src/nact/nact-statusbar.h b/src/nact/nact-main-tab.h
similarity index 75%
rename from src/nact/nact-statusbar.h
rename to src/nact/nact-main-tab.h
index 6d8221a..d52306c 100644
--- a/src/nact/nact-statusbar.h
+++ b/src/nact/nact-main-tab.h
@@ -28,16 +28,18 @@
  *   ... and many others (see AUTHORS)
  */
 
-#ifndef __NACT_STATUSBAR_H__
-#define __NACT_STATUSBAR_H__
+#ifndef __NACT_MAIN_TAB_H__
+#define __NACT_MAIN_TAB_H__
 
-#include "nact-main-window.h"
-
-G_BEGIN_DECLS
+/* properties set against the GObject instance
+ */
+#define TAB_UPDATABLE_PROP_EDITED_ACTION				"nact-tab-updatable-edited-action"
+#define TAB_UPDATABLE_PROP_EDITED_PROFILE				"nact-tab-updatable-edited-profile"
 
-void  nact_statusbar_display_status( NactMainWindow *window, const gchar *context, const gchar *status );
-void  nact_statusbar_hide_status( NactMainWindow *window, const gchar *context );
+/* signals
+ */
+#define TAB_UPDATABLE_SIGNAL_SELECTION_UPDATED			"nact-tab-updatable-selection-updated"
 
 G_END_DECLS
 
-#endif /* __NACT_STATUSBAR_H__ */
+#endif /* __NACT_MAIN_TAB_H__ */
diff --git a/src/nact/nact-main-window.c b/src/nact/nact-main-window.c
index bf524e5..78a7e5f 100644
--- a/src/nact/nact-main-window.c
+++ b/src/nact/nact-main-window.c
@@ -37,19 +37,21 @@
 #include <glib/gi18n.h>
 #include <gtk/gtk.h>
 
+#include <common/na-object-api.h>
 #include <common/na-pivot.h>
 #include <common/na-iio-provider.h>
 #include <common/na-ipivot-consumer.h>
 #include <common/na-iprefs.h>
 
+#include "base-iprefs.h"
 #include "nact-application.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-tab.h"
+#include "nact-main-menubar.h"
 #include "nact-main-window.h"
 
 /* private class data
@@ -62,74 +64,92 @@ struct NactMainWindowClassPrivate {
  */
 struct NactMainWindowPrivate {
 	gboolean         dispose_has_run;
-	gint             initial_count;
-	GSList          *actions;
-	NAAction        *edited_action;
-	NAActionProfile *edited_profile;
+
+	/* TODO: this will have to be replaced with undo-manager */
 	GSList          *deleted;
+
+	/**
+	 * Currently edited action or menu.
+	 *
+	 * This is the action or menu which is displayed in tab Action ;
+	 * it may be different of the row being currently selected.
+	 *
+	 * Can be null, and this implies that edited_profile is also null.
+	 */
+	NAObjectItem    *edited_item;
+
+	/**
+	 * Edition status for the edited action or menu.
+	 *
+	 * Menu is always editable as only displayed if it is the currently
+	 * selected item.
+	 *
+	 * Action is only enable if the action itself, or an action with
+	 * only one profile, is currently selected
+	 */
+	/* TODO: remove this variable */
+	/*gboolean         edition_enabled;*/
+
+	/**
+	 * Currently edited profile.
+	 *
+	 * This is the profile which is displayed in tabs Command,
+	 * Conditions and Advanced ; it may be different of the row being
+	 * currently selected.
+	 *
+	 * Can be null and this implies that the edited item is a menu
+	 * (because an action cannot have zero profile).
+	 */
+	NAObjectProfile *edited_profile;
 };
 
-/* the GConf key used to read/write size and position of auxiliary dialogs
+/* action properties
  */
-#define IPREFS_IMPORT_ACTIONS		"main-window-import-actions"
-
-static GObjectClass *st_parent_class = NULL;
-
-static GType            register_type( void );
-static void             class_init( NactMainWindowClass *klass );
-static void             iactions_list_iface_init( NactIActionsListInterface *iface );
-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             imenubar_iface_init( NactIMenubarInterface *iface );
-static void             ipivot_consumer_iface_init( NAIPivotConsumerInterface *iface );
-static void             iprefs_iface_init( NAIPrefsInterface *iface );
-static void             instance_init( GTypeInstance *instance, gpointer klass );
-static void             instance_dispose( GObject *application );
-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 void             on_initial_load_toplevel( BaseWindow *window );
-static void             on_runtime_init_toplevel( BaseWindow *window );
-static void             setup_dialog_title( NactWindow *window );
-
-static void             on_actions_list_selection_changed( NactIActionsList *instance, GSList *selected_items );
-static gboolean         on_actions_list_double_click( GtkWidget *widget, GdkEventButton *event, gpointer data );
-static gboolean         on_actions_list_enter_key_pressed( GtkWidget *widget, GdkEventKey *event, gpointer data );
-static void             set_current_action( NactMainWindow *window, GSList *selected_items );
-static void             set_current_profile( NactMainWindow *window, gboolean set_action, GSList *selected_items );
-static NAAction        *get_edited_action( NactWindow *window );
-static NAActionProfile *get_edited_profile( NactWindow *window );
-static void             on_modified_field( NactWindow *window );
-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             insert_item( 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             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             reload_actions( NactWindow *window );
-static GSList          *free_actions( GSList *actions );
-static void             on_actions_changed( NAIPivotConsumer *instance, gpointer user_data );
-static void             on_display_order_changed( NAIPivotConsumer *instance, gpointer user_data );
-static void             sort_actions_list( NactMainWindow *window );
+enum {
+	PROP_EDITED_ITEM = 1,
+	PROP_ITEM_EDITION_ENABLED,
+	PROP_EDITED_PROFILE
+};
+
+/* signals
+ */
+enum {
+	SELECTION_UPDATED,
+	LAST_SIGNAL
+};
+
+static NactWindowClass *st_parent_class = NULL;
+static gint             st_signals[ LAST_SIGNAL ] = { 0 };
+
+static GType    register_type( void );
+static void     class_init( NactMainWindowClass *klass );
+static void     iactions_list_iface_init( NactIActionsListInterface *iface );
+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_consumer_iface_init( NAIPivotConsumerInterface *iface );
+static void     iprefs_iface_init( NAIPrefsInterface *iface );
+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 *application );
+static void     instance_finalize( GObject *application );
+
+static void     actually_delete_item( NactMainWindow *window, NAObject *item, NAPivot *pivot );
+
+static gchar   *base_get_toplevel_name( BaseWindow *window );
+static gchar   *base_get_iprefs_window_id( BaseWindow *window );
+static void     on_base_initial_load_toplevel( NactMainWindow *window, gpointer user_data );
+static void     on_base_runtime_init_toplevel( NactMainWindow *window, gpointer user_data );
+static void     on_base_all_widgets_showed( NactMainWindow *window, gpointer user_data );
+
+static void     iactions_list_selection_changed( NactIActionsList *instance, GSList *selected_items );
+static void     set_current_object_item( NactMainWindow *window, GSList *selected_items );
+static void     set_current_profile( NactMainWindow *window, gboolean set_action, GSList *selected_items );
+
+static void     ipivot_consumer_on_actions_changed( NAIPivotConsumer *instance, gpointer user_data );
+static void     ipivot_consumer_on_display_order_changed( NAIPivotConsumer *instance, gpointer user_data );
 
 GType
 nact_main_window_get_type( void )
@@ -191,12 +211,6 @@ register_type( void )
 		NULL
 	};
 
-	static const GInterfaceInfo imenubar_iface_info = {
-		( GInterfaceInitFunc ) imenubar_iface_init,
-		NULL,
-		NULL
-	};
-
 	static const GInterfaceInfo ipivot_consumer_iface_info = {
 		( GInterfaceInitFunc ) ipivot_consumer_iface_init,
 		NULL,
@@ -223,8 +237,6 @@ register_type( void )
 
 	g_type_add_interface_static( type, NACT_IADVANCED_TAB_TYPE, &iadvanced_tab_iface_info );
 
-	g_type_add_interface_static( type, NACT_IMENUBAR_TYPE, &imenubar_iface_info );
-
 	g_type_add_interface_static( type, NA_IPIVOT_CONSUMER_TYPE, &ipivot_consumer_iface_info );
 
 	g_type_add_interface_static( type, NA_IPREFS_TYPE, &iprefs_iface_info );
@@ -238,7 +250,7 @@ class_init( NactMainWindowClass *klass )
 	static const gchar *thisfn = "nact_main_window_class_init";
 	GObjectClass *object_class;
 	BaseWindowClass *base_class;
-	NactWindowClass *nact_class;
+	GParamSpec *spec;
 
 	g_debug( "%s: klass=%p", thisfn, ( void * ) klass );
 
@@ -247,17 +259,53 @@ class_init( NactMainWindowClass *klass )
 	object_class = G_OBJECT_CLASS( klass );
 	object_class->dispose = instance_dispose;
 	object_class->finalize = instance_finalize;
+	object_class->set_property = instance_set_property;
+	object_class->get_property = instance_get_property;
+
+	spec = g_param_spec_pointer(
+			TAB_UPDATABLE_PROP_EDITED_ACTION,
+			"Edited NAObjectItem",
+			"A pointer to the edited NAObjectItem, an action or a menu",
+			G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE );
+	g_object_class_install_property( object_class, PROP_EDITED_ITEM, spec );
+
+	/*spec = g_param_spec_boolean(
+			TAB_UPDATABLE_PROP_EDITION_ACTION_ENABLED,
+			"Edition enabled",
+			"Whether editing the characteristics of NAObjectItem is allowed", FALSE,
+			G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE );
+	g_object_class_install_property( object_class, PROP_ITEM_EDITION_ENABLED, spec );*/
+
+	spec = g_param_spec_pointer(
+			TAB_UPDATABLE_PROP_EDITED_PROFILE,
+			"Edited NAObjectProfile",
+			"A pointer to the edited NAObjectProfile",
+			G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE );
+	g_object_class_install_property( object_class, PROP_EDITED_PROFILE, spec );
 
 	klass->private = g_new0( NactMainWindowClassPrivate, 1 );
 
 	base_class = BASE_WINDOW_CLASS( klass );
-	base_class->get_toplevel_name = get_toplevel_name;
-	base_class->initial_load_toplevel = on_initial_load_toplevel;
-	base_class->runtime_init_toplevel = on_runtime_init_toplevel;
-	base_class->delete_event = on_delete_event;
-
-	nact_class = NACT_WINDOW_CLASS( klass );
-	nact_class->get_iprefs_window_id = get_iprefs_window_id;
+	base_class->get_toplevel_name = base_get_toplevel_name;
+	base_class->get_iprefs_window_id = base_get_iprefs_window_id;
+
+	/**
+	 * "nact-tab-updatable-selection-updated":
+	 *
+	 * This signal is emitted to inform updatable tabs that a new
+	 * item has been selected, and the displays should reflect it.
+	 */
+	st_signals[ SELECTION_UPDATED ] = g_signal_new(
+			TAB_UPDATABLE_SIGNAL_SELECTION_UPDATED,
+			G_TYPE_OBJECT,
+			G_SIGNAL_RUN_LAST,
+			0,					/* no default handler */
+			NULL,
+			NULL,
+			g_cclosure_marshal_VOID__POINTER,
+			G_TYPE_NONE,
+			1,
+			G_TYPE_POINTER );
 }
 
 static void
@@ -267,15 +315,7 @@ iactions_list_iface_init( NactIActionsListInterface *iface )
 
 	g_debug( "%s: iface=%p", thisfn, ( void * ) 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 = NULL;
-	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;
+	iface->selection_changed = iactions_list_selection_changed;
 }
 
 static void
@@ -284,9 +324,6 @@ iaction_tab_iface_init( NactIActionTabInterface *iface )
 	static const gchar *thisfn = "nact_main_window_iaction_tab_iface_init";
 
 	g_debug( "%s: iface=%p", thisfn, ( void * ) iface );
-
-	iface->get_edited_action = get_edited_action;
-	iface->field_modified = on_modified_field;
 }
 
 static void
@@ -295,12 +332,6 @@ icommand_tab_iface_init( NactICommandTabInterface *iface )
 	static const gchar *thisfn = "nact_main_window_icommand_tab_iface_init";
 
 	g_debug( "%s: iface=%p", thisfn, ( void * ) iface );
-
-	iface->get_edited_profile = get_edited_profile;
-	iface->field_modified = on_modified_field;
-	iface->get_isfiledir = get_isfiledir;
-	iface->get_multiple = get_multiple;
-	iface->get_schemes = get_schemes;
 }
 
 static void
@@ -309,9 +340,6 @@ iconditions_tab_iface_init( NactIConditionsTabInterface *iface )
 	static const gchar *thisfn = "nact_main_window_iconditions_tab_iface_init";
 
 	g_debug( "%s: iface=%p", thisfn, ( void * ) iface );
-
-	iface->get_edited_profile = get_edited_profile;
-	iface->field_modified = on_modified_field;
 }
 
 static void
@@ -320,32 +348,6 @@ iadvanced_tab_iface_init( NactIAdvancedTabInterface *iface )
 	static const gchar *thisfn = "nact_main_window_iadvanced_tab_iface_init";
 
 	g_debug( "%s: iface=%p", thisfn, ( void * ) iface );
-
-	iface->get_edited_profile = get_edited_profile;
-	iface->field_modified = on_modified_field;
-}
-
-static void
-imenubar_iface_init( NactIMenubarInterface *iface )
-{
-	static const gchar *thisfn = "nact_main_window_imenubar_iface_init";
-
-	g_debug( "%s: iface=%p", thisfn, ( void * ) iface );
-
-	iface->insert_item = insert_item;
-	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->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->reload_actions = reload_actions;
 }
 
 static void
@@ -355,8 +357,8 @@ ipivot_consumer_iface_init( NAIPivotConsumerInterface *iface )
 
 	g_debug( "%s: iface=%p", thisfn, ( void * ) iface );
 
-	iface->on_actions_changed = on_actions_changed;
-	iface->on_display_order_changed = on_display_order_changed;
+	iface->on_actions_changed = ipivot_consumer_on_actions_changed;
+	iface->on_display_order_changed = ipivot_consumer_on_display_order_changed;
 }
 
 static void
@@ -380,10 +382,82 @@ instance_init( GTypeInstance *instance, gpointer klass )
 
 	self->private = g_new0( NactMainWindowPrivate, 1 );
 
+	base_window_signal_connect(
+			BASE_WINDOW( instance ),
+			G_OBJECT( instance ),
+			BASE_WINDOW_SIGNAL_INITIAL_LOAD,
+			G_CALLBACK( on_base_initial_load_toplevel ));
+
+	base_window_signal_connect(
+			BASE_WINDOW( instance ),
+			G_OBJECT( instance ),
+			BASE_WINDOW_SIGNAL_RUNTIME_INIT,
+			G_CALLBACK( on_base_runtime_init_toplevel ));
+
+	base_window_signal_connect(
+			BASE_WINDOW( instance ),
+			G_OBJECT( instance ),
+			BASE_WINDOW_SIGNAL_ALL_WIDGETS_SHOWED,
+			G_CALLBACK( on_base_all_widgets_showed ));
+
 	self->private->dispose_has_run = FALSE;
 }
 
 static void
+instance_get_property( GObject *object, guint property_id, GValue *value, GParamSpec *spec )
+{
+	NactMainWindow *self;
+
+	g_assert( NACT_IS_MAIN_WINDOW( object ));
+	self = NACT_MAIN_WINDOW( object );
+
+	switch( property_id ){
+		case PROP_EDITED_ITEM:
+			g_value_set_pointer( value, self->private->edited_item );
+			break;
+
+		/*case PROP_ITEM_EDITION_ENABLED:
+			g_value_set_boolean( value, self->private->edition_enabled );
+			break;*/
+
+		case PROP_EDITED_PROFILE:
+			g_value_set_pointer( value, self->private->edited_profile );
+			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 )
+{
+	NactMainWindow *self;
+
+	g_assert( NACT_IS_MAIN_WINDOW( object ));
+	self = NACT_MAIN_WINDOW( object );
+
+	switch( property_id ){
+		case PROP_EDITED_ITEM:
+			self->private->edited_item = g_value_get_pointer( value );
+			break;
+
+		/*case PROP_ITEM_EDITION_ENABLED:
+			self->private->edition_enabled = g_value_get_boolean( value );
+			break;*/
+
+		case PROP_EDITED_PROFILE:
+			self->private->edited_profile = g_value_get_pointer( value );
+			break;
+
+		default:
+			G_OBJECT_WARN_INVALID_PROPERTY_ID( object, property_id, spec );
+			break;
+	}
+}
+
+static void
 instance_dispose( GObject *window )
 {
 	static const gchar *thisfn = "nact_main_window_instance_dispose";
@@ -397,22 +471,24 @@ instance_dispose( GObject *window )
 
 	if( !self->private->dispose_has_run ){
 
-		self->private->dispose_has_run = TRUE;
-
 		pane = base_window_get_widget( BASE_WINDOW( window ), "MainPaned" );
 		pos = gtk_paned_get_position( GTK_PANED( pane ));
-		nact_iprefs_set_int( NACT_WINDOW( window ), "main-paned", pos );
+		base_iprefs_set_int( BASE_WINDOW( window ), "main-paned", pos );
 
-		self->private->actions = free_actions( self->private->actions );
-		self->private->deleted = free_actions( self->private->deleted );
+		self->private->deleted = na_pivot_free_items_tree( self->private->deleted );
 
-		nact_iaction_tab_dispose( NACT_WINDOW( window ));
-		nact_icommand_tab_dispose( NACT_WINDOW( window ));
-		nact_iconditions_tab_dispose( NACT_WINDOW( window ));
-		nact_iadvanced_tab_dispose( NACT_WINDOW( window ));
+		nact_iactions_list_dispose( NACT_IACTIONS_LIST( window ));
+		nact_iaction_tab_dispose( NACT_IACTION_TAB( window ));
+		nact_icommand_tab_dispose( NACT_ICOMMAND_TAB( window ));
+		nact_iconditions_tab_dispose( NACT_ICONDITIONS_TAB( window ));
+		nact_iadvanced_tab_dispose( NACT_IADVANCED_TAB( window ));
 
 		/* chain up to the parent class */
-		G_OBJECT_CLASS( st_parent_class )->dispose( window );
+		if( G_OBJECT_CLASS( st_parent_class )->dispose ){
+			G_OBJECT_CLASS( st_parent_class )->dispose( window );
+		}
+
+		self->private->dispose_has_run = TRUE;
 	}
 }
 
@@ -425,12 +501,12 @@ instance_finalize( GObject *window )
 	g_debug( "%s: window=%p", thisfn, ( void * ) window );
 
 	g_assert( NACT_IS_MAIN_WINDOW( window ));
-	self = ( NactMainWindow * ) window;
+	self = NACT_MAIN_WINDOW( window );
 
 	g_free( self->private );
 
 	/* chain call to parent class */
-	if( st_parent_class->finalize ){
+	if( G_OBJECT_CLASS( st_parent_class )->finalize ){
 		G_OBJECT_CLASS( st_parent_class )->finalize( window );
 	}
 }
@@ -443,71 +519,183 @@ nact_main_window_new( BaseApplication *application )
 {
 	g_assert( NACT_IS_APPLICATION( application ));
 
-	return( g_object_new( NACT_MAIN_WINDOW_TYPE, PROP_WINDOW_APPLICATION_STR, application, NULL ));
+	return( g_object_new( NACT_MAIN_WINDOW_TYPE, BASE_WINDOW_PROP_APPLICATION, application, NULL ));
 }
 
 /**
- * Returns the current list of actions
- */
-GSList *
-nact_main_window_get_actions( const NactMainWindow *window )
-{
-	return( window->private->actions );
-}
-
-/**
- * The specified action does already exist in the list ?
+ * nact_main_window_action_exists:
+ * @window: this #NactMainWindow instance.
+ * @uuid: the uuid to check for existancy.
+ *
+ * Returns: %TRUE if the specified action already exists in the system,
+ * %FALSE else.
+ *
+ * We have to check against existing actions in #NAPivot, and against
+ * currently edited actions in #NactIActionsList.
  */
 gboolean
 nact_main_window_action_exists( const NactMainWindow *window, const gchar *uuid )
 {
-	GSList *ia;
+	/*GSList *ia;*/
 
-	for( ia = window->private->actions ; ia ; ia = ia->next ){
-		NAAction *action = NA_ACTION( ia->data );
-		gchar *action_uuid = na_action_get_uuid( action );
+	g_assert( FALSE );
+	/* TODO: search in current state of the tree store + in pivot */
+	/*for( ia = window->private->actions ; ia ; ia = ia->next ){
+		NAObjectAction *action = NA_ACTION( ia->data );
+		gchar *action_uuid = na_object_action_get_uuid( action );
 		gboolean ok = ( g_ascii_strcasecmp( action_uuid, uuid ) == 0 );
 		g_free( action_uuid );
 		if( ok ){
 			return( TRUE );
 		}
-	}
+	}*/
 
 	return( FALSE );
 }
 
+GSList *
+nact_main_window_delete_selection( NactMainWindow *window )
+{
+	static const gchar *thisfn = "nact_main_window_delete_selection";
+	GtkTreePath *path;
+	GSList *deleted;
+	GSList *it;
+
+	g_return_val_if_fail( NACT_IS_MAIN_WINDOW( window ), 0 );
+	g_return_val_if_fail( NACT_IS_IACTIONS_LIST( window ), 0 );
+
+	deleted = nact_iactions_list_delete_selection( NACT_IACTIONS_LIST( window ), &path );
+
+	for( it = deleted ; it ; it = it->next ){
+		g_debug( "%s: deleting %s at %p", thisfn, G_OBJECT_TYPE_NAME( it->data ), ( void * ) it->data );
+		window->private->deleted = g_slist_prepend( window->private->deleted, g_object_ref( NA_OBJECT( it->data )));
+	}
+
+	/* the next row must be selected after having updated the deleted list
+	 * so that count_modified will take it into account
+	 */
+	nact_iactions_list_select_row( NACT_IACTIONS_LIST( window ), path );
+	gtk_tree_path_free( path );
+
+	return( deleted );
+}
+
 /**
- * Returns the status bar widget
+ * nact_main_window_get_all_items_count:
+ * @window: this #NactMainWindow instance.
+ *
+ * Returns: the current total count of items in the view.
  */
-GtkStatusbar *
-nact_main_window_get_statusbar( const NactMainWindow *window )
+guint
+nact_main_window_get_all_items_count( const NactMainWindow *window )
 {
-	GtkWidget *statusbar;
+	g_return_val_if_fail( NACT_IS_MAIN_WINDOW( window ), 0 );
+	g_return_val_if_fail( NACT_IS_IACTIONS_LIST( window ), 0 );
 
-	g_assert( NACT_IS_MAIN_WINDOW( window ));
+	return( nact_iactions_list_get_items_count( NACT_IACTIONS_LIST( window )));
+}
+
+/**
+ * nact_main_window_get_modified_items_count:
+ * @window: this #NactMainWindow instance.
+ *
+ * Returns: a count of modified items.
+ *
+ * Note that exact count of modified actions is subject to some
+ * approximation:
+ * 1. counting the modified actions currently in the list is ok
+ * 2. but what about deleted actions ?
+ *    we can create any new actions, deleting them, and so on
+ *    if we have eventually deleted all newly created actions, then the
+ *    final count of modified actions should be zero... don't it ?
+ */
+guint
+nact_main_window_get_modified_items_count( const NactMainWindow *window )
+{
+	static const gchar *thisfn = "nact_main_window_get_modified_items_count";
+	GSList *ia, *modified;
+	gint count_deleted = 0;
+	gint count_modified = 0;
+
+	g_return_val_if_fail( NACT_IS_MAIN_WINDOW( window ), 0 );
+	g_return_val_if_fail( NACT_IS_IACTIONS_LIST( window ), 0 );
+
+	for( ia = window->private->deleted ; ia ; ia = ia->next ){
+		if( na_object_get_origin( NA_OBJECT( ia->data )) != NULL ){
+			count_deleted += 1;
+		}
+	}
+	g_debug( "%s: count_deleted=%d", thisfn, count_deleted );
 
-	statusbar = base_window_get_widget( BASE_WINDOW( window ), "StatusBar" );
+	modified = nact_iactions_list_get_modified_items( NACT_IACTIONS_LIST( window ));
+	count_modified = g_slist_length( modified );
+	nact_iactions_list_free_items_list(NACT_IACTIONS_LIST( window ), modified );
+	g_debug( "%s: count_modified=%d", thisfn, count_modified );
 
-	return( GTK_STATUSBAR( statusbar ));
+	return( count_deleted + count_modified );
 }
 
-static gchar *
-get_iprefs_window_id( NactWindow *window )
+/**
+ * nact_main_window_remove_deleted:
+ *
+ * Removes the deleted items from the underlying I/O storage subsystem.
+ */
+void
+nact_main_window_remove_deleted( NactMainWindow *window )
 {
-	return( g_strdup( "main-window" ));
+	NactApplication *application;
+	NAPivot *pivot;
+	GSList *it;
+	NAObject *item;
+
+	application = NACT_APPLICATION( base_window_get_application( BASE_WINDOW( window )));
+	pivot = nact_application_get_pivot( application );
+
+	for( it = window->private->deleted ; it ; it = it->next ){
+		item = NA_OBJECT( it->data );
+		actually_delete_item( window, item, pivot );
+	}
+
+	window->private->deleted = na_pivot_free_items_tree( window->private->deleted );
+}
+
+/**
+ * nact_main_window_remove_deleted:
+ *
+ * Removes the deleted items from the underlying I/O storage subsystem.
+ */
+static void
+actually_delete_item( NactMainWindow *window, NAObject *item, NAPivot *pivot )
+{
+	GSList *items, *it;
+
+	if( nact_window_delete_object_item( NACT_WINDOW( window ), NA_OBJECT_ITEM( item ))){
+
+		NAObject *origin = na_object_get_origin( item );
+		if( origin ){
+			na_pivot_remove_item( pivot, origin );
+		}
+
+		if( NA_IS_OBJECT_MENU( item )){
+			items = na_object_get_items( item );
+			for( it = items ; it ; it = it->next ){
+				actually_delete_item( window, NA_OBJECT( it->data ), pivot );
+			}
+			na_object_free_items( items );
+		}
+	}
 }
 
 static gchar *
-get_toplevel_name( BaseWindow *window )
+base_get_toplevel_name( BaseWindow *window )
 {
 	return( g_strdup( "MainWindow" ));
 }
 
-static GSList *
-get_actions( NactWindow *window )
+static gchar *
+base_get_iprefs_window_id( BaseWindow *window )
 {
-	g_assert( NACT_IS_MAIN_WINDOW( window ));
-	return( NACT_MAIN_WINDOW( window )->private->actions );
+	return( g_strdup( "main-window" ));
 }
 
 /*
@@ -517,481 +705,208 @@ get_actions( NactWindow *window )
  * is the same than quitting the application
  */
 static void
-on_initial_load_toplevel( BaseWindow *window )
+on_base_initial_load_toplevel( NactMainWindow *window, gpointer user_data )
 {
-	static const gchar *thisfn = "nact_main_window_on_initial_load_toplevel";
-	NactMainWindow *wnd;
+	static const gchar *thisfn = "nact_main_window_on_base_initial_load_toplevel";
 	gint pos;
 	GtkWidget *pane;
-	/*gboolean alpha_order;*/
-
-	/* call parent class at the very beginning */
-	if( BASE_WINDOW_CLASS( st_parent_class )->initial_load_toplevel ){
-		BASE_WINDOW_CLASS( st_parent_class )->initial_load_toplevel( window );
-	}
 
-	g_debug( "%s: window=%p", thisfn, ( void * ) window );
+	g_debug( "%s: window=%p, user_data=%p", thisfn, ( void * ) window, ( void * ) user_data );
 	g_assert( NACT_IS_MAIN_WINDOW( window ));
-	wnd = NACT_MAIN_WINDOW( window );
-
-	nact_imenubar_init( wnd );
 
-	g_assert( NACT_IS_IACTIONS_LIST( window ));
-	nact_iactions_list_initial_load( NACT_WINDOW( window ));
-	nact_iactions_list_set_edition_mode( NACT_WINDOW( window ), TRUE );
-	nact_iactions_list_set_send_selection_changed_on_fill_list( NACT_WINDOW( window ), FALSE );
-	nact_iactions_list_set_multiple_selection( NACT_WINDOW( window ), TRUE );
-
-	/*alpha_order = na_iprefs_get_alphabetical_order( NA_IPREFS( window ));
-	nact_iactions_list_set_multiple_selection( NACT_WINDOW( window ), !alpha_order );
-	nact_iactions_list_set_dnd_mode( NACT_WINDOW( window ), !alpha_order );*/
-
-	g_assert( NACT_IS_IACTION_TAB( window ));
-	nact_iaction_tab_initial_load( NACT_WINDOW( window ));
-
-	g_assert( NACT_IS_ICOMMAND_TAB( window ));
-	nact_icommand_tab_initial_load( NACT_WINDOW( window ));
-
-	g_assert( NACT_IS_ICONDITIONS_TAB( window ));
-	nact_iconditions_tab_initial_load( NACT_WINDOW( window ));
-
-	g_assert( NACT_IS_IADVANCED_TAB( window ));
-	nact_iadvanced_tab_initial_load( NACT_WINDOW( window ));
-
-	pos = nact_iprefs_get_int( NACT_WINDOW( window ), "main-paned" );
+	pos = base_iprefs_get_int( BASE_WINDOW( window ), "main-paned" );
 	if( pos ){
-		pane = base_window_get_widget( window, "MainPaned" );
+		pane = base_window_get_widget( BASE_WINDOW( window ), "MainPaned" );
 		gtk_paned_set_position( GTK_PANED( pane ), pos );
 	}
+
+	nact_iactions_list_initial_load_toplevel( NACT_IACTIONS_LIST( window ));
+	nact_iactions_list_set_multiple_selection_mode( NACT_IACTIONS_LIST( window ), TRUE );
+	nact_iactions_list_set_dnd_mode( NACT_IACTIONS_LIST( window ), TRUE );
+
+	nact_iaction_tab_initial_load_toplevel( NACT_IACTION_TAB( window ));
+	nact_icommand_tab_initial_load_toplevel( NACT_ICOMMAND_TAB( window ));
+	nact_iconditions_tab_initial_load_toplevel( NACT_ICONDITIONS_TAB( window ));
+	nact_iadvanced_tab_initial_load_toplevel( NACT_IADVANCED_TAB( window ));
 }
 
 static void
-on_runtime_init_toplevel( BaseWindow *window )
+on_base_runtime_init_toplevel( NactMainWindow *window, gpointer user_data )
 {
-	static const gchar *thisfn = "nact_main_window_on_runtime_init_toplevel";
-	NactMainWindow *wnd;
+	static const gchar *thisfn = "nact_main_window_on_base_runtime_init_toplevel";
 	NactApplication *application;
 	NAPivot *pivot;
-	GSList *ia;
-
-	/* call parent class at the very beginning */
-	if( BASE_WINDOW_CLASS( st_parent_class )->runtime_init_toplevel ){
-		BASE_WINDOW_CLASS( st_parent_class )->runtime_init_toplevel( window );
-	}
+	GSList *tree;
 
+	g_debug( "%s: window=%p, user_data=%p", thisfn, ( void * ) window, ( void * ) user_data );
 	g_assert( NACT_IS_MAIN_WINDOW( window ));
-	g_debug( "%s: window=%p", thisfn, ( void * ) window );
-	wnd = NACT_MAIN_WINDOW( window );
 
-	application = NACT_APPLICATION( base_window_get_application( BASE_WINDOW( wnd )));
+	application = NACT_APPLICATION( base_window_get_application( BASE_WINDOW( window )));
 	pivot = nact_application_get_pivot( application );
-	na_pivot_set_automatic_reload( pivot, FALSE );
-	wnd->private->actions = na_pivot_get_duplicate_actions( pivot );
-	wnd->private->initial_count = g_slist_length( wnd->private->actions );
-
-	/* initialize the current edition status as a loaded action may be
-	 * invalid (without having been modified)
-	 */
-	for( ia = wnd->private->actions ; ia ; ia = ia->next ){
-		na_object_check_edited_status( NA_OBJECT( ia->data ));
-	}
-
-	g_assert( NACT_IS_IACTIONS_LIST( window ));
-	nact_iactions_list_runtime_init( NACT_WINDOW( window ));
-
-	g_assert( NACT_IS_IACTION_TAB( window ));
-	nact_iaction_tab_runtime_init( NACT_WINDOW( window ));
+	tree = na_pivot_get_items_tree( pivot );
+	g_debug( "%s: pivot_tree=%p", thisfn, ( void * ) tree );
 
-	g_assert( NACT_IS_ICOMMAND_TAB( window ));
-	nact_icommand_tab_runtime_init( NACT_WINDOW( window ));
+	nact_iaction_tab_runtime_init_toplevel( NACT_IACTION_TAB( window ));
+	nact_icommand_tab_runtime_init_toplevel( NACT_ICOMMAND_TAB( window ));
+	nact_iconditions_tab_runtime_init_toplevel( NACT_ICONDITIONS_TAB( window ));
+	nact_iadvanced_tab_runtime_init_toplevel( NACT_IADVANCED_TAB( window ));
 
-	g_assert( NACT_IS_ICONDITIONS_TAB( window ));
-	nact_iconditions_tab_runtime_init( NACT_WINDOW( window ));
-
-	g_assert( NACT_IS_IADVANCED_TAB( window ));
-	nact_iadvanced_tab_runtime_init( NACT_WINDOW( window ));
+	/* fill the IActionsList at last so that all signals are connected
+	 */
+	nact_iactions_list_runtime_init_toplevel( NACT_IACTIONS_LIST( window ), tree );
+	nact_main_menubar_runtime_init( window );
 
 	/* forces a no-selection when the list is initially empty
 	 */
-	if( !wnd->private->initial_count ){
+	/*if( !g_slist_length( wnd->private->actions )){
 		set_current_action( NACT_MAIN_WINDOW( window ), NULL );
-	} else {
-		nact_iactions_list_select_first( NACT_WINDOW( window ));
-	}
+	}*/
 }
 
 static void
-setup_dialog_title( NactWindow *window )
+on_base_all_widgets_showed( NactMainWindow *window, gpointer user_data )
 {
-	GtkWindow *toplevel;
-	BaseApplication *appli = BASE_APPLICATION( base_window_get_application( BASE_WINDOW( window )));
-	gchar *title = base_application_get_application_name( appli );
-
-	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;
-	}
+	static const gchar *thisfn = "nact_main_window_on_base_all_widgets_showed";
 
-	if( count_modified_actions( window )){
-		gchar *tmp = g_strdup_printf( "*%s", title );
-		g_free( title );
-		title = tmp;
-	}
+	g_debug( "%s: window=%p, user_data=%p", thisfn, ( void * ) window, ( void * ) user_data );
+	g_return_if_fail( NACT_IS_MAIN_WINDOW( window ));
+	g_return_if_fail( NACT_IS_IACTIONS_LIST( window ));
+	g_return_if_fail( NACT_IS_IACTION_TAB( window ));
+	g_return_if_fail( NACT_IS_ICOMMAND_TAB( window ));
+	g_return_if_fail( NACT_IS_ICONDITIONS_TAB( window ));
+	g_return_if_fail( NACT_IS_IADVANCED_TAB( window ));
 
-	toplevel = base_window_get_toplevel_dialog( BASE_WINDOW( window ));
-	gtk_window_set_title( toplevel, title );
+	nact_iactions_list_all_widgets_showed( NACT_IACTIONS_LIST( window ));
+	nact_iaction_tab_all_widgets_showed( NACT_IACTION_TAB( window ));
+	nact_icommand_tab_all_widgets_showed( NACT_ICOMMAND_TAB( window ));
+	nact_iconditions_tab_all_widgets_showed( NACT_ICONDITIONS_TAB( window ));
+	nact_iadvanced_tab_all_widgets_showed( NACT_IADVANCED_TAB( window ));
 
-	g_free( title );
+	nact_main_menubar_refresh_actions_sensitivity( window );
 }
 
+/*
+ * iactions_list_selection_changed:
+ * @window: this #NactMainWindow instance.
+ * @selected_items: the currently selected items in ActionsList
+ */
 static void
-on_actions_list_selection_changed( NactIActionsList *instance, GSList *selected_items )
+iactions_list_selection_changed( NactIActionsList *instance, GSList *selected_items )
 {
-	static const gchar *thisfn = "nact_main_window_on_actions_list_selection_changed";
+	static const gchar *thisfn = "nact_main_window_list_actions_selection_changed";
 	NactMainWindow *window;
 	NAObject *object;
 	gint count;
 
-	g_debug( "%s: instance=%p, selected_items=%p", thisfn, ( void * ) instance, ( void * ) selected_items );
+	count = g_slist_length( selected_items );
 
-	g_assert( NACT_IS_MAIN_WINDOW( instance ));
-	window = NACT_MAIN_WINDOW( instance );
+	g_debug( "%s: instance=%p, selected_items=%p, count=%d",
+			thisfn, ( void * ) instance, ( void * ) selected_items, count );
 
-	count = g_slist_length( selected_items );
+	window = NACT_MAIN_WINDOW( instance );
 
 	if( count == 1 ){
 		object = NA_OBJECT( selected_items->data );
-		if( NA_IS_ACTION( object )){
-			window->private->edited_action = NA_ACTION( object );
-			set_current_action( window, selected_items );
+		if( NA_IS_OBJECT_ITEM( object )){
+			window->private->edited_item = NA_OBJECT_ITEM( object );
+			set_current_object_item( window, selected_items );
 
 		} else {
-			g_assert( NA_IS_ACTION_PROFILE( object ));
-			window->private->edited_profile = NA_ACTION_PROFILE( object );
+			g_assert( NA_IS_OBJECT_PROFILE( object ));
+			window->private->edited_profile = NA_OBJECT_PROFILE( object );
 			set_current_profile( window, TRUE, selected_items );
 		}
 
 	} else {
-		window->private->edited_action = NULL;
-		set_current_action( window, selected_items );
+		window->private->edited_item = NULL;
+		set_current_object_item( window, selected_items );
 	}
-}
-
-static gboolean
-on_actions_list_double_click( GtkWidget *widget, GdkEventButton *event, gpointer user_data )
-{
-	g_assert( event->type == GDK_2BUTTON_PRESS );
 
-	nact_iactions_list_toggle_collapse(
-			NACT_WINDOW( user_data ), NACT_MAIN_WINDOW( user_data )->private->edited_action );
+	g_object_set(
+			G_OBJECT( window ),
+			TAB_UPDATABLE_PROP_EDITED_ACTION, window->private->edited_item,
+			/*TAB_UPDATABLE_PROP_EDITION_ACTION_ENABLED, window->private->edition_enabled,*/
+			TAB_UPDATABLE_PROP_EDITED_PROFILE, window->private->edited_profile,
+			NULL );
 
-	return( TRUE );
-}
-
-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_MAIN_WINDOW( user_data )->private->edited_action );
-
-	return( TRUE );
+	g_signal_emit_by_name( window, TAB_UPDATABLE_SIGNAL_SELECTION_UPDATED, GINT_TO_POINTER( count ));
 }
 
 /*
- * update the notebook when selection changes in IActionsList
+ * update the notebook when selection changes in ActionsList
  * if there is only one profile, we also setup the profile
  */
 static void
-set_current_action( NactMainWindow *window, GSList *selected_items )
+set_current_object_item( NactMainWindow *window, GSList *selected_items )
 {
-	static const gchar *thisfn = "nact_main_window_set_current_action";
+	static const gchar *thisfn = "nact_main_window_set_current_object_item";
+	gint count_profiles;
+	GSList *profiles;
+	/*NAObject *current;*/
 
 	g_debug( "%s: window=%p, current=%p, selected_items=%p",
-			thisfn, ( void * ) window, ( void * ) window->private->edited_action, ( void * ) selected_items );
-
-	nact_iaction_tab_set_action( NACT_WINDOW( window ), window->private->edited_action, selected_items );
+			thisfn, ( void * ) window, ( void * ) window->private->edited_item, ( void * ) selected_items );
 
+	/* set the profile to be displayed, if any
+	 */
 	window->private->edited_profile = NULL;
 
-	if( window->private->edited_action ){
-		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 );
-		}
-	}
-
-	set_current_profile( window, FALSE, selected_items );
-}
-
-static void
-set_current_profile( NactMainWindow *window, gboolean set_action, GSList *selected_items )
-{
-	static const gchar *thisfn = "nact_main_window_set_current_profile";
+	if( window->private->edited_item &&
+		NA_IS_OBJECT_ACTION( window->private->edited_item )){
 
-	g_debug( "%s: window=%p, set_action=%s, selected_items=%p",
-			thisfn, ( void * ) window, set_action ? "True":"False", ( void * ) selected_items );
+			count_profiles = na_object_get_items_count( NA_OBJECT_ACTION( window->private->edited_item ));
+			g_return_if_fail( count_profiles >= 1 );
 
-	if( window->private->edited_profile && set_action ){
-		NAAction *action = NA_ACTION( na_action_profile_get_action( window->private->edited_profile ));
-		window->private->edited_action = action;
-		nact_iaction_tab_set_action( NACT_WINDOW( window ), window->private->edited_action, selected_items );
+			if( count_profiles == 1 ){
+				profiles = na_object_get_items( window->private->edited_item );
+				window->private->edited_profile = NA_OBJECT_PROFILE( profiles->data );
+				na_object_free_items( profiles );
+			}
 	}
 
-	nact_icommand_tab_set_profile( NACT_WINDOW( window ), window->private->edited_profile );
-	nact_iconditions_tab_set_profile( NACT_WINDOW( window ), window->private->edited_profile );
-	nact_iadvanced_tab_set_profile( NACT_WINDOW( window ), window->private->edited_profile );
-}
-
-/*
- * update the currently edited NAAction when a field is modified
- * (called as a virtual function by each interface tab)
- */
-static NAAction *
-get_edited_action( NactWindow *window )
-{
-	g_assert( NACT_IS_MAIN_WINDOW( window ));
-	return( NACT_MAIN_WINDOW( window )->private->edited_action );
-}
-
-static NAActionProfile *
-get_edited_profile( NactWindow *window )
-{
-	g_assert( NACT_IS_MAIN_WINDOW( window ));
-	return( NACT_MAIN_WINDOW( window )->private->edited_profile );
-}
-
-/*
- * called as a virtual function by each interface tab when a field
- * has been modified
- * - if the label has been modified, the IActionsList must reflect this
- * - setup dialog title
- */
-static void
-on_modified_field( NactWindow *window )
-{
-	g_assert( NACT_IS_MAIN_WINDOW( window ));
-
-	na_object_check_edited_status( NA_OBJECT( NACT_MAIN_WINDOW( window )->private->edited_action ));
-
-	setup_dialog_title( window );
-
-	nact_iactions_list_update_selected( window, NACT_MAIN_WINDOW( window )->private->edited_action );
-}
-
-static gboolean
-is_modified_action( NactWindow *window, const NAAction *action )
-{
-	return( na_object_get_modified_status( NA_OBJECT( action )));
-}
-
-static gboolean
-is_valid_action( NactWindow *window, const NAAction *action )
-{
-	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
-get_isfiledir( NactWindow *window, gboolean *isfile, gboolean *isdir )
-{
-	nact_iconditions_tab_get_isfiledir( window, isfile, isdir );
-}
-
-static gboolean
-get_multiple( NactWindow *window )
-{
-	return( nact_iconditions_tab_get_multiple( window ));
-}
-
-static GSList *
-get_schemes( NactWindow *window )
-{
-	return( nact_iadvanced_tab_get_schemes( window ));
-}
-
-/*
- * insert an item (action or menu) in the list:
- * - the last position if the list is sorted, and sort it
- * - at the current position if the list is not sorted
- *
- * set the selection on the new item
- */
-static void
-insert_item( NactWindow *window, NAAction *item )
-{
-	NactMainWindow *wnd = NACT_MAIN_WINDOW( window );
-	gboolean alpha_order;
-	gchar *uuid;
-	NAAction *current;
-	gint index;
-
-	alpha_order = na_iprefs_get_alphabetical_order( NA_IPREFS( window ));
-	if( alpha_order ){
-		wnd->private->actions = g_slist_prepend( wnd->private->actions, ( gpointer ) item );
-		sort_actions_list( wnd );
+	/* do the profile tabs (ICommandTab, IConditionsTab and IAdvancedTab)
+	 * will be editable ?
+	 * yes if we have an action with only one profile, or the selected
+	 * item is itself a profile
+	 */
+	/*window->private->edition_enabled = ( window->private->edited_item != NULL );
 
-	} else {
-		current = get_edited_action( window );
-		if( current ){
-			index = g_slist_index( wnd->private->actions, current );
-			g_assert( index >= 0 );
-			wnd->private->actions = g_slist_insert( wnd->private->actions, item, index );
-		} else {
-			g_assert( g_slist_length( wnd->private->actions ) == 0 );
-			wnd->private->actions = g_slist_prepend( wnd->private->actions, ( gpointer ) item );
+	if( window->private->edition_enabled ){
+		g_assert( selected_items );
+		if( g_slist_length( selected_items ) > 1 ){
+			window->private->edition_enabled = FALSE;
 		}
 	}
 
-	nact_iactions_list_fill( window, TRUE );
-
-	uuid = na_action_get_uuid( item );
-	nact_iactions_list_set_selection( window, NA_ACTION_TYPE, uuid, NULL );
-	g_free( uuid );
-}
-
-static void
-add_profile( NactWindow *window, NAActionProfile *profile )
-{
-	NAAction *action = na_action_profile_get_action( profile );
-
-	if( !nact_iactions_list_is_expanded( window, action )){
-		nact_iactions_list_toggle_collapse( window, action );
-	}
-}
-
-static void
-remove_action( NactWindow *window, NAAction *action )
-{
-	NactMainWindow *wnd = NACT_MAIN_WINDOW( window );
-	wnd->private->actions = g_slist_remove( wnd->private->actions, ( gconstpointer ) action );
-}
-
-static GSList *
-get_deleted_actions( NactWindow *window )
-{
-	return( NACT_MAIN_WINDOW( window )->private->deleted );
-}
-
-static void
-free_deleted_actions( NactWindow *window )
-{
-	NactMainWindow *self = NACT_MAIN_WINDOW( window );
-
-	self->private->deleted = free_actions( self->private->deleted );
-}
-
-static void
-push_removed_action( NactWindow *window, NAAction *action )
-{
-	NactMainWindow *wnd = NACT_MAIN_WINDOW( window );
-	wnd->private->deleted = g_slist_append( wnd->private->deleted, ( gpointer ) action );
-}
-
-static void
-update_actions_list( NactWindow *window )
-{
-	nact_iactions_list_fill( window, TRUE );
-}
-
-static gboolean
-on_delete_event( BaseWindow *window, GtkWindow *toplevel, GdkEvent *event )
-{
-	static const gchar *thisfn = "nact_main_window_on_delete_event";
-
-	g_debug( "%s: window=%p, toplevel=%p, event=%p",
-			thisfn, ( void * ) window, ( void * ) toplevel, ( void * ) event );
-	g_assert( NACT_IS_MAIN_WINDOW( window ));
-
-	nact_imenubar_on_delete_event( NACT_WINDOW( window ));
-
-	return( TRUE );
-}
-
-static gint
-count_actions( NactWindow *window )
-{
-	return( g_slist_length( NACT_MAIN_WINDOW( window )->private->actions ));
-}
-
-/*
- * exact count of modified actions is subject to some approximation
- * 1. counting the actions currently in the list is ok
- * 2. what about deleted actions ?
- *    we can create any new actions, deleting them, and so on
- *    if we have eventually deleted all newly created actions, then the
- *    final count of modified actions should be zero... don't it ?
- */
-static gint
-count_modified_actions( NactWindow *window )
-{
-	GSList *ia;
-	gint count = 0;
-
-	if( g_slist_length( NACT_MAIN_WINDOW( window )->private->actions ) == 0 &&
-		NACT_MAIN_WINDOW( window )->private->initial_count == 0 ){
-			return( 0 );
+	if( window->private->edition_enabled && NA_IS_OBJECT_MENU( window->private->edited_item )){
+		window->private->edition_enabled = FALSE;
 	}
 
-	for( ia = NACT_MAIN_WINDOW( window )->private->deleted ; ia ; ia = ia->next ){
-		if( na_object_get_origin( NA_OBJECT( ia->data )) != NULL ){
-			count += 1;
+	if( window->private->edition_enabled ){
+		g_assert( NA_IS_ACTION( window->private->edited_item ));
+		current = NA_OBJECT( selected_items->data );
+		if( NA_IS_OBJECT_ACTION( current)){
+			if( na_object_action_get_profiles_count( NA_ACTION( window->private->edited_item )) > 1 ){
+				window->private->edition_enabled = FALSE;
+			}
 		}
-	}
-
-	for( ia = NACT_MAIN_WINDOW( window )->private->actions ; ia ; ia = ia->next ){
-		if( is_modified_action( window, NA_ACTION( ia->data ))){
-			count += 1;
-		}
-	}
+	}*/
 
-	return( count );
+	set_current_profile( window, FALSE, selected_items );
 }
 
 static void
-reload_actions( NactWindow *window )
+set_current_profile( NactMainWindow *window, gboolean set_action, GSList *selected_items )
 {
-	NactMainWindow *self = NACT_MAIN_WINDOW( window );
-	NactApplication *application;
-	NAPivot *pivot;
-
-	self->private->actions = free_actions( self->private->actions );
-	self->private->deleted = free_actions( self->private->deleted );
-
-	application = NACT_APPLICATION( base_window_get_application( BASE_WINDOW( window )));
-	pivot = nact_application_get_pivot( application );
-	na_pivot_reload_actions( pivot );
-	self->private->actions = na_pivot_get_duplicate_actions( pivot );
-	self->private->initial_count = g_slist_length( self->private->actions );
-
-	nact_iactions_list_fill( window, FALSE );
+	static const gchar *thisfn = "nact_main_window_set_current_profile";
 
-	if( self->private->initial_count ){
-		nact_iactions_list_select_first( window );
-	}
-}
+	g_debug( "%s: window=%p, set_action=%s, selected_items=%p",
+			thisfn, ( void * ) window, set_action ? "True":"False", ( void * ) selected_items );
 
-static GSList *
-free_actions( GSList *actions )
-{
-	GSList *ia;
-	for( ia = actions ; ia ; ia = ia->next ){
-		g_object_unref( NA_ACTION( ia->data ));
+	if( window->private->edited_profile && set_action ){
+		NAObjectAction *action = NA_OBJECT_ACTION( na_object_profile_get_action( window->private->edited_profile ));
+		window->private->edited_item = NA_OBJECT_ITEM( action );
 	}
-	g_slist_free( actions );
-	return( NULL );
 }
 
 /*
@@ -1004,10 +919,9 @@ free_actions( GSList *actions )
  * reset - saving is handled on a per-action basis.
  */
 static void
-on_actions_changed( NAIPivotConsumer *instance, gpointer user_data )
+ipivot_consumer_on_actions_changed( NAIPivotConsumer *instance, gpointer user_data )
 {
-	static const gchar *thisfn = "nact_main_window_on_actions_changed";
-	NactMainWindow *self;
+	static const gchar *thisfn = "nact_main_window_ipivot_consumer_on_actions_changed";
 	NactApplication *application;
 	NAPivot *pivot;
 	gchar *first, *second;
@@ -1015,7 +929,6 @@ on_actions_changed( NAIPivotConsumer *instance, gpointer user_data )
 
 	g_debug( "%s: instance=%p, user_data=%p", thisfn, ( void * ) instance, ( void * ) user_data );
 	g_assert( NACT_IS_MAIN_WINDOW( instance ));
-	self = NACT_MAIN_WINDOW( instance );
 
 	application = NACT_APPLICATION( base_window_get_application( BASE_WINDOW( instance )));
 	pivot = nact_application_get_pivot( application );
@@ -1024,7 +937,7 @@ on_actions_changed( NAIPivotConsumer *instance, gpointer user_data )
 								"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 ){
+	if( nact_main_window_get_modified_items_count( NACT_MAIN_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." ));
@@ -1041,13 +954,13 @@ on_actions_changed( NAIPivotConsumer *instance, gpointer user_data )
 
 	if( ok ){
 
-		na_pivot_reload_actions( pivot );
+		na_pivot_reload_items_tree( pivot );
 
-		na_pivot_free_actions( self->private->actions );
+		/*na_pivot_free_actions( self->private->actions );
 
 		self->private->actions = na_pivot_get_duplicate_actions( pivot );
 
-		nact_iactions_list_fill( NACT_WINDOW( instance ), TRUE );
+		nact_iactions_list_fill( NACT_IACTIONS_LIST( instance ), na_pivot_get_actions( pivot ));*/
 	}
 }
 
@@ -1056,29 +969,12 @@ on_actions_changed( NAIPivotConsumer *instance, gpointer user_data )
  * "sort in alphabetical order" preference is modified.
  */
 static void
-on_display_order_changed( NAIPivotConsumer *instance, gpointer user_data )
+ipivot_consumer_on_display_order_changed( NAIPivotConsumer *instance, gpointer user_data )
 {
-	static const gchar *thisfn = "nact_main_window_on_display_order_changed";
+	static const gchar *thisfn = "nact_main_window_ipivot_consumer_on_display_order_changed";
 	/*NactMainWindow *self;*/
-	gboolean alpha_order;
 
 	g_debug( "%s: instance=%p, user_data=%p", thisfn, ( void * ) instance, ( void * ) user_data );
 	g_assert( NACT_IS_MAIN_WINDOW( instance ));
 	/*self = NACT_MAIN_WINDOW( instance );*/
-
-	alpha_order = na_iprefs_get_alphabetical_order( NA_IPREFS( instance ));
-
-	nact_iactions_list_set_multiple_selection( NACT_WINDOW( instance ), !alpha_order );
-	nact_iactions_list_set_dnd_mode( NACT_WINDOW( instance ), !alpha_order );
-}
-
-static void
-sort_actions_list( NactMainWindow *window )
-{
-	NactApplication *application;
-	NAPivot *pivot;
-
-	application = NACT_APPLICATION( base_window_get_application( BASE_WINDOW( window )));
-	pivot = nact_application_get_pivot( application );
-	window->private->actions = na_iio_provider_sort_actions( pivot, window->private->actions );
 }
diff --git a/src/nact/nact-main-window.h b/src/nact/nact-main-window.h
index 308db6e..ca4ee1d 100644
--- a/src/nact/nact-main-window.h
+++ b/src/nact/nact-main-window.h
@@ -34,7 +34,7 @@
 /*
  * NactMainWindow class definition.
  *
- * This class is derived from BaseWindow and manages the MainWindow.
+ * This class is derived from BaseWindow and manages the main window.
  */
 
 #include "nact-window.h"
@@ -68,18 +68,11 @@ GType           nact_main_window_get_type( void );
 
 NactMainWindow *nact_main_window_new( BaseApplication *application );
 
-GSList         *nact_main_window_get_actions( const NactMainWindow *window );
 gboolean        nact_main_window_action_exists( const NactMainWindow *window, const gchar *uuid );
-GtkStatusbar   *nact_main_window_get_statusbar( const NactMainWindow *window );
-
-GtkStatusbar   *nact_main_window_get_statusbar( const NactMainWindow *window );
-
-enum {
-	ACTION_TAB = 0,
-	COMMAND_TAB,
-	CONDITIONS_TAB,
-	ADVANCED_TAB
-};
+GSList         *nact_main_window_delete_selection( NactMainWindow *window );
+guint           nact_main_window_get_all_items_count( const NactMainWindow *window );
+guint           nact_main_window_get_modified_items_count( const NactMainWindow *window );
+void            nact_main_window_remove_deleted( NactMainWindow *window );
 
 G_END_DECLS
 
diff --git a/src/nact/nact-preferences-editor.c b/src/nact/nact-preferences-editor.c
index 0a1ca58..f7b9803 100644
--- a/src/nact/nact-preferences-editor.c
+++ b/src/nact/nact-preferences-editor.c
@@ -36,8 +36,8 @@
 
 #include <common/na-iprefs.h>
 
+#include "base-iprefs.h"
 #include "nact-application.h"
-#include "nact-iprefs.h"
 #include "nact-preferences-editor.h"
 
 /* private class data
@@ -50,7 +50,7 @@ struct NactPreferencesEditorClassPrivate {
  */
 struct NactPreferencesEditorPrivate {
 	gboolean         dispose_has_run;
-	NactWindow      *parent;
+	BaseWindow      *parent;
 };
 
 static GObjectClass *st_parent_class = NULL;
@@ -62,21 +62,21 @@ static void     instance_init( GTypeInstance *instance, gpointer klass );
 static void     instance_dispose( GObject *dialog );
 static void     instance_finalize( GObject *dialog );
 
-static NactPreferencesEditor *preferences_editor_new( BaseApplication *application );
+static NactPreferencesEditor *preferences_editor_new( NactApplication *application );
 
-static gchar   *do_get_iprefs_window_id( NactWindow *window );
-static gchar   *do_get_dialog_name( BaseWindow *dialog );
-static void     on_initial_load_dialog( BaseWindow *dialog );
-static void     on_runtime_init_dialog( BaseWindow *dialog );
-static void     on_all_widgets_showed( BaseWindow *dialog );
+static gchar   *base_get_iprefs_window_id( BaseWindow *window );
+static gchar   *base_get_dialog_name( BaseWindow *window );
+static void     on_base_initial_load_dialog( NactPreferencesEditor *editor, gpointer user_data );
+static void     on_base_runtime_init_dialog( NactPreferencesEditor *editor, gpointer user_data );
 /*static void     setup_buttons( NactPreferencesEditor *dialog, gboolean is_modified );
 static void     on_modified_field( NactWindow *dialog );*/
-static void     on_sort_alpha_toggled( GtkToggleButton *button, NactWindow *window );
-static void     on_add_about_toggled( GtkToggleButton *button, NactWindow *window );
-static void     on_cancel_clicked( GtkButton *button, NactWindow *window );
-static void     on_ok_clicked( GtkButton *button, NactWindow *window );
+static void     on_sort_alpha_toggled( GtkToggleButton *button, NactPreferencesEditor *editor );
+static void     on_add_about_toggled( GtkToggleButton *button, NactPreferencesEditor *editor );
+static void     on_cancel_clicked( GtkButton *button, NactPreferencesEditor *editor );
+static void     on_ok_clicked( GtkButton *button, NactPreferencesEditor *editor );
 static void     save_preferences( NactPreferencesEditor *editor );
-static gboolean on_dialog_response( GtkDialog *dialog, gint code, BaseWindow *window );
+
+static gboolean base_dialog_response( GtkDialog *dialog, gint code, BaseWindow *window );
 
 GType
 nact_preferences_editor_get_type( void )
@@ -116,7 +116,7 @@ register_type( void )
 
 	g_debug( "%s", thisfn );
 
-	type = g_type_register_static( NACT_WINDOW_TYPE, "NactPreferencesEditor", &info, 0 );
+	type = g_type_register_static( BASE_DIALOG_TYPE, "NactPreferencesEditor", &info, 0 );
 
 	g_type_add_interface_static( type, NA_IPREFS_TYPE, &prefs_iface_info );
 
@@ -129,7 +129,6 @@ class_init( NactPreferencesEditorClass *klass )
 	static const gchar *thisfn = "nact_preferences_editor_class_init";
 	GObjectClass *object_class;
 	BaseWindowClass *base_class;
-	NactWindowClass *nact_class;
 
 	g_debug( "%s: klass=%p", thisfn, ( void * ) klass );
 
@@ -142,14 +141,9 @@ class_init( NactPreferencesEditorClass *klass )
 	klass->private = g_new0( NactPreferencesEditorClassPrivate, 1 );
 
 	base_class = BASE_WINDOW_CLASS( klass );
-	base_class->initial_load_toplevel = on_initial_load_dialog;
-	base_class->runtime_init_toplevel = on_runtime_init_dialog;
-	base_class->all_widgets_showed = on_all_widgets_showed;
-	base_class->dialog_response = on_dialog_response;
-	base_class->get_toplevel_name = do_get_dialog_name;
-
-	nact_class = NACT_WINDOW_CLASS( klass );
-	nact_class->get_iprefs_window_id = do_get_iprefs_window_id;
+	base_class->dialog_response = base_dialog_response;
+	base_class->get_toplevel_name = base_get_dialog_name;
+	base_class->get_iprefs_window_id = base_get_iprefs_window_id;
 }
 
 static void
@@ -173,6 +167,18 @@ instance_init( GTypeInstance *instance, gpointer klass )
 
 	self->private = g_new0( NactPreferencesEditorPrivate, 1 );
 
+	base_window_signal_connect(
+			BASE_WINDOW( instance ),
+			G_OBJECT( instance ),
+			BASE_WINDOW_SIGNAL_INITIAL_LOAD,
+			G_CALLBACK( on_base_initial_load_dialog ));
+
+	base_window_signal_connect(
+			BASE_WINDOW( instance ),
+			G_OBJECT( instance ),
+			BASE_WINDOW_SIGNAL_RUNTIME_INIT,
+			G_CALLBACK( on_base_runtime_init_dialog ));
+
 	self->private->dispose_has_run = FALSE;
 }
 
@@ -222,28 +228,29 @@ instance_finalize( GObject *dialog )
  * toplevel window of the application).
  */
 static NactPreferencesEditor *
-preferences_editor_new( BaseApplication *application )
+preferences_editor_new( NactApplication *application )
 {
-	return( g_object_new( NACT_PREFERENCES_EDITOR_TYPE, PROP_WINDOW_APPLICATION_STR, application, NULL ));
+	return( g_object_new( NACT_PREFERENCES_EDITOR_TYPE, BASE_WINDOW_PROP_APPLICATION, application, NULL ));
 }
 
 /**
- * Initializes and runs the dialog.
+ * nact_preferences_editor_run:
+ * @parent: the BaseWindow parent of this dialog
+ * (usually the NactMainWindow).
  *
- * @parent: the NactWindow parent of this dialog.
- * Usually the NactMainWindow.
+ * Initializes and runs the dialog.
  */
 void
-nact_preferences_editor_run( NactWindow *parent )
+nact_preferences_editor_run( BaseWindow *parent )
 {
 	static const gchar *thisfn = "nact_preferences_editor_run";
-	BaseApplication *application;
+	NactApplication *application;
 	NactPreferencesEditor *editor;
 
 	g_debug( "%s: parent=%p", thisfn, ( void * ) parent );
-	g_assert( NACT_IS_WINDOW( parent ));
+	g_assert( BASE_IS_WINDOW( parent ));
 
-	application = BASE_APPLICATION( base_window_get_application( BASE_WINDOW( parent )));
+	application = NACT_APPLICATION( base_window_get_application( parent ));
 	g_assert( NACT_IS_APPLICATION( application ));
 
 	editor = preferences_editor_new( application );
@@ -253,86 +260,73 @@ nact_preferences_editor_run( NactWindow *parent )
 }
 
 static gchar *
-do_get_iprefs_window_id( NactWindow *window )
+base_get_iprefs_window_id( BaseWindow *window )
 {
 	return( g_strdup( "preferences-editor" ));
 }
 
 static gchar *
-do_get_dialog_name( BaseWindow *dialog )
+base_get_dialog_name( BaseWindow *window )
 {
 	return( g_strdup( "PreferencesDialog" ));
 }
 
 static void
-on_initial_load_dialog( BaseWindow *dialog )
+on_base_initial_load_dialog( NactPreferencesEditor *editor, gpointer user_data )
 {
 	static const gchar *thisfn = "nact_preferences_editor_on_initial_load_dialog";
-	NactPreferencesEditor *editor;
-	GtkWindow *toplevel;
-	GtkWindow *parent_toplevel;
-
-	/* call parent class at the very beginning */
-	if( BASE_WINDOW_CLASS( st_parent_class )->initial_load_toplevel ){
-		BASE_WINDOW_CLASS( st_parent_class )->initial_load_toplevel( dialog );
-	}
+	/*GtkWindow *toplevel;
+	GtkWindow *parent_toplevel;*/
 
-	g_debug( "%s: dialog=%p", thisfn, ( void * ) dialog );
-	g_assert( NACT_IS_PREFERENCES_EDITOR( dialog ));
-	editor = NACT_PREFERENCES_EDITOR( dialog );
+	g_debug( "%s: editor=%p, user_data=%p", thisfn, ( void * ) editor, ( void * ) user_data );
 
-	toplevel = base_window_get_toplevel_dialog( dialog );
+	/*toplevel = base_window_get_toplevel_window( dialog );
 	parent_toplevel = base_window_get_toplevel_dialog( BASE_WINDOW( editor->private->parent ));
-	gtk_window_set_transient_for( toplevel, parent_toplevel );
+	gtk_window_set_transient_for( toplevel, parent_toplevel );*/
 }
 
 static void
-on_runtime_init_dialog( BaseWindow *dialog )
+on_base_runtime_init_dialog( NactPreferencesEditor *editor, gpointer user_data )
 {
 	static const gchar *thisfn = "nact_preferences_editor_on_runtime_init_dialog";
-	NactPreferencesEditor *editor;
 	gboolean sort_alpha, add_about_item;
 	GtkWidget *button;
 
-	/* call parent class at the very beginning */
-	if( BASE_WINDOW_CLASS( st_parent_class )->runtime_init_toplevel ){
-		BASE_WINDOW_CLASS( st_parent_class )->runtime_init_toplevel( dialog );
-	}
-
-	g_debug( "%s: dialog=%p", thisfn, ( void * ) dialog );
-	g_assert( NACT_IS_PREFERENCES_EDITOR( dialog ));
-	editor = NACT_PREFERENCES_EDITOR( dialog );
+	g_debug( "%s: editor=%p, user_data=%p", thisfn, ( void * ) editor, ( void * ) user_data );
 
-	sort_alpha = na_iprefs_get_alphabetical_order( NA_IPREFS( editor ));
-	button = base_window_get_widget( dialog, "SortAlphabeticalButton" );
+	sort_alpha = na_iprefs_is_alphabetical_order( NA_IPREFS( editor ));
+	button = base_window_get_widget( BASE_WINDOW( editor ), "SortAlphabeticalButton" );
 	gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( button ), sort_alpha );
-	nact_window_signal_connect_by_name( NACT_WINDOW( editor ), "SortAlphabeticalButton", "toggled", G_CALLBACK( on_sort_alpha_toggled ));
+	base_window_signal_connect_by_name(
+			BASE_WINDOW( editor ),
+			"SortAlphabeticalButton",
+			"toggled",
+			G_CALLBACK( on_sort_alpha_toggled ));
 
-	add_about_item = na_iprefs_get_add_about_item( NA_IPREFS( editor ));
-	button = base_window_get_widget( dialog, "AddAboutButton" );
+	add_about_item = na_iprefs_should_add_about_item( NA_IPREFS( editor ));
+	button = base_window_get_widget( BASE_WINDOW( editor ), "AddAboutButton" );
 	gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( button ), add_about_item );
-	nact_window_signal_connect_by_name( NACT_WINDOW( editor ), "AddAboutButton", "toggled", G_CALLBACK( on_add_about_toggled ));
-
-	nact_window_signal_connect_by_name( NACT_WINDOW( editor ), "CancelButton", "clicked", G_CALLBACK( on_cancel_clicked ));
-	nact_window_signal_connect_by_name( NACT_WINDOW( editor ), "OKButton", "clicked", G_CALLBACK( on_ok_clicked ));
+	base_window_signal_connect_by_name(
+			BASE_WINDOW( editor ),
+			"AddAboutButton",
+			"toggled",
+			G_CALLBACK( on_add_about_toggled ));
+
+	base_window_signal_connect_by_name(
+			BASE_WINDOW( editor ),
+			"CancelButton",
+			"clicked",
+			G_CALLBACK( on_cancel_clicked ));
+
+	base_window_signal_connect_by_name(
+			BASE_WINDOW( editor ),
+			"OKButton",
+			"clicked",
+			G_CALLBACK( on_ok_clicked ));
 
 	/*setup_buttons( editor, FALSE );*/
 }
 
-static void
-on_all_widgets_showed( BaseWindow *dialog )
-{
-	static const gchar *thisfn = "nact_preferences_editor_on_all_widgets_showed";
-
-	/* call parent class at the very beginning */
-	if( BASE_WINDOW_CLASS( st_parent_class )->all_widgets_showed ){
-		BASE_WINDOW_CLASS( st_parent_class )->all_widgets_showed( dialog );
-	}
-
-	g_debug( "%s: dialog=%p", thisfn, ( void * ) dialog );
-	g_assert( NACT_IS_PREFERENCES_EDITOR( dialog ));
-}
-
 /*
  * rationale:
  * - while the preferences are not modified, only the cancel
@@ -376,30 +370,28 @@ on_modified_field( NactWindow *window )
 }*/
 
 static void
-on_sort_alpha_toggled( GtkToggleButton *button, NactWindow *window )
+on_sort_alpha_toggled( GtkToggleButton *button, NactPreferencesEditor *editor )
 {
-	g_assert( NACT_IS_PREFERENCES_EDITOR( window ));
-	/*NactPreferencesEditor *editor = NACT_PREFERENCES_EDITOR( window );*/
 }
 
 static void
-on_add_about_toggled( GtkToggleButton *button, NactWindow *window )
+on_add_about_toggled( GtkToggleButton *button, NactPreferencesEditor *editor )
 {
-	g_assert( NACT_IS_PREFERENCES_EDITOR( window ));
-	/*NactPreferencesEditor *editor = NACT_PREFERENCES_EDITOR( window );*/
 }
 
 static void
-on_cancel_clicked( GtkButton *button, NactWindow *window )
+on_cancel_clicked( GtkButton *button, NactPreferencesEditor *editor )
 {
-	GtkWindow *toplevel = base_window_get_toplevel_dialog( BASE_WINDOW( window ));
+	GtkWindow *toplevel = base_window_get_toplevel_window( BASE_WINDOW( editor ));
+
 	gtk_dialog_response( GTK_DIALOG( toplevel ), GTK_RESPONSE_CLOSE );
 }
 
 static void
-on_ok_clicked( GtkButton *button, NactWindow *window )
+on_ok_clicked( GtkButton *button, NactPreferencesEditor *editor )
 {
-	GtkWindow *toplevel = base_window_get_toplevel_dialog( BASE_WINDOW( window ));
+	GtkWindow *toplevel = base_window_get_toplevel_window( BASE_WINDOW( editor ));
+
 	gtk_dialog_response( GTK_DIALOG( toplevel ), GTK_RESPONSE_OK );
 }
 
@@ -411,15 +403,15 @@ save_preferences( NactPreferencesEditor *editor )
 
 	button = base_window_get_widget( BASE_WINDOW( editor ), "SortAlphabeticalButton" );
 	enabled = gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON( button ));
-	na_iprefs_set_bool( NA_IPREFS( editor ), PREFS_DISPLAY_ALPHABETICAL_ORDER, enabled );
+	na_iprefs_set_alphabetical_order( NA_IPREFS( editor ), enabled );
 
 	button = base_window_get_widget( BASE_WINDOW( editor ), "AddAboutButton" );
 	enabled = gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON( button ));
-	na_iprefs_set_bool( NA_IPREFS( editor ), PREFS_ADD_ABOUT_ITEM, enabled );
+	na_iprefs_set_add_about_item( NA_IPREFS( editor ), enabled );
 }
 
 static gboolean
-on_dialog_response( GtkDialog *dialog, gint code, BaseWindow *window )
+base_dialog_response( GtkDialog *dialog, gint code, BaseWindow *window )
 {
 	static const gchar *thisfn = "nact_preferences_editor_on_dialog_response";
 	NactPreferencesEditor *editor;
diff --git a/src/nact/nact-preferences-editor.h b/src/nact/nact-preferences-editor.h
index 5b1b069..1024651 100644
--- a/src/nact/nact-preferences-editor.h
+++ b/src/nact/nact-preferences-editor.h
@@ -38,7 +38,7 @@
  * It encapsulates the "PreferencesDialog" widget dialog.
  */
 
-#include "nact-window.h"
+#include "base-dialog.h"
 
 G_BEGIN_DECLS
 
@@ -52,7 +52,7 @@ G_BEGIN_DECLS
 typedef struct NactPreferencesEditorPrivate NactPreferencesEditorPrivate;
 
 typedef struct {
-	NactWindow                    parent;
+	BaseDialog                    parent;
 	NactPreferencesEditorPrivate *private;
 }
 	NactPreferencesEditor;
@@ -60,14 +60,14 @@ typedef struct {
 typedef struct NactPreferencesEditorClassPrivate NactPreferencesEditorClassPrivate;
 
 typedef struct {
-	NactWindowClass                    parent;
+	BaseDialogClass                    parent;
 	NactPreferencesEditorClassPrivate *private;
 }
 	NactPreferencesEditorClass;
 
 GType nact_preferences_editor_get_type( void );
 
-void  nact_preferences_editor_run( NactWindow *parent );
+void  nact_preferences_editor_run( BaseWindow *parent );
 
 G_END_DECLS
 
diff --git a/src/nact/nact-tree-model.c b/src/nact/nact-tree-model.c
index a35d8da..405214c 100644
--- a/src/nact/nact-tree-model.c
+++ b/src/nact/nact-tree-model.c
@@ -38,13 +38,16 @@
 
 #include <string.h>
 
-#include <common/na-action.h>
+#include <common/na-object-api.h>
+#include <common/na-obj-action.h>
+#include <common/na-obj-menu.h>
+#include <common/na-obj-profile.h>
 #include <common/na-iprefs.h>
 #include <common/na-utils.h>
 
 #include "egg-tree-multi-dnd.h"
 #include "nact-iactions-list.h"
-#include "nact-selection.h"
+#include "nact-clipboard.h"
 #include "nact-tree-model.h"
 
 /*
@@ -58,12 +61,13 @@
  * as soon as mouse has quitted the selected area
  *   call once egg_tree_multi_dnd_stop_drag_check( treeview )
  *   call once nact_tree_model_imulti_drag_source_row_draggable: drag_source=0x92a0d70, path_list=0x9373c90
- *   call once nact_selection_on_drag_begin( treeview, context, main_window )
+ *   call once nact_clipboard_on_drag_begin( treeview, context, main_window )
  *
  * when we drop (e.g. in Nautilus)
  *   call once egg_tree_multi_drag_drag_data_get( treeview, context, selection_data, info=0, time )
  *   call once nact_tree_model_imulti_drag_source_drag_data_get( drag_source, context, selection_data, path_list, atom=XdndDirectSave0 )
- *   call once nact_selection_on_drag_end( treeview, context, main_window )
+ *   call once nact_tree_model_idrag_dest_drag_data_received
+ *   call once nact_clipboard_on_drag_end( treeview, context, main_window )
  */
 
 /* private class data
@@ -75,24 +79,26 @@ struct NactTreeModelClassPrivate {
 /* private instance data
  */
 struct NactTreeModelPrivate {
-	gboolean        dispose_has_run;
-	NactMainWindow *window;
-	gchar          *drag_dest_uri;
-	GSList         *drag_items;
+	gboolean     dispose_has_run;
+	BaseWindow  *window;
+	GtkTreeView *treeview;
+	guint        count;
+	gboolean     have_dnd;
+	gchar       *drag_dest_uri;
+	GSList      *drag_items;
 };
 
 #define MAX_XDS_ATOM_VAL_LEN			4096
 #define TEXT_ATOM						gdk_atom_intern( "text/plain", FALSE )
 #define XDS_ATOM						gdk_atom_intern( "XdndDirectSave0", FALSE )
 #define XDS_FILENAME					"xds.txt"
-#define XNACT_ATOM						gdk_atom_intern( "XdndNautilusActions", FALSE )
 
 enum {
 	NACT_XCHANGE_FORMAT_NACT = 0,
 	NACT_XCHANGE_FORMAT_XDS,
 	NACT_XCHANGE_FORMAT_APPLICATION_XML,
-	NACT_XCHANGE_FORMAT_TEXT_PLAIN
-
+	NACT_XCHANGE_FORMAT_TEXT_PLAIN,
+	NACT_XCHANGE_FORMAT_URI_LIST
 };
 
 /* as a dnd source, we provide
@@ -109,10 +115,28 @@ static GtkTargetEntry dnd_source_formats[] = {
 	{ "text/plain",          GTK_TARGET_OTHER_APP,   NACT_XCHANGE_FORMAT_TEXT_PLAIN },
 };
 
-/*static GtkTargetEntry dnd_dest_targets[] = {
-	{ "XdndNautilusActions0", 0, 0 },
-	{ "XdndDirectSave0", 0, 2 }
-};*/
+#define NACT_ATOM						gdk_atom_intern( "XdndNautilusActions", FALSE )
+
+static GtkTargetEntry dnd_dest_targets[] = {
+	{ "XdndNautilusActions", 0, NACT_XCHANGE_FORMAT_NACT },
+	{ "text/uri-list",       0, NACT_XCHANGE_FORMAT_URI_LIST },
+	{ "application/xml",     0, NACT_XCHANGE_FORMAT_APPLICATION_XML },
+	{ "text/plain",          0, NACT_XCHANGE_FORMAT_TEXT_PLAIN },
+};
+
+typedef struct {
+	gchar *fname;
+	gchar *prefix;
+}
+	ntmDumpStruct;
+
+typedef struct {
+	GtkTreeModel   *store;
+	const NAObject *object;
+	gboolean        found;
+	GtkTreeIter    *iter;
+}
+	ntmSearchStruct;
 
 static GtkTreeModelFilterClass *st_parent_class = NULL;
 
@@ -124,6 +148,18 @@ static void           instance_init( GTypeInstance *instance, gpointer klass );
 static void           instance_dispose( GObject *application );
 static void           instance_finalize( GObject *application );
 
+static NactTreeModel *tree_model_new( BaseWindow *window, GtkTreeView *treeview );
+
+static void           append_item( GtkTreeStore *model, GtkTreeView *treeview, GtkTreeIter *parent, GtkTreeIter *iter, const NAObject *object );
+static void           display_item( GtkTreeStore *model, GtkTreeView *treeview, GtkTreeIter *iter, const NAObject *object );
+static gboolean       dump_store( NactTreeModel *model, GtkTreePath *path, NAObject *object, ntmDumpStruct *ntm );
+static void           fill_tree_store( GtkTreeStore *model, GtkTreeView *treeview, GSList *items, gboolean only_actions, GtkTreeIter *parent );
+static void           iter_on_store( NactTreeModel *model, GtkTreeModel *store, GtkTreeIter *parent, FnIterOnStore fn, gpointer user_data );
+static gboolean       iter_on_store_item( NactTreeModel *model, GtkTreeModel *store, GtkTreeIter *iter, FnIterOnStore fn, gpointer user_data );
+static gboolean       search_for_object( NactTreeModel *model, GtkTreeModel *store, const NAObject *object, GtkTreeIter *iter );
+static gboolean       search_for_objet_iter( NactTreeModel *model, GtkTreePath *path, NAObject *object, ntmSearchStruct *ntm );
+static void           update_parent( GtkTreeModel *store, GtkTreeIter *iter );
+
 static gboolean       imulti_drag_source_row_draggable( EggTreeMultiDragSource *drag_source, GList *path_list );
 static gboolean       imulti_drag_source_drag_data_get( EggTreeMultiDragSource *drag_source, GdkDragContext *context, GtkSelectionData *selection_data, GList *path_list, guint info );
 static gboolean       imulti_drag_source_drag_data_delete( EggTreeMultiDragSource *drag_source, GList *path_list );
@@ -133,13 +169,16 @@ static GdkDragAction  imulti_drag_source_get_drag_actions( EggTreeMultiDragSourc
 static gboolean       idrag_dest_drag_data_received( GtkTreeDragDest *drag_dest, GtkTreePath *dest, GtkSelectionData  *selection_data );
 static gboolean       idrag_dest_row_drop_possible( GtkTreeDragDest *drag_dest, GtkTreePath *dest_path, GtkSelectionData *selection_data );
 
-static gboolean       on_drag_begin( GtkWidget *widget, GdkDragContext *context, NactWindow *window );
-static void           on_drag_end( GtkWidget *widget, GdkDragContext *context, NactWindow *window );
+static gboolean       on_drag_begin( GtkWidget *widget, GdkDragContext *context, BaseWindow *window );
+static void           on_drag_end( GtkWidget *widget, GdkDragContext *context, BaseWindow *window );
+static void           on_row_deleted( GtkTreeModel *tree_model, GtkTreePath *path, NactTreeModel *model );
+static void           on_row_inserted( GtkTreeModel *tree_model, GtkTreePath *path, GtkTreeIter *iter, NactTreeModel *model );
+
+/*static gboolean       on_drag_drop( GtkWidget *widget, GdkDragContext *context, gint x, gint y, guint time, BaseWindow *window );
+static void           on_drag_data_received( GtkWidget *widget, GdkDragContext *drag_context, gint x, gint y, GtkSelectionData *data, guint info, guint time, BaseWindow *window );*/
 
-static gint           sort_actions_list( GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b, NactWindow *window );
-static gboolean       filter_visible( GtkTreeModel *model, GtkTreeIter *iter, gpointer data );
-/*static gboolean       nautilus_xds_dnd_is_valid_xds_context( GdkDragContext *context );
-static gboolean       context_offers_target( GdkDragContext *context, GdkAtom target );*/
+static gint           sort_actions_list( GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b, BaseWindow *window );
+static gboolean       filter_visible( GtkTreeModel *model, GtkTreeIter *iter, NactIActionsList *window );
 static char          *get_xds_atom_value( GdkDragContext *context );
 
 GType
@@ -162,11 +201,11 @@ register_type (void)
 
 	static const GTypeInfo info = {
 		sizeof( NactTreeModelClass ),
-		NULL,		/* base_init */
-		NULL,		/* base_finalize */
+		NULL,							/* base_init */
+		NULL,							/* base_finalize */
 		( GClassInitFunc ) class_init,
-		NULL,		/* class_finalize */
-		NULL,		/* class_data */
+		NULL,							/* class_finalize */
+		NULL,							/* class_data */
 		sizeof( NactTreeModel ),
 		0,
 		( GInstanceInitFunc ) instance_init
@@ -241,25 +280,26 @@ idrag_dest_init( GtkTreeDragDestIface *iface )
 static void
 instance_init( GTypeInstance *instance, gpointer klass )
 {
-	/*static const gchar *thisfn = "nact_tree_model_instance_init";*/
+	static const gchar *thisfn = "nact_tree_model_instance_init";
 	NactTreeModel *self;
 
-	/*g_debug( "%s: instance=%p, klass=%p", thisfn, ( void * ) instance, ( void * ) klass );*/
+	g_debug( "%s: instance=%p, klass=%p", thisfn, ( void * ) instance, ( void * ) klass );
 	g_assert( NACT_IS_TREE_MODEL( instance ));
 	self = NACT_TREE_MODEL( instance );
 
 	self->private = g_new0( NactTreeModelPrivate, 1 );
 
 	self->private->dispose_has_run = FALSE;
+	self->private->count = 0;
 }
 
 static void
 instance_dispose( GObject *object )
 {
-	/*static const gchar *thisfn = "nact_tree_model_instance_dispose";*/
+	static const gchar *thisfn = "nact_tree_model_instance_dispose";
 	NactTreeModel *self;
 
-	/*g_debug( "%s: object=%p", thisfn, ( void * ) object );*/
+	g_debug( "%s: object=%p", thisfn, ( void * ) object );
 	g_assert( NACT_IS_TREE_MODEL( object ));
 	self = NACT_TREE_MODEL( object );
 
@@ -277,10 +317,10 @@ instance_dispose( GObject *object )
 static void
 instance_finalize( GObject *object )
 {
-	/*static const gchar *thisfn = "nact_tree_model_instance_finalize";*/
+	static const gchar *thisfn = "nact_tree_model_instance_finalize";
 	NactTreeModel *self;
 
-	/*g_debug( "%s: object=%p", thisfn, ( void * ) object );*/
+	g_debug( "%s: object=%p", thisfn, ( void * ) object );
 	g_assert( NACT_IS_TREE_MODEL( object ));
 	self = NACT_TREE_MODEL( object );
 
@@ -295,12 +335,29 @@ instance_finalize( GObject *object )
 	}
 }
 
-NactTreeModel *
-nact_tree_model_new( NactMainWindow *window )
+/*
+ * tree_model_new:
+ * @window: a #BaseWindow window which must implement #NactIActionsList
+ * interface.
+ * @treeview: the #GtkTreeView widget.
+ *
+ * Creates a new #NactTreeModel model.
+ *
+ * This function should be called at widget initial load time. Is is so
+ * too soon to make any assumption about sorting in the tree view.
+ */
+static NactTreeModel *
+tree_model_new( BaseWindow *window, GtkTreeView *treeview )
 {
-	GtkTreeStore  *ts_model;
+	static const gchar *thisfn = "nact_tree_model_new";
+	GtkTreeStore *ts_model;
 	NactTreeModel *model;
-	gboolean       alpha_order;
+	/*gboolean       alpha_order;*/
+
+	g_debug( "%s: window=%p, treeview=%p", thisfn, ( void * ) window, ( void * ) treeview );
+	g_return_val_if_fail( BASE_IS_WINDOW( window ), NULL );
+	g_return_val_if_fail( NACT_IS_IACTIONS_LIST( window ), NULL );
+	g_return_val_if_fail( GTK_IS_TREE_VIEW( treeview ), NULL );
 
 	ts_model = gtk_tree_store_new(
 			IACTIONS_LIST_N_COLUMN, GDK_TYPE_PIXBUF, G_TYPE_STRING, NA_OBJECT_TYPE );
@@ -309,32 +366,67 @@ nact_tree_model_new( NactMainWindow *window )
 			GTK_TREE_SORTABLE( ts_model ),
 	        ( GtkTreeIterCompareFunc ) sort_actions_list, window, NULL );
 
-	alpha_order = na_iprefs_get_alphabetical_order( NA_IPREFS( window ));
+	/*alpha_order = na_iprefs_get_alphabetical_order( NA_IPREFS( window ));
 
 	if( alpha_order ){
 		gtk_tree_sortable_set_sort_column_id(
 				GTK_TREE_SORTABLE( ts_model ),
 				IACTIONS_LIST_LABEL_COLUMN, GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID );
-	}
-
-	/* create the filter model */
+	}*/
 
+	/* create the filter model
+	 */
 	model = g_object_new( NACT_TREE_MODEL_TYPE, "child-model", ts_model, NULL );
 
 	gtk_tree_model_filter_set_visible_func(
 			GTK_TREE_MODEL_FILTER( model ), ( GtkTreeModelFilterVisibleFunc ) filter_visible, window, NULL );
 
 	model->private->window = window;
+	model->private->treeview = treeview;
 
 	return( model );
 }
 
 /**
+ * nact_tree_model_initial_load:
+ * @window: the #BaseWindow window.
+ * @widget: the #GtkTreeView which will implement the #NactTreeModel.
+ *
+ * Creates a #NactTreeModel, and attaches it to the treeview.
+ *
+ * Please note that we cannot make any assumption here whether the
+ * treeview, and so the tree model, must or not implement the drag and
+ * drop interfaces.
+ * This is because #NactIActionsList::on_initial_load() initializes these
+ * properties to %FALSE. The actual values will be set by the main
+ * program between #NactIActionsList::on_initial_load() returns and call
+ * to #NactIActionsList::on_runtime_init().
+ */
+void
+nact_tree_model_initial_load( BaseWindow *window, GtkTreeView *treeview )
+{
+	static const gchar *thisfn = "nact_tree_model_initial_load";
+	NactTreeModel *model;
+
+	g_debug( "%s: window=%p, treeview=%p", thisfn, ( void * ) window, ( void * ) treeview );
+	g_return_if_fail( BASE_IS_WINDOW( window ));
+	g_return_if_fail( NACT_IS_IACTIONS_LIST( window ));
+	g_return_if_fail( GTK_IS_TREE_VIEW( treeview ));
+
+	model = tree_model_new( window, treeview );
+
+	gtk_tree_view_set_model( treeview, GTK_TREE_MODEL( model ));
+
+	g_object_unref( model );
+}
+
+/**
  * nact_tree_model_runtime_init_dnd:
- * @window: the #NactMainWindow window.
- * @widget: the #GtkTreeView which implements this #NactTreeModel.
+ * @model: this #NactTreeModel instance.
+ * @have_dnd: whether the tree model must implement drag and drop
+ * interfaces.
  *
- * Initializes the drag & drop features.
+ * Initializes the tree model.
  *
  * We use drag and drop:
  * - inside of treeview, for duplicating items, or moving items between
@@ -343,37 +435,469 @@ nact_tree_model_new( NactMainWindow *window )
  * - from outside world (e.g. Nautilus) to import actions
  */
 void
-nact_tree_model_runtime_init_dnd( NactMainWindow *window, GtkTreeView *widget )
+nact_tree_model_runtime_init( NactTreeModel *model, gboolean have_dnd )
 {
-	NactTreeModel *model;
+	static const gchar *thisfn = "nact_tree_model_runtime_init";
+	GtkTreeModel *ts_model;
+
+	g_debug( "%s: model=%p, have_dnd=%s", thisfn, ( void * ) model, have_dnd ? "True":"False" );
+	g_return_if_fail( NACT_IS_TREE_MODEL( model ));
+
+	if( have_dnd ){
+		egg_tree_multi_drag_add_drag_support( EGG_TREE_MULTI_DRAG_SOURCE( model ), model->private->treeview );
+
+		gtk_tree_view_enable_model_drag_dest(
+			model->private->treeview,
+			dnd_dest_targets, G_N_ELEMENTS( dnd_dest_targets ), GDK_ACTION_COPY | GDK_ACTION_MOVE );
+
+		base_window_signal_connect(
+				BASE_WINDOW( model->private->window ),
+				G_OBJECT( model->private->treeview ),
+				"drag-begin",
+				G_CALLBACK( on_drag_begin ));
+
+		base_window_signal_connect(
+				BASE_WINDOW( model->private->window ),
+				G_OBJECT( model->private->treeview ),
+				"drag-end",
+				G_CALLBACK( on_drag_end ));
+
+		/*nact_window_signal_connect(
+				NACT_WINDOW( window ),
+				G_OBJECT( treeview ),
+				"drag_drop",
+				G_CALLBACK( on_drag_drop ));
+
+		nact_window_signal_connect(
+				NACT_WINDOW( window ),
+				G_OBJECT( treeview ),
+				"drag_data-received",
+				G_CALLBACK( on_drag_data_received ));*/
+	}
+
+	ts_model = gtk_tree_model_filter_get_model( GTK_TREE_MODEL_FILTER( model ));
+
+	g_signal_connect(
+			G_OBJECT( ts_model ),
+			"row-deleted",
+			G_CALLBACK( on_row_deleted ),
+			model );
+
+	g_signal_connect(
+			G_OBJECT( ts_model ),
+			"row-inserted",
+			G_CALLBACK( on_row_inserted ),
+			model );
+}
+
+void
+nact_tree_model_dispose( NactTreeModel *model )
+{
+	static const gchar *thisfn = "nact_tree_model_dispose";
+	GtkTreeStore *ts_model;
+
+	g_debug( "%s: model=%p", thisfn, ( void * ) model );
+	g_return_if_fail( NACT_IS_TREE_MODEL( model ));
+
+#ifdef NA_MAINTAINER_MODE
+	nact_tree_model_dump( model );
+#endif
+
+	ts_model = GTK_TREE_STORE( gtk_tree_model_filter_get_model( GTK_TREE_MODEL_FILTER( model )));
+
+	gtk_tree_store_clear( ts_model );
+}
+
+void
+nact_tree_model_dump( NactTreeModel *model )
+{
+	static const gchar *thisfn = "nact_tree_model_dump";
+	GtkTreeStore *store;
+	ntmDumpStruct *ntm;
 
-	model = NACT_TREE_MODEL( gtk_tree_view_get_model( widget ));
-	g_assert( NACT_IS_TREE_MODEL( model ));
+	g_return_if_fail( NACT_IS_TREE_MODEL( model ));
 
-	nact_window_signal_connect(
-			NACT_WINDOW( window ),
-			G_OBJECT( widget ),
-			"drag_begin",
-			G_CALLBACK( on_drag_begin ));
+	store = GTK_TREE_STORE( gtk_tree_model_filter_get_model( GTK_TREE_MODEL_FILTER( model )));
 
-	nact_window_signal_connect(
-			NACT_WINDOW( window ),
-			G_OBJECT( widget ),
-			"drag_end",
-			G_CALLBACK( on_drag_end ));
+	g_debug( "%s: %s at %p, %s at %p", thisfn,
+			G_OBJECT_TYPE_NAME( model ), ( void * ) model, G_OBJECT_TYPE_NAME( store ), ( void * ) store );
 
-	egg_tree_multi_drag_add_drag_support( EGG_TREE_MULTI_DRAG_SOURCE( model ), GTK_TREE_VIEW( widget ));
+	ntm = g_new0( ntmDumpStruct, 1 );
+	ntm->fname = g_strdup( thisfn );
+	ntm->prefix = g_strdup( "" );
 
-	/*gtk_drag_source_set(
-		GTK_WIDGET( widget ),
-		GDK_BUTTON1_MASK,
-		dnd_source_formats, G_N_ELEMENTS( dnd_source_formats ),
-		GDK_ACTION_COPY | GDK_ACTION_MOVE
-	);*/
+	nact_tree_model_iter( model, ( FnIterOnStore ) dump_store, ntm );
+	/*dump_store( GTK_TREE_MODEL( store ), NULL, thisfn, "" );*/
 
-	/*gtk_drag_dest_set(
-		GTK_WIDGET( widget ), GTK_DEST_DEFAULT_ALL,
-		dnd_dest_targets, G_N_ELEMENTS( dnd_dest_targets ), GDK_ACTION_COPY | GDK_ACTION_MOVE );*/
+	g_free( ntm->prefix );
+	g_free( ntm->fname );
+	g_free( ntm );
+}
+
+/**
+ * nact_tree_model_fill:
+ * @model: this #NactTreeModel instance.
+ * @ŧreeview: the #GtkTreeView widget.
+ * @items: this list of items, usually from #NAPivot, which will be used
+ * to fill up the tree store.
+ * @only_actions: whether to store only actions, or all items.
+ *
+ * Fill up the tree store with specified items.
+ *
+ * We enter with the GSList owned by NAPivot which contains the ordered
+ * list of level-zero items. We want have a duplicate of this list in
+ * tree store, so that we are able to freely edit it.
+ */
+void
+nact_tree_model_fill( NactTreeModel *model, GSList *items, gboolean only_actions)
+{
+	static const gchar *thisfn = "nact_tree_model_fill";
+	GtkTreeStore *ts_model;
+
+	g_debug( "%s: model=%p, items=%p (%d items), only_actions=%s",
+			thisfn, ( void * ) model, ( void * ) items, g_slist_length( items ), only_actions ? "True":"False" );
+	g_return_if_fail( NACT_IS_TREE_MODEL( model ));
+
+	ts_model = GTK_TREE_STORE( gtk_tree_model_filter_get_model( GTK_TREE_MODEL_FILTER( model )));
+
+	gtk_tree_store_clear( ts_model );
+
+	fill_tree_store( ts_model, model->private->treeview, items, only_actions, NULL );
+}
+
+static void
+fill_tree_store( GtkTreeStore *model, GtkTreeView *treeview,
+					GSList *items, gboolean only_actions, GtkTreeIter *parent )
+{
+	/*static const gchar *thisfn = "nact_tree_model_fill_tree_store";*/
+	GSList *subitems, *it;
+	NAObject *object;
+	NAObject *duplicate;
+	GtkTreeIter iter;
+
+	for( it = items ; it ; it = it->next ){
+		object = NA_OBJECT( it->data );
+		/*g_debug( "%s: %s at %p", thisfn, G_OBJECT_TYPE_NAME( object ), ( void * ) object );*/
+
+		if( NA_IS_OBJECT_MENU( object )){
+			duplicate = object;
+			if( !only_actions ){
+				duplicate = parent ? g_object_ref( object ) : na_object_duplicate( object );
+				append_item( model, treeview, parent, &iter, duplicate );
+				g_object_unref( duplicate );
+			}
+			subitems = na_object_get_items( duplicate );
+			fill_tree_store( model, treeview, subitems, only_actions, only_actions ? NULL : &iter );
+			na_object_free_items( subitems );
+		}
+
+		if( NA_IS_OBJECT_ACTION( object )){
+			duplicate = parent ? g_object_ref( object ) : na_object_duplicate( object );
+			append_item( model, treeview, parent, &iter, duplicate );
+			g_object_unref( duplicate );
+			if( !only_actions ){
+				subitems = na_object_get_items( duplicate );
+				fill_tree_store( model, treeview, subitems, only_actions, &iter );
+				na_object_free_items( subitems );
+			}
+			g_return_if_fail( NA_IS_OBJECT_ACTION( duplicate ));
+			g_return_if_fail( na_object_get_items_count( duplicate ) >= 1 );
+		}
+
+		if( NA_IS_OBJECT_PROFILE( object )){
+			g_assert( !only_actions );
+			append_item( model, treeview, parent, &iter, object );
+		}
+	}
+}
+
+/**
+ * nact_tree_model_get_items_count:
+ * @model: this #NactTreeModel instance.
+ *
+ * Returns: the total count of rows, whether they are currently visible
+ * or not.
+ */
+guint
+nact_tree_model_get_items_count( NactTreeModel *model )
+{
+	g_return_val_if_fail( NACT_IS_TREE_MODEL( model ), 0 );
+
+	return( model->private->count );
+}
+
+/**
+ * nact_tree_model_insert_item:
+ * @model: this #NactTreeModel instance.
+ * @object: the #NAObject-derived object to be inserted.
+ * @path: the #GtkTreePath of the beginning of the current selection,
+ * or NULL.
+ * @selected: the first currently selected #NAObject if any, or NULL.
+ * In other words, @selected is the item selected at @path.
+ * @iter: a #GtkTreeIter which will be set to the new row.
+ *
+ * Insert a new row at the given position.
+ */
+void
+nact_tree_model_insert_item( NactTreeModel *model, const NAObject *object, GtkTreePath *path, const NAObject *selected, GtkTreeIter *iter )
+{
+	static const gchar *thisfn = "nact_tree_model_insert_item";
+	gchar *path_str;
+	GtkTreeModel *store;
+	GtkTreeIter sibling;
+	GtkTreeIter *parent;
+	GtkTreeIter store_iter;
+	GtkTreeIter profile_iter;
+	GSList *profiles;
+
+	path_str = path ? gtk_tree_path_to_string( path ) : NULL;
+	g_debug( "%s: model=%p, object=%p, path=%p (%s), selected=%p, iter=%p",
+			thisfn, ( void * ) model, ( void * ) object, ( void * ) path, path_str, ( void * ) selected, ( void * ) iter );
+	g_free( path_str );
+
+	g_return_if_fail( NACT_IS_TREE_MODEL( model ));
+	g_return_if_fail( NA_IS_OBJECT( object ));
+	g_return_if_fail( iter );
+
+	store = gtk_tree_model_filter_get_model( GTK_TREE_MODEL_FILTER( model ));
+	parent = NULL;
+
+	if( path ){
+		g_return_if_fail( selected );
+		g_return_if_fail( NA_IS_OBJECT( selected ));
+
+		if( NA_IS_OBJECT_ITEM( object )){
+			if( !NA_IS_OBJECT_ITEM( selected )){
+				gtk_tree_path_up( path );
+			}
+			gtk_tree_model_get_iter( store, &sibling, path );
+			if( NA_IS_OBJECT_MENU( selected )){
+				parent = gtk_tree_iter_copy( &sibling );
+				na_object_insert_item( selected, object );
+			}
+		}
+
+		if( NA_IS_OBJECT_PROFILE( object )){
+			if( NA_IS_OBJECT_ACTION( selected )){
+				gtk_tree_path_down( path );
+				g_debug( "nact_tree_model_insert_item: object_is_action_profile, selected_is_action" );
+			}
+			gtk_tree_model_get_iter( store, &sibling, path );
+		}
+
+	} else {
+		g_return_if_fail( NA_IS_OBJECT_ITEM( object ));
+	}
+
+	gtk_tree_store_insert_before( GTK_TREE_STORE( store ), &store_iter, parent, parent ? NULL : ( path ? &sibling : NULL ));
+	gtk_tree_store_set( GTK_TREE_STORE( store ), &store_iter, IACTIONS_LIST_NAOBJECT_COLUMN, object, -1 );
+	display_item( GTK_TREE_STORE( store ), model->private->treeview, &store_iter, object );
+
+	if( parent ){
+		gtk_tree_iter_free( parent );
+	}
+
+	if( NA_IS_OBJECT_ACTION( object )){
+		g_return_if_fail( na_object_get_items_count( object ) == 1 );
+		profiles = na_object_get_items( object );
+		append_item( GTK_TREE_STORE( store ), model->private->treeview, &store_iter, &profile_iter, NA_OBJECT( profiles->data ));
+		na_object_free_items( profiles );
+	}
+
+	nact_tree_model_update_parent( model, object );
+
+	gtk_tree_model_filter_refilter( GTK_TREE_MODEL_FILTER( model ));
+	gtk_tree_model_filter_convert_child_iter_to_iter( GTK_TREE_MODEL_FILTER( model ), iter, &store_iter );
+}
+
+void
+nact_tree_model_iter( NactTreeModel *model, FnIterOnStore fn, gpointer user_data )
+{
+	GtkTreeStore *store;
+
+	g_return_if_fail( NACT_IS_TREE_MODEL( model ));
+
+	store = GTK_TREE_STORE( gtk_tree_model_filter_get_model( GTK_TREE_MODEL_FILTER( model )));
+
+	iter_on_store( model, GTK_TREE_MODEL( store ), NULL, fn, user_data );
+}
+
+GSList *
+nact_tree_model_remove( NactTreeModel *model, GList *selected )
+{
+	GList *reversed, *item;
+	GtkTreeIter iter;
+	GtkTreeStore *store;
+	gchar *path_str;
+	GSList *deleted = NULL;
+	NAObject *object;
+
+	reversed = g_list_reverse( selected );
+	store = GTK_TREE_STORE( gtk_tree_model_filter_get_model( GTK_TREE_MODEL_FILTER( model )));
+
+	for( item = reversed ; item ; item = item->next ){
+		path_str = gtk_tree_path_to_string(( GtkTreePath * ) item->data );
+		g_debug( "nact_tree_model_remove: path=%s", path_str );
+		g_free( path_str );
+		gtk_tree_model_get_iter( GTK_TREE_MODEL( store ), &iter, ( GtkTreePath * ) item->data );
+		gtk_tree_model_get( GTK_TREE_MODEL( store ), &iter, IACTIONS_LIST_NAOBJECT_COLUMN, &object, -1 );
+		gtk_tree_store_remove( store, &iter );
+		deleted = g_slist_prepend( deleted, object );
+	}
+
+	return( g_slist_reverse( deleted ));
+}
+
+/**
+ * Recursively update the parent hierarchy of this #NAObject
+ * by setting their modified status to %TRUE.
+ */
+void
+nact_tree_model_update_parent( NactTreeModel *model, const NAObject *object )
+{
+	GtkTreeModel *store;
+	GtkTreeIter iter;
+
+	g_return_if_fail( NACT_IS_TREE_MODEL( model ));
+	g_return_if_fail( NA_IS_OBJECT( object ));
+
+	store = gtk_tree_model_filter_get_model( GTK_TREE_MODEL_FILTER( model ));
+
+	if( search_for_object( model, store, object, &iter )){
+		update_parent( store, &iter );
+	}
+
+	gtk_tree_model_filter_refilter( GTK_TREE_MODEL_FILTER( model ));
+}
+
+static void
+append_item( GtkTreeStore *model, GtkTreeView *treeview, GtkTreeIter *parent, GtkTreeIter *iter, const NAObject *object )
+{
+	gtk_tree_store_append( model, iter, parent );
+
+	gtk_tree_store_set( model, iter, IACTIONS_LIST_NAOBJECT_COLUMN, object, -1 );
+
+	display_item( model, treeview, iter, object );
+}
+
+static void
+display_item( GtkTreeStore *model, GtkTreeView *treeview, GtkTreeIter *iter, const NAObject *object )
+{
+	gchar *label = na_object_get_label( object );
+	gtk_tree_store_set( model, iter, IACTIONS_LIST_LABEL_COLUMN, label, -1 );
+	g_free( label );
+
+	if( NA_IS_OBJECT_ITEM( object )){
+		GdkPixbuf *icon = na_object_item_get_pixbuf( NA_OBJECT_ITEM( object ), GTK_WIDGET( treeview ));
+		gtk_tree_store_set( model, iter, IACTIONS_LIST_ICON_COLUMN, icon, -1 );
+	}
+}
+
+static gboolean
+dump_store( NactTreeModel *model, GtkTreePath *path, NAObject *object, ntmDumpStruct *ntm )
+{
+	gint depth;
+	gint i;
+	GString *prefix;
+
+	depth = gtk_tree_path_get_depth( path );
+	prefix = g_string_new( ntm->prefix );
+	for( i=1 ; i<depth ; ++i ){
+		g_string_append_printf( prefix, "  " );
+	}
+
+	g_debug( "%s: %s%s at %p", ntm->fname, prefix->str, G_OBJECT_TYPE_NAME( object ), ( void * ) object );
+
+	g_string_free( prefix, TRUE );
+
+	/* don't stop iteration */
+	return( FALSE );
+}
+
+static void
+iter_on_store( NactTreeModel *model, GtkTreeModel *store, GtkTreeIter *parent, FnIterOnStore fn, gpointer user_data )
+{
+	GtkTreeIter iter;
+	gboolean stop;
+
+	if( gtk_tree_model_iter_children( store, &iter, parent )){
+		stop = iter_on_store_item( model, store, &iter, fn, user_data );
+		while( !stop && gtk_tree_model_iter_next( store, &iter )){
+			stop = iter_on_store_item( model, store, &iter, fn, user_data );
+		}
+	}
+}
+
+static gboolean
+iter_on_store_item( NactTreeModel *model, GtkTreeModel *store, GtkTreeIter *iter, FnIterOnStore fn, gpointer user_data )
+{
+	NAObject *object;
+	GtkTreePath *path;
+	gboolean stop;
+
+	gtk_tree_model_get( store, iter, IACTIONS_LIST_NAOBJECT_COLUMN, &object, -1 );
+	path = gtk_tree_model_get_path( store, iter );
+
+	stop = ( *fn )( model, path, object, user_data );
+
+	gtk_tree_path_free( path );
+	g_object_unref( object );
+
+	if( !stop ){
+		iter_on_store( model, store, iter, fn, user_data );
+	}
+
+	return( stop );
+}
+
+static gboolean
+search_for_object( NactTreeModel *model, GtkTreeModel *store, const NAObject *object, GtkTreeIter *result_iter )
+{
+	gboolean found = FALSE;
+	ntmSearchStruct *ntm;
+	GtkTreeIter iter;
+
+	ntm = g_new0( ntmSearchStruct, 1 );
+	ntm->store = store;
+	ntm->object = object;
+	ntm->found = FALSE;
+	ntm->iter = &iter;
+
+	iter_on_store( model, store, NULL, ( FnIterOnStore ) search_for_objet_iter, ntm );
+
+	if( ntm->found ){
+		found = TRUE;
+		memcpy( result_iter, ntm->iter, sizeof( GtkTreeIter ));
+	}
+
+	g_free( ntm );
+	return( found );
+}
+
+static gboolean
+search_for_objet_iter( NactTreeModel *model, GtkTreePath *path, NAObject *object, ntmSearchStruct *ntm )
+{
+	if( object == ntm->object ){
+		if( gtk_tree_model_get_iter( ntm->store, ntm->iter, path )){
+			ntm->found = TRUE;
+		}
+	}
+	/* stop iteration when found */
+	return( ntm->found );
+}
+
+static void
+update_parent( GtkTreeModel *store, GtkTreeIter *iter )
+{
+	GtkTreeIter parent;
+	NAObject *object;
+
+	if( gtk_tree_model_iter_parent( store, &parent, iter )){
+		gtk_tree_model_get( store, &parent, IACTIONS_LIST_NAOBJECT_COLUMN, &object, -1 );
+		/*na_object_set_modified_status( object, TRUE );*/
+		g_object_unref( object );
+		update_parent( store, &parent );
+	}
 }
 
 /*
@@ -446,10 +970,11 @@ imulti_drag_source_drag_data_get( EggTreeMultiDragSource *drag_source,
 	gboolean ret = FALSE;
 	gchar *dest_folder, *folder;
 	gboolean is_writable;
+	gboolean copy_data;
 
 	atom_name = gdk_atom_name( selection_data->target );
-	g_debug( "%s: drag_source=%p, context=%p, selection_data=%p, path_list=%p, atom=%s",
-			thisfn, ( void * ) drag_source, ( void * ) context, ( void * ) selection_data, ( void * ) path_list,
+	g_debug( "%s: drag_source=%p, context=%p, action=%d, selection_data=%p, path_list=%p, atom=%s",
+			thisfn, ( void * ) drag_source, ( void * ) context, ( int ) context->suggested_action, ( void * ) selection_data, ( void * ) path_list,
 			atom_name );
 	g_free( atom_name );
 
@@ -467,9 +992,9 @@ imulti_drag_source_drag_data_get( EggTreeMultiDragSource *drag_source,
 
 	switch( info ){
 		case NACT_XCHANGE_FORMAT_NACT:
-			data = nact_selection_get_data_for_intern_use( selected_items );
-			gtk_selection_data_set( selection_data, selection_data->target, 8, ( guchar * ) data, strlen( data ));
-			g_free( data );
+			copy_data = ( context->suggested_action == GDK_ACTION_COPY );
+			nact_clipboard_get_data_for_intern_use( selected_items, copy_data );
+			gtk_selection_data_set( selection_data, selection_data->target, 8, ( guchar * ) "", 0 );
 			ret = TRUE;
 			break;
 
@@ -489,7 +1014,7 @@ imulti_drag_source_drag_data_get( EggTreeMultiDragSource *drag_source,
 
 		case NACT_XCHANGE_FORMAT_APPLICATION_XML:
 		case NACT_XCHANGE_FORMAT_TEXT_PLAIN:
-			data = nact_selection_get_data_for_extern_use( selected_items );
+			data = nact_clipboard_get_data_for_extern_use( selected_items );
 			gtk_selection_data_set( selection_data, selection_data->target, 8, ( guchar * ) data, strlen( data ));
 			g_free( data );
 			ret = TRUE;
@@ -529,6 +1054,9 @@ imulti_drag_source_get_drag_actions( EggTreeMultiDragSource *drag_source )
 	return( GDK_ACTION_COPY | GDK_ACTION_MOVE );
 }
 
+/*
+ * TODO: empty the internal clipboard at drop time
+ */
 static gboolean
 idrag_dest_drag_data_received( GtkTreeDragDest *drag_dest, GtkTreePath *dest, GtkSelectionData  *selection_data )
 {
@@ -550,9 +1078,9 @@ idrag_dest_row_drop_possible( GtkTreeDragDest *drag_dest, GtkTreePath *dest_path
 }
 
 static gboolean
-on_drag_begin( GtkWidget *widget, GdkDragContext *context, NactWindow *window )
+on_drag_begin( GtkWidget *widget, GdkDragContext *context, BaseWindow *window )
 {
-	static const gchar *thisfn = "nact_selection_on_drag_begin";
+	static const gchar *thisfn = "nact_clipboard_on_drag_begin";
 	NactTreeModel *model;
 
 	g_debug( "%s: widget=%p, context=%p, window=%p",
@@ -574,9 +1102,9 @@ on_drag_begin( GtkWidget *widget, GdkDragContext *context, NactWindow *window )
 }
 
 static void
-on_drag_end( GtkWidget *widget, GdkDragContext *context, NactWindow *window )
+on_drag_end( GtkWidget *widget, GdkDragContext *context, BaseWindow *window )
 {
-	static const gchar *thisfn = "nact_selection_on_drag_end";
+	static const gchar *thisfn = "nact_clipboard_on_drag_end";
 	NactTreeModel *model;
 
 	g_debug( "%s: widget=%p, context=%p, window=%p",
@@ -585,7 +1113,7 @@ on_drag_end( GtkWidget *widget, GdkDragContext *context, NactWindow *window )
 	model = NACT_TREE_MODEL( gtk_tree_view_get_model( GTK_TREE_VIEW( widget )));
 
 	if( model->private->drag_dest_uri && model->private->drag_items && g_slist_length( model->private->drag_items )){
-		nact_selection_export_items( model->private->drag_dest_uri, model->private->drag_items );
+		nact_clipboard_export_items( model->private->drag_dest_uri, model->private->drag_items );
 	}
 
 	g_free( model->private->drag_dest_uri );
@@ -597,8 +1125,48 @@ on_drag_end( GtkWidget *widget, GdkDragContext *context, NactWindow *window )
 	gdk_property_delete( context->source_window, XDS_ATOM );
 }
 
+/*static gboolean
+on_drag_drop( GtkWidget *widget, GdkDragContext *context, gint x, gint y, guint time, BaseWindow *window )
+{
+	static const gchar *thisfn = "nact_clipboard_on_drag_drop";
+
+	g_debug( "%s: widget=%p, context=%p, x=%d, y=%d, time=%d, window=%p",
+			thisfn, ( void * ) widget, ( void * ) context, x, y, time, ( void * ) window );
+*/
+	/*No!*/
+	/*gtk_drag_get_data( widget, context, NACT_ATOM, time );*/
+
+	/* return TRUE is the mouse pointer is on a drop zone, FALSE else */
+	/*return( TRUE );
+}*/
+
+/*static void
+on_drag_data_received( GtkWidget *widget, GdkDragContext *drag_context, gint x, gint y, GtkSelectionData *data, guint info, guint time, BaseWindow *window )
+{
+	static const gchar *thisfn = "nact_tree_model_on_drag_data_received";
+
+	g_debug( "%s: widget=%p, drag_context=%p, x=%d, y=%d, selection_data=%p, info=%d, time=%d, window=%p",
+			thisfn, ( void * ) widget, ( void * ) drag_context, x, y, ( void * ) data, info, time, ( void * ) window );
+}*/
+
+static void
+on_row_deleted( GtkTreeModel *tree_model, GtkTreePath *path, NactTreeModel *model )
+{
+	g_return_if_fail( NACT_IS_TREE_MODEL( model ));
+
+	model->private->count -= 1;
+}
+
+static void
+on_row_inserted( GtkTreeModel *tree_model, GtkTreePath *path, GtkTreeIter *iter, NactTreeModel *model )
+{
+	g_return_if_fail( NACT_IS_TREE_MODEL( model ));
+
+	model->private->count += 1;
+}
+
 static gint
-sort_actions_list( GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b, NactWindow *window )
+sort_actions_list( GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b, BaseWindow *window )
 {
 	static const gchar *thisfn = "nact_tree_model_sort_actions_list";
 	gchar *labela, *labelb;
@@ -618,64 +1186,56 @@ sort_actions_list( GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b, NactWind
 }
 
 static gboolean
-filter_visible( GtkTreeModel *model, GtkTreeIter *iter, gpointer data )
+filter_visible( GtkTreeModel *model, GtkTreeIter *iter, NactIActionsList *window )
 {
 	/*static const gchar *thisfn = "nact_tree_model_filter_visible";*/
 	NAObject *object;
-	NAAction *action;
+	NAObjectAction *action;
+	gboolean only_actions;
 
-	/*g_debug( "%s: model=%p, iter=%p, data=%p", thisfn, ( void * ) model, ( void * ) iter, ( void * ) data );*/
+	/*g_debug( "%s: model=%p, iter=%p, window=%p", thisfn, ( void * ) model, ( void * ) iter, ( void * ) window );*/
+	/*g_debug( "%s at %p", G_OBJECT_TYPE_NAME( model ), ( void * ) model );*/
+	/* is a GtkTreeStore */
 
 	gtk_tree_model_get( model, iter, IACTIONS_LIST_NAOBJECT_COLUMN, &object, -1 );
 
 	if( object ){
-		if( NA_IS_ACTION( object )){
+		/*na_object_dump( object );*/
+
+		if( NA_IS_OBJECT_ACTION( object )){
+			g_object_unref( object );
 			return( TRUE );
 		}
 
-		g_assert( NA_IS_ACTION_PROFILE( object ));
-		action = na_action_profile_get_action( NA_ACTION_PROFILE( object ));
-		return( na_action_get_profiles_count( action ) > 1 );
+		only_actions = nact_iactions_list_is_only_actions_mode( window );
+
+		if( !only_actions ){
+
+			if( NA_IS_OBJECT_MENU( object )){
+				g_object_unref( object );
+				return( TRUE );
+			}
+
+			if( NA_IS_OBJECT_PROFILE( object )){
+				action = na_object_profile_get_action( NA_OBJECT_PROFILE( object ));
+				g_object_unref( object );
+				/*return( TRUE );*/
+				return( na_object_get_items_count( action ) > 1 );
+			}
+
+			g_assert_not_reached();
+		}
 	}
 
 	return( FALSE );
 }
 
-/*
- * from FileRoller
- */
-/* The following three functions taken from bugzilla
+/* The following function taken from bugzilla
  * (http://bugzilla.gnome.org/attachment.cgi?id=49362&action=view)
  * Author: Christian Neumair
  * Copyright: 2005 Free Software Foundation, Inc
  * License: GPL
  */
-/*static gboolean
-nautilus_xds_dnd_is_valid_xds_context (GdkDragContext *context)
-{
-	char *tmp;
-	gboolean ret;
-
-	g_return_val_if_fail (context != NULL, FALSE);
-
-	tmp = NULL;
-	if (context_offers_target (context, XDS_ATOM)) {
-		tmp = get_xds_atom_value (context);
-	}
-
-	ret = (tmp != NULL);
-	g_free (tmp);
-
-	return ret;
-}
-
-static gboolean
-context_offers_target (GdkDragContext *context,
-                       GdkAtom target)
-{
-	return (g_list_find (context->targets, target) != NULL);
-}*/
-
 static char *
 get_xds_atom_value (GdkDragContext *context)
 {
diff --git a/src/nact/nact-tree-model.h b/src/nact/nact-tree-model.h
index a2b773c..9f30fac 100644
--- a/src/nact/nact-tree-model.h
+++ b/src/nact/nact-tree-model.h
@@ -28,10 +28,6 @@
  *   ... and many others (see AUTHORS)
  */
 
-/*
- * Adapted from File-Roller:fr-list-model.h
- */
-
 /**
  * SECTION: nact_tree_model
  *
@@ -49,7 +45,7 @@
 
 #include <gtk/gtk.h>
 
-#include "nact-main-window.h"
+#include "base-window.h"
 
 G_BEGIN_DECLS
 
@@ -85,10 +81,23 @@ enum {
 	IACTIONS_LIST_N_COLUMN
 };
 
-GType          nact_tree_model_get_type( void );
+/* iter on tree store
+ */
+typedef gboolean ( *FnIterOnStore )( NactTreeModel *, GtkTreePath *, NAObject *, gpointer );
+
+GType   nact_tree_model_get_type( void );
+
+void    nact_tree_model_initial_load( BaseWindow *window, GtkTreeView *treeview );
+void    nact_tree_model_runtime_init( NactTreeModel *model, gboolean have_dnd );
+void    nact_tree_model_dispose( NactTreeModel *model );
 
-NactTreeModel *nact_tree_model_new( NactMainWindow *window );
-void           nact_tree_model_runtime_init_dnd( NactMainWindow *window, GtkTreeView *widget );
+void    nact_tree_model_dump( NactTreeModel *model );
+void    nact_tree_model_fill( NactTreeModel *model, GSList *items, gboolean only_actions);
+guint   nact_tree_model_get_items_count( NactTreeModel *model );
+void    nact_tree_model_insert_item( NactTreeModel *model, const NAObject *object, GtkTreePath *path, const NAObject *selected, GtkTreeIter *iter );
+void    nact_tree_model_iter( NactTreeModel *model, FnIterOnStore fn, gpointer user_data );
+GSList *nact_tree_model_remove( NactTreeModel *model, GList *selected );
+void    nact_tree_model_update_parent( NactTreeModel *model, const NAObject *object );
 
 G_END_DECLS
 
diff --git a/src/nact/nact-window.c b/src/nact/nact-window.c
index 8282db4..5405b1a 100644
--- a/src/nact/nact-window.c
+++ b/src/nact/nact-window.c
@@ -35,10 +35,12 @@
 #include <glib.h>
 #include <glib/gi18n.h>
 
+#include <common/na-object-api.h>
+#include <common/na-iprefs.h>
 #include <common/na-iio-provider.h>
+#include <common/na-utils.h>
 
 #include "nact-application.h"
-#include "nact-iprefs.h"
 #include "nact-window.h"
 
 /* private class data
@@ -51,31 +53,17 @@ struct NactWindowClassPrivate {
  */
 struct NactWindowPrivate {
 	gboolean dispose_has_run;
-	GSList  *signals;
 };
 
-/* connected signal, to be disconnected at NactWindow dispose
- */
-typedef struct {
-	gpointer instance;
-	gulong   handler_id;
-}
-	NactWindowRecordedSignal;
-
-static GObjectClass *st_parent_class = NULL;
-static gboolean      st_debug_signal_connect = FALSE;
+static BaseWindowClass *st_parent_class = NULL;
 
-static GType    register_type( void );
-static void     class_init( NactWindowClass *klass );
-static void     iprefs_iface_init( NactIPrefsInterface *iface );
-static void     instance_init( GTypeInstance *instance, gpointer klass );
-static void     instance_dispose( GObject *application );
-static void     instance_finalize( GObject *application );
+static GType  register_type( void );
+static void   class_init( NactWindowClass *klass );
+static void   instance_init( GTypeInstance *instance, gpointer klass );
+static void   instance_dispose( GObject *application );
+static void   instance_finalize( GObject *application );
 
-static gchar   *v_get_iprefs_window_id( NactWindow *window );
-
-static void     on_runtime_init_toplevel( BaseWindow *window );
-static void     on_all_widgets_showed( BaseWindow *dialog );
+static void   do_edition_field_modified( NactWindow *window, gpointer user_data );
 
 GType
 nact_window_get_type( void )
@@ -107,18 +95,10 @@ register_type( void )
 		( GInstanceInitFunc ) instance_init
 	};
 
-	static const GInterfaceInfo prefs_iface_info = {
-		( GInterfaceInitFunc ) iprefs_iface_init,
-		NULL,
-		NULL
-	};
-
 	g_debug( "%s", thisfn );
 
 	type = g_type_register_static( BASE_WINDOW_TYPE, "NactWindow", &info, 0 );
 
-	g_type_add_interface_static( type, NACT_IPREFS_TYPE, &prefs_iface_info );
-
 	return( type );
 }
 
@@ -127,7 +107,6 @@ class_init( NactWindowClass *klass )
 {
 	static const gchar *thisfn = "nact_window_class_init";
 	GObjectClass *object_class;
-	BaseWindowClass *base_class;
 
 	g_debug( "%s: klass=%p", thisfn, ( void * ) klass );
 
@@ -139,21 +118,7 @@ class_init( NactWindowClass *klass )
 
 	klass->private = g_new0( NactWindowClassPrivate, 1 );
 
-	base_class = BASE_WINDOW_CLASS( klass );
-	base_class->runtime_init_toplevel = on_runtime_init_toplevel;
-	base_class->all_widgets_showed = on_all_widgets_showed;
-
-	klass->get_iprefs_window_id = v_get_iprefs_window_id;
-}
-
-static void
-iprefs_iface_init( NactIPrefsInterface *iface )
-{
-	static const gchar *thisfn = "nact_window_iprefs_iface_init";
-
-	g_debug( "%s: iface=%p", thisfn, ( void * ) iface );
-
-	iface->get_iprefs_window_id = v_get_iprefs_window_id;
+	klass->edition_field_modified = do_edition_field_modified;
 }
 
 static void
@@ -170,7 +135,6 @@ instance_init( GTypeInstance *instance, gpointer klass )
 	self->private = g_new0( NactWindowPrivate, 1 );
 
 	self->private->dispose_has_run = FALSE;
-	self->private->signals = NULL;
 }
 
 static void
@@ -178,7 +142,6 @@ instance_dispose( GObject *window )
 {
 	static const gchar *thisfn = "nact_window_instance_dispose";
 	NactWindow *self;
-	GSList *is;
 
 	g_debug( "%s: window=%p", thisfn, ( void * ) window );
 
@@ -189,20 +152,10 @@ instance_dispose( GObject *window )
 
 		self->private->dispose_has_run = TRUE;
 
-		nact_iprefs_save_window_position( NACT_WINDOW( window ));
-
-		for( is = self->private->signals ; is ; is = is->next ){
-			NactWindowRecordedSignal *str = ( NactWindowRecordedSignal * ) is->data;
-			g_signal_handler_disconnect( str->instance, str->handler_id );
-			if( st_debug_signal_connect ){
-				g_debug( "%s: disconnecting signal handler %p:%lu", thisfn, str->instance, str->handler_id );
-			}
-			g_free( str );
-		}
-		g_slist_free( self->private->signals );
-
 		/* chain up to the parent class */
-		G_OBJECT_CLASS( st_parent_class )->dispose( window );
+		if( G_OBJECT_CLASS( st_parent_class )->dispose ){
+			G_OBJECT_CLASS( st_parent_class )->dispose( window );
+		}
 	}
 }
 
@@ -220,7 +173,7 @@ instance_finalize( GObject *window )
 	g_free( self->private );
 
 	/* chain call to parent class */
-	if( st_parent_class->finalize ){
+	if( G_OBJECT_CLASS( st_parent_class )->finalize ){
 		G_OBJECT_CLASS( st_parent_class )->finalize( window );
 	}
 }
@@ -234,7 +187,7 @@ nact_window_get_pivot( NactWindow *window )
 	NactApplication *application;
 	NAPivot *pivot;
 
-	g_object_get( G_OBJECT( window ), PROP_WINDOW_APPLICATION_STR, &application, NULL );
+	g_object_get( G_OBJECT( window ), BASE_WINDOW_PROP_APPLICATION, &application, NULL );
 	g_return_val_if_fail( NACT_IS_APPLICATION( application ), NULL );
 
 	pivot = nact_application_get_pivot( application );
@@ -244,32 +197,38 @@ nact_window_get_pivot( NactWindow *window )
 }
 
 /**
- * Saves a modified action to the I/O storage subsystem.
+ * nact_window_save_object_item:
+ * @window: this #NactWindow instance.
+ * @item: the #NAObjectItem to be saved.
  *
- * @window: this NactWindow object.
+ * Saves a modified item (action or menu) to the I/O storage subsystem.
+ *
+ * An action is always written at once, with all its profiles.
  *
- * @action: the modified action.
+ * Writing a menu only involves writing its NAObjectItem properties,
+ * along with the list and the order of its subitems.
  */
 gboolean
-nact_window_save_action( NactWindow *window, NAAction *action )
+nact_window_save_object_item( NactWindow *window, NAObjectItem *item )
 {
 	static const gchar *thisfn = "nact_window_save_action";
 	NAPivot *pivot;
 	gchar *msg = NULL;
 	guint ret;
 
-	g_debug( "%s: window=%p, action=%p", thisfn, ( void * ) window, ( void * ) action );
+	g_debug( "%s: window=%p, item=%p", thisfn, ( void * ) window, ( void * ) item );
 
 	pivot = nact_window_get_pivot( window );
 	g_assert( NA_IS_PIVOT( pivot ));
 
-	na_object_dump( NA_OBJECT( action ));
+	na_object_dump( item );
+
+	ret = na_pivot_write_item( pivot, NA_OBJECT( item ), &msg );
 
-	ret = na_pivot_write_action( pivot, action, &msg );
 	if( msg ){
 		base_window_error_dlg(
 				BASE_WINDOW( window ),
-				GTK_MESSAGE_WARNING, _( "An error has occured when trying to save the action" ), msg );
+				GTK_MESSAGE_WARNING, _( "An error has occured when trying to save the item" ), msg );
 		g_free( msg );
 	}
 
@@ -277,32 +236,33 @@ nact_window_save_action( NactWindow *window, NAAction *action )
 }
 
 /**
- * Deleted an action from the I/O storage subsystem.
- *
- * @window: this NactWindow object.
+ * nact_window_delete_object_item:
+ * @window: this #NactWindow object.
+ * @item: the item (action or menu) to delete.
  *
- * @action: the action to delete.
+ * Deleted an item from the I/O storage subsystem.
  */
 gboolean
-nact_window_delete_action( NactWindow *window, NAAction *action )
+nact_window_delete_object_item( NactWindow *window, NAObjectItem *item )
 {
-	static const gchar *thisfn = "nact_window_delete_action";
+	static const gchar *thisfn = "nact_window_delete_object_item";
 	NAPivot *pivot;
 	gchar *msg = NULL;
 	guint ret;
 
-	g_debug( "%s: window=%p, action=%p", thisfn, ( void * ) window, ( void * ) action );
+	g_debug( "%s: window=%p, item=%p", thisfn, ( void * ) window, ( void * ) item );
 
 	pivot = nact_window_get_pivot( window );
 	g_assert( NA_IS_PIVOT( pivot ));
 
-	na_object_dump( NA_OBJECT( action ));
+	na_object_dump( item );
+
+	ret = na_pivot_delete_item( pivot, NA_OBJECT( item ), &msg );
 
-	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 );
+				GTK_MESSAGE_WARNING, _( "An error has occured when trying to delete the item" ), msg );
 		g_free( msg );
 	}
 
@@ -310,6 +270,43 @@ nact_window_delete_action( NactWindow *window, NAAction *action )
 }
 
 /**
+ * nact_window_write_level_zero:
+ * @window: this #NactWindow-derived instance.
+ * @items: full current tree of items in #NactIActionsList treeview.
+ *
+ * Writes as a GConf preference order and content of level zero items
+ * if it has been modified.
+ */
+void
+nact_window_write_level_zero( NactWindow *window, GSList *items )
+{
+	GSList *it;
+	gboolean modified;
+	gchar *id;
+	GSList *content;
+	NactApplication *application;
+	NAPivot *pivot;
+
+	modified = FALSE;
+	for( it = items ; it && !modified ; it = it->next ){
+		modified = na_object_is_modified( it->data );
+	}
+
+	if( modified ){
+		content = NULL;
+		for( it = items ; it && !modified ; it = it->next ){
+			id = na_object_get_id( it->data );
+			content = g_slist_prepend( content, id );
+		}
+		content = g_slist_reverse( content );
+		application = NACT_APPLICATION( base_window_get_application( BASE_WINDOW( window )));
+		pivot = nact_application_get_pivot( application );
+		na_iprefs_set_level_zero_items( NA_IPREFS( pivot ), content );
+		na_utils_free_string_list( content );
+	}
+}
+
+/**
  * Emits a warning if the action has been modified.
  *
  * @window: this NactWindow object.
@@ -346,72 +343,11 @@ nact_window_warn_count_modified( NactWindow *window, gint count )
 	return( ok );
 }
 
-/**
- * Records a connected signal, to be disconnected at NactWindow dispose.
+/*
+ * default implementation of "nact-signal-edition-field-modified" signal
+ * does nothing here
  */
-void
-nact_window_signal_connect( NactWindow *window, GObject *instance, const gchar *signal, GCallback fn )
-{
-	static const gchar *thisfn = "nact_window_signal_connect";
-
-	gulong handler_id = g_signal_connect( instance, signal, fn, window );
-
-	NactWindowRecordedSignal *str = g_new0( NactWindowRecordedSignal, 1 );
-	str->instance = instance;
-	str->handler_id = handler_id;
-	window->private->signals = g_slist_prepend( window->private->signals, str );
-
-	if( st_debug_signal_connect ){
-		g_debug( "%s: connecting signal handler %p:%lu", thisfn, ( void * ) instance, handler_id );
-	}
-}
-
-void
-nact_window_signal_connect_by_name( NactWindow *window, const gchar *name, const gchar *signal, GCallback fn )
-{
-	GtkWidget *widget = base_window_get_widget( BASE_WINDOW( window ), name );
-	if( GTK_IS_WIDGET( widget )){
-		nact_window_signal_connect( window, G_OBJECT( widget ), signal, fn );
-	}
-}
-
-static gchar *
-v_get_iprefs_window_id( NactWindow *window )
-{
-	g_assert( NACT_IS_IPREFS( window ));
-
-	if( NACT_WINDOW_GET_CLASS( window )->get_iprefs_window_id ){
-		return( NACT_WINDOW_GET_CLASS( window )->get_iprefs_window_id( window ));
-	}
-
-	return( NULL );
-}
-
-static void
-on_runtime_init_toplevel( BaseWindow *window )
-{
-	static const gchar *thisfn = "nact_window_on_runtime_init_toplevel";
-
-	/* call parent class at the very beginning */
-	if( BASE_WINDOW_CLASS( st_parent_class )->runtime_init_toplevel ){
-		BASE_WINDOW_CLASS( st_parent_class )->runtime_init_toplevel( window );
-	}
-
-	g_debug( "%s: window=%p", thisfn, ( void * ) window );
-	g_assert( NACT_IS_WINDOW( window ));
-
-	nact_iprefs_position_window( NACT_WINDOW( window ));
-}
-
 static void
-on_all_widgets_showed( BaseWindow *dialog )
+do_edition_field_modified( NactWindow *window, gpointer user_data )
 {
-	static const gchar *thisfn = "nact_window_on_all_widgets_showed";
-
-	/* call parent class at the very beginning */
-	if( BASE_WINDOW_CLASS( st_parent_class )->all_widgets_showed ){
-		BASE_WINDOW_CLASS( st_parent_class )->all_widgets_showed( dialog );
-	}
-
-	g_debug( "%s: dialog=%p", thisfn, ( void * ) dialog );
 }
diff --git a/src/nact/nact-window.h b/src/nact/nact-window.h
index 67279a2..36b50e6 100644
--- a/src/nact/nact-window.h
+++ b/src/nact/nact-window.h
@@ -38,9 +38,9 @@
  * It is a common base class for all Nautilus Actions window documents.
  */
 
-#include <common/na-action.h>
-#include <common/na-action-menu.h>
-#include <common/na-action-profile.h>
+#include <common/na-obj-action.h>
+#include <common/na-obj-menu.h>
+#include <common/na-obj-profile.h>
 #include <common/na-pivot.h>
 
 #include "base-window.h"
@@ -68,9 +68,13 @@ typedef struct {
 	BaseWindowClass         parent;
 	NactWindowClassPrivate *private;
 
-	/* api */
-	gchar *  ( *get_iprefs_window_id )( NactWindow *window );
-	void     ( *set_current_action )  ( NactWindow *window, const NAAction *action );
+	/**
+	 * edition_field_modified
+	 *
+	 * virtual handler for "nact-signal-edition-field-modified" signal
+	 * default implementation does nothing
+	 */
+	void    ( *edition_field_modified )( NactWindow *window, gpointer user_data );
 }
 	NactWindowClass;
 
@@ -79,13 +83,12 @@ GType    nact_window_get_type( void );
 NAPivot *nact_window_get_pivot( NactWindow *window );
 
 /*void     nact_window_set_current_action( NactWindow *window, const NAAction *action );*/
-gboolean nact_window_save_action( NactWindow *window, NAAction *action );
-gboolean nact_window_delete_action( NactWindow *window, NAAction *action );
+gboolean nact_window_save_object_item( NactWindow *window, NAObjectItem *item );
+gboolean nact_window_delete_object_item( NactWindow *window, NAObjectItem *item );
 
-gboolean nact_window_warn_count_modified( NactWindow *window, gint count );
+void     nact_window_write_level_zero( NactWindow *window, GSList *items );
 
-void     nact_window_signal_connect( NactWindow *window, GObject *instance, const gchar *signal, GCallback fn );
-void     nact_window_signal_connect_by_name( NactWindow *window, const gchar *name, const gchar *signal, GCallback fn );
+gboolean nact_window_warn_count_modified( NactWindow *window, gint count );
 
 G_END_DECLS
 
diff --git a/src/nact/nact-xml-reader.c b/src/nact/nact-xml-reader.c
index 246656c..fcdd7cd 100644
--- a/src/nact/nact-xml-reader.c
+++ b/src/nact/nact-xml-reader.c
@@ -38,13 +38,14 @@
 #include <string.h>
 #include <uuid/uuid.h>
 
-#include <common/na-gconf-keys.h>
+#include <common/na-gconf-provider-keys.h>
+#include <common/na-gconf-utils.h>
+#include <common/na-object-api.h>
 #include <common/na-utils.h>
 #include <common/na-xml-names.h>
 
 #include "nact-application.h"
 #include "nact-main-window.h"
-#include "nact-assistant.h"
 #include "nact-xml-reader.h"
 
 /* private class data
@@ -60,14 +61,14 @@ struct NactXMLReaderClassPrivate {
  */
 struct NactXMLReaderPrivate {
 	gboolean         dispose_has_run;
-	NactWindow      *window;
-	NAAction        *action;			/* the action that we will return, or NULL */
+	BaseWindow      *window;
+	NAObjectAction  *action;			/* the action that we will return, or NULL */
 	GSList          *messages;
 	gboolean         uuid_set;			/* set at first uuid, then checked against */
 
 	/* following values are reset at each schema/entry node
 	 */
-	NAActionProfile *profile;			/* profile */
+	NAObjectProfile *profile;			/* profile */
 	gboolean         locale_waited;		/* does this require a locale ? */
 	gboolean         profile_waited;	/* does this entry apply to a profile ? */
 	gboolean         list_waited;
@@ -87,10 +88,10 @@ typedef struct {
 
 static GConfReaderStruct reader_str[] = {
 	{ ACTION_VERSION_ENTRY      , FALSE, FALSE, FALSE, FALSE },
-	{ ACTION_LABEL_ENTRY        , FALSE,  TRUE, FALSE, FALSE },
-	{ ACTION_TOOLTIP_ENTRY      , FALSE,  TRUE, FALSE, FALSE },
-	{ ACTION_ICON_ENTRY         , FALSE, FALSE, FALSE, FALSE },
-	{ ACTION_ENABLED_ENTRY      , FALSE, FALSE, FALSE, FALSE },
+	{ OBJECT_ITEM_LABEL_ENTRY   , FALSE,  TRUE, FALSE, FALSE },
+	{ OBJECT_ITEM_TOOLTIP_ENTRY , FALSE,  TRUE, FALSE, FALSE },
+	{ OBJECT_ITEM_ICON_ENTRY    , FALSE, FALSE, FALSE, FALSE },
+	{ OBJECT_ITEM_ENABLED_ENTRY , FALSE, FALSE, FALSE, FALSE },
 	{ ACTION_PROFILE_LABEL_ENTRY, FALSE,  TRUE,  TRUE, FALSE },
 	{ ACTION_PATH_ENTRY         , FALSE, FALSE,  TRUE, FALSE },
 	{ ACTION_PARAMETERS_ENTRY   , FALSE, FALSE,  TRUE, FALSE },
@@ -123,39 +124,39 @@ static GConfReaderStruct reader_str[] = {
 
 static GObjectClass *st_parent_class = NULL;
 
-static GType            register_type( void );
-static void             class_init( NactXMLReaderClass *klass );
-static void             instance_init( GTypeInstance *instance, gpointer klass );
-static void             instance_dispose( GObject *object );
-static void             instance_finalize( GObject *object );
+static GType    register_type( void );
+static void     class_init( NactXMLReaderClass *klass );
+static void     instance_init( GTypeInstance *instance, gpointer klass );
+static void     instance_dispose( GObject *object );
+static void     instance_finalize( GObject *object );
 
 static NactXMLReader *gconf_reader_new( void );
 
-static void             gconf_reader_parse_schema_root( NactXMLReader *reader, xmlNode *root );
-static void             gconf_reader_parse_schemalist( NactXMLReader *reader, xmlNode *schemalist );
-static gboolean         gconf_reader_parse_schema( NactXMLReader *reader, xmlNode *schema );
-static gboolean         gconf_reader_parse_applyto( NactXMLReader *reader, xmlNode *node );
-static gboolean         gconf_reader_check_for_entry( NactXMLReader *reader, xmlNode *node, const char *entry );
-static gboolean         gconf_reader_parse_locale( NactXMLReader *reader, xmlNode *node );
-static void             gconf_reader_parse_default( NactXMLReader *reader, xmlNode *node );
-static gchar           *get_profile_name_from_schema_key( const gchar *key, const gchar *uuid );
-
-static void             gconf_reader_parse_dump_root( NactXMLReader *reader, xmlNode *root );
-static void             gconf_reader_parse_entrylist( NactXMLReader *reader, xmlNode *entrylist );
-static gboolean         gconf_reader_parse_entry( NactXMLReader *reader, xmlNode *entry );
-static gboolean         gconf_reader_parse_dump_key( NactXMLReader *reader, xmlNode *key );
-static void             gconf_reader_parse_dump_value( NactXMLReader *reader, xmlNode *key );
-static void             gconf_reader_parse_dump_value_list( NactXMLReader *reader, xmlNode *key );
-static gchar           *get_profile_name_from_dump_key( const gchar *key );
-
-static void             apply_values( NactXMLReader *reader );
-static void             add_message( NactXMLReader *reader, const gchar *format, ... );
-static int              strxcmp( const xmlChar *a, const char *b );
-static gchar           *get_uuid_from_key( NactXMLReader *reader, const gchar *key, guint line );
-static gboolean         is_uuid_valid( const gchar *uuid );
-static gchar           *get_entry_from_key( const gchar *key );
-static void             free_reader_values( NactXMLReader *reader );
-static gboolean         action_exists( NactXMLReader *reader, const gchar *uuid );
+static void     gconf_reader_parse_schema_root( NactXMLReader *reader, xmlNode *root );
+static void     gconf_reader_parse_schemalist( NactXMLReader *reader, xmlNode *schemalist );
+static gboolean gconf_reader_parse_schema( NactXMLReader *reader, xmlNode *schema );
+static gboolean gconf_reader_parse_applyto( NactXMLReader *reader, xmlNode *node );
+static gboolean gconf_reader_check_for_entry( NactXMLReader *reader, xmlNode *node, const char *entry );
+static gboolean gconf_reader_parse_locale( NactXMLReader *reader, xmlNode *node );
+static void     gconf_reader_parse_default( NactXMLReader *reader, xmlNode *node );
+static gchar   *get_profile_name_from_schema_key( const gchar *key, const gchar *uuid );
+
+static void     gconf_reader_parse_dump_root( NactXMLReader *reader, xmlNode *root );
+static void     gconf_reader_parse_entrylist( NactXMLReader *reader, xmlNode *entrylist );
+static gboolean gconf_reader_parse_entry( NactXMLReader *reader, xmlNode *entry );
+static gboolean gconf_reader_parse_dump_key( NactXMLReader *reader, xmlNode *key );
+static void     gconf_reader_parse_dump_value( NactXMLReader *reader, xmlNode *key );
+static void     gconf_reader_parse_dump_value_list( NactXMLReader *reader, xmlNode *key );
+static gchar   *get_profile_name_from_dump_key( const gchar *key );
+
+static void     apply_values( NactXMLReader *reader );
+static void     add_message( NactXMLReader *reader, const gchar *format, ... );
+static int      strxcmp( const xmlChar *a, const char *b );
+static gchar   *get_uuid_from_key( NactXMLReader *reader, const gchar *key, guint line );
+static gboolean is_uuid_valid( const gchar *uuid );
+static gchar   *get_entry_from_key( const gchar *key );
+static void     free_reader_values( NactXMLReader *reader );
+static gboolean action_exists( NactXMLReader *reader, const gchar *uuid );
 
 GType
 nact_xml_reader_get_type( void )
@@ -218,7 +219,7 @@ instance_init( GTypeInstance *instance, gpointer klass )
 	NactXMLReader *self;
 
 	g_debug( "%s: instance=%p, klass=%p", thisfn, ( void * ) instance, ( void * ) klass );
-	g_assert( NACT_IS_XML_READER( instance ));
+	g_return_if_fail( NACT_IS_XML_READER( instance ));
 	self = NACT_XML_READER( instance );
 
 	self->private = g_new0( NactXMLReaderPrivate, 1 );
@@ -239,8 +240,8 @@ instance_dispose( GObject *object )
 	static const gchar *thisfn = "nact_xml_reader_instance_dispose";
 	NactXMLReader *self;
 
-	g_assert( NACT_IS_XML_READER( object ));
 	g_debug( "%s: object=%p", thisfn, ( void * ) object );
+	g_return_if_fail( NACT_IS_XML_READER( object ));
 	self = NACT_XML_READER( object );
 
 	if( !self->private->dispose_has_run ){
@@ -248,12 +249,14 @@ instance_dispose( GObject *object )
 		self->private->dispose_has_run = TRUE;
 
 		if( self->private->action ){
-			g_assert( NA_IS_ACTION( self->private->action ));
+			g_return_if_fail( NA_IS_OBJECT_ACTION( self->private->action ));
 			g_object_unref( self->private->action );
 		}
 
 		/* chain up to the parent class */
-		G_OBJECT_CLASS( st_parent_class )->dispose( object );
+		if( G_OBJECT_CLASS( st_parent_class )->dispose ){
+			G_OBJECT_CLASS( st_parent_class )->dispose( object );
+		}
 	}
 }
 
@@ -263,8 +266,8 @@ instance_finalize( GObject *object )
 	static const gchar *thisfn = "nact_xml_reader_instance_finalize";
 	NactXMLReader *self;
 
-	g_assert( NACT_IS_XML_READER( object ));
 	g_debug( "%s: object=%p", thisfn, ( void * ) object );
+	g_return_if_fail( NACT_IS_XML_READER( object ));
 	self = NACT_XML_READER( object );
 
 	na_utils_free_string_list( self->private->messages );
@@ -273,7 +276,7 @@ instance_finalize( GObject *object )
 	g_free( self->private );
 
 	/* chain call to parent class */
-	if( st_parent_class->finalize ){
+	if( G_OBJECT_CLASS( st_parent_class )->finalize ){
 		G_OBJECT_CLASS( st_parent_class )->finalize( object );
 	}
 }
@@ -287,20 +290,21 @@ gconf_reader_new( void )
 /**
  * Import the specified file as an NAAction XML description.
  */
-NAAction *
-nact_xml_reader_import( NactWindow *window, const gchar *uri, GSList **msg )
+NAObjectAction *
+nact_xml_reader_import( BaseWindow *window, const gchar *uri, GSList **msg )
 {
 	static const gchar *thisfn = "nact_xml_reader_import";
-	NAAction *action = NULL;
+	NAObjectAction *action = NULL;
 	NactXMLReader *reader;
 	xmlDoc *doc;
 
 	g_debug( "%s: window=%p, uri=%s, msg=%p", thisfn, ( void * ) window, uri, ( void * ) msg );
+	g_return_val_if_fail( BASE_IS_WINDOW( window ), NULL );
 
 	reader = gconf_reader_new();
 	reader->private->window = window;
 
-	g_assert( NACT_IS_ASSISTANT( window ));
+	g_assert( BASE_IS_ASSISTANT( window ));
 
 	doc = xmlParseFile( uri );
 
@@ -334,7 +338,7 @@ nact_xml_reader_import( NactWindow *window, const gchar *uri, GSList **msg )
 	*msg = na_utils_duplicate_string_list( reader->private->messages );
 
 	if( reader->private->action ){
-		g_assert( NA_IS_ACTION( reader->private->action ));
+		g_assert( NA_IS_OBJECT_ACTION( reader->private->action ));
 		action = g_object_ref( reader->private->action );
 	}
 	g_object_unref( reader );
@@ -388,7 +392,7 @@ gconf_reader_parse_schemalist( NactXMLReader *reader, xmlNode *schema )
 
 	g_debug( "%s: reader=%p, schema=%p", thisfn, ( void * ) reader, ( void * ) schema );
 
-	reader->private->action = na_action_new();
+	reader->private->action = na_object_action_new();
 	reader->private->uuid_set = FALSE;
 
 	for( iter = schema->children ; iter ; iter = iter->next ){
@@ -415,7 +419,7 @@ gconf_reader_parse_schemalist( NactXMLReader *reader, xmlNode *schema )
 	}
 
 	if( ok ){
-		gchar *label = na_action_get_label( reader->private->action );
+		gchar *label = na_object_get_label( reader->private->action );
 		if( !label || !g_utf8_strlen( label, -1 )){
 			add_message( reader, ERR_ACTION_LABEL_NOT_FOUND );
 		}
@@ -615,12 +619,12 @@ gconf_reader_parse_applyto( NactXMLReader *reader, xmlNode *node )
 				ret = FALSE;
 
 			} else {
-				na_action_set_uuid( reader->private->action, uuid );
+				na_object_set_id( reader->private->action, uuid );
 				reader->private->uuid_set = TRUE;
 			}
 
 		} else {
-			gchar *ref = na_action_get_uuid( reader->private->action );
+			gchar *ref = na_object_get_id( reader->private->action );
 			if( g_ascii_strcasecmp(( const gchar * ) uuid, ( const gchar * ) ref )){
 				add_message( reader, ERR_INVALID_UUID, ref, uuid, node->line );
 				ret = FALSE;
@@ -633,12 +637,12 @@ gconf_reader_parse_applyto( NactXMLReader *reader, xmlNode *node )
 		profile = get_profile_name_from_schema_key(( const gchar * ) text, uuid );
 
 		if( profile ){
-			reader->private->profile = NA_ACTION_PROFILE( na_action_get_profile( reader->private->action, profile ));
+			reader->private->profile = NA_OBJECT_PROFILE( na_object_get_item( reader->private->action, profile ));
 
 			if( !reader->private->profile ){
-				reader->private->profile = na_action_profile_new();
-				na_action_profile_set_name( reader->private->profile, profile );
-				na_action_attach_profile( reader->private->action, reader->private->profile );
+				reader->private->profile = na_object_profile_new();
+				na_object_set_id( reader->private->profile, profile );
+				na_object_action_attach_profile( reader->private->action, reader->private->profile );
 			}
 		}
 
@@ -775,7 +779,7 @@ gconf_reader_parse_default( NactXMLReader *reader, xmlNode *node )
 static gchar *
 get_profile_name_from_schema_key( const gchar *key, const gchar *uuid )
 {
-	gchar *prefix = g_strdup_printf( "%s/%s/%s", NA_GCONF_CONFIG_PATH, uuid, ACTION_PROFILE_PREFIX );
+	gchar *prefix = g_strdup_printf( "%s/%s/%s", NA_GCONF_CONFIG_PATH, uuid, OBJECT_PROFILE_PREFIX );
 	gchar *profile_name = NULL;
 	gchar *pos;
 
@@ -835,9 +839,9 @@ gconf_reader_parse_entrylist( NactXMLReader *reader, xmlNode *entrylist )
 
 	g_debug( "%s: reader=%p, entrylist=%p", thisfn, ( void * ) reader, ( void * ) entrylist );
 
-	reader->private->action = na_action_new();
+	reader->private->action = na_object_action_new();
 	path = xmlGetProp( entrylist, ( const xmlChar * ) NACT_GCONF_DUMP_ENTRYLIST_BASE );
-	uuid = na_utils_path_to_key(( const gchar * ) path );
+	uuid = na_gconf_utils_path_to_key(( const gchar * ) path );
 	/*g_debug( "%s: uuid=%s", thisfn, uuid );*/
 
 	if( is_uuid_valid( uuid )){
@@ -845,7 +849,7 @@ gconf_reader_parse_entrylist( NactXMLReader *reader, xmlNode *entrylist )
 			add_message( reader, ERR_UUID_ALREADY_EXISTS, uuid, entrylist->line );
 
 		} else {
-			na_action_set_uuid( reader->private->action, uuid );
+			na_object_set_id( reader->private->action, uuid );
 			reader->private->uuid_set = TRUE;
 		}
 	} else {
@@ -875,7 +879,7 @@ gconf_reader_parse_entrylist( NactXMLReader *reader, xmlNode *entrylist )
 			}
 		}
 
-		label = na_action_get_label( reader->private->action );
+		label = na_object_get_label( reader->private->action );
 		if( !label || !g_utf8_strlen( label, -1 )){
 			add_message( reader, ERR_ACTION_LABEL_NOT_FOUND );
 		}
@@ -999,12 +1003,12 @@ gconf_reader_parse_dump_key( NactXMLReader *reader, xmlNode *node )
 		profile = get_profile_name_from_dump_key(( const gchar * ) text );
 
 		if( profile ){
-			reader->private->profile = na_action_get_profile( reader->private->action, profile );
+			reader->private->profile = NA_OBJECT_PROFILE( na_object_get_item( reader->private->action, profile ));
 
 			if( !reader->private->profile ){
-				reader->private->profile = na_action_profile_new();
-				na_action_profile_set_name( reader->private->profile, profile );
-				na_action_attach_profile( reader->private->action, reader->private->profile );
+				reader->private->profile = na_object_profile_new();
+				na_object_set_id( reader->private->profile, profile );
+				na_object_action_attach_profile( reader->private->action, reader->private->profile );
 			}
 		}
 
@@ -1099,49 +1103,49 @@ apply_values( NactXMLReader *reader )
 
 	if( reader->private->entry && strlen( reader->private->entry )){
 		if( !strcmp( reader->private->entry, ACTION_VERSION_ENTRY )){
-			na_action_set_version( reader->private->action, reader->private->value );
+			na_object_action_set_version( reader->private->action, reader->private->value );
 
-		} else if( !strcmp( reader->private->entry, ACTION_LABEL_ENTRY )){
-			na_action_set_label( reader->private->action, reader->private->value );
+		} else if( !strcmp( reader->private->entry, OBJECT_ITEM_LABEL_ENTRY )){
+			na_object_set_label( reader->private->action, reader->private->value );
 
-		} else if( !strcmp( reader->private->entry, ACTION_TOOLTIP_ENTRY )){
-			na_action_set_tooltip( reader->private->action, reader->private->value );
+		} else if( !strcmp( reader->private->entry, OBJECT_ITEM_TOOLTIP_ENTRY )){
+			na_object_set_tooltip( reader->private->action, reader->private->value );
 
-		} else if( !strcmp( reader->private->entry, ACTION_ICON_ENTRY )){
-			na_action_set_icon( reader->private->action, reader->private->value );
+		} else if( !strcmp( reader->private->entry, OBJECT_ITEM_ICON_ENTRY )){
+			na_object_set_icon( reader->private->action, reader->private->value );
 
-		} else if( !strcmp( reader->private->entry, ACTION_ENABLED_ENTRY )){
-			na_action_set_enabled( reader->private->action, na_utils_schema_to_boolean( reader->private->value, TRUE ));
+		} else if( !strcmp( reader->private->entry, OBJECT_ITEM_ENABLED_ENTRY )){
+			na_object_set_enabled( NA_OBJECT_ITEM( reader->private->action ), na_utils_schema_to_boolean( reader->private->value, TRUE ));
 
 		} else if( !strcmp( reader->private->entry, ACTION_PROFILE_LABEL_ENTRY )){
-			na_action_profile_set_label( reader->private->profile, reader->private->value );
+			na_object_set_label( reader->private->profile, reader->private->value );
 
 		} else if( !strcmp( reader->private->entry, ACTION_PATH_ENTRY )){
-			na_action_profile_set_path( reader->private->profile, reader->private->value );
+			na_object_profile_set_path( reader->private->profile, reader->private->value );
 
 		} else if( !strcmp( reader->private->entry, ACTION_PARAMETERS_ENTRY )){
-			na_action_profile_set_parameters( reader->private->profile, reader->private->value );
+			na_object_profile_set_parameters( reader->private->profile, reader->private->value );
 
 		} else if( !strcmp( reader->private->entry, ACTION_BASENAMES_ENTRY )){
-			na_action_profile_set_basenames( reader->private->profile, reader->private->list_value );
+			na_object_profile_set_basenames( reader->private->profile, reader->private->list_value );
 
 		} else if( !strcmp( reader->private->entry, ACTION_MATCHCASE_ENTRY )){
-			na_action_profile_set_matchcase( reader->private->profile, na_utils_schema_to_boolean( reader->private->value, TRUE ));
+			na_object_profile_set_matchcase( reader->private->profile, na_utils_schema_to_boolean( reader->private->value, TRUE ));
 
 		} else if( !strcmp( reader->private->entry, ACTION_ISFILE_ENTRY )){
-			na_action_profile_set_isfile( reader->private->profile, na_utils_schema_to_boolean( reader->private->value, TRUE ));
+			na_object_profile_set_isfile( reader->private->profile, na_utils_schema_to_boolean( reader->private->value, TRUE ));
 
 		} else if( !strcmp( reader->private->entry, ACTION_ISDIR_ENTRY )){
-			na_action_profile_set_isdir( reader->private->profile, na_utils_schema_to_boolean( reader->private->value, FALSE ));
+			na_object_profile_set_isdir( reader->private->profile, na_utils_schema_to_boolean( reader->private->value, FALSE ));
 
 		} else if( !strcmp( reader->private->entry, ACTION_MULTIPLE_ENTRY )){
-			na_action_profile_set_multiple( reader->private->profile, na_utils_schema_to_boolean( reader->private->value, FALSE ));
+			na_object_profile_set_multiple( reader->private->profile, na_utils_schema_to_boolean( reader->private->value, FALSE ));
 
 		} else if( !strcmp( reader->private->entry, ACTION_MIMETYPES_ENTRY )){
-			na_action_profile_set_mimetypes( reader->private->profile, reader->private->list_value );
+			na_object_profile_set_mimetypes( reader->private->profile, reader->private->list_value );
 
 		} else if( !strcmp( reader->private->entry, ACTION_SCHEMES_ENTRY )){
-			na_action_profile_set_schemes( reader->private->profile, reader->private->list_value );
+			na_object_profile_set_schemes( reader->private->profile, reader->private->list_value );
 
 		} else {
 			g_assert_not_reached();
diff --git a/src/nact/nact-xml-reader.h b/src/nact/nact-xml-reader.h
index 4fc2ff7..a38a08e 100644
--- a/src/nact/nact-xml-reader.h
+++ b/src/nact/nact-xml-reader.h
@@ -34,11 +34,11 @@
 /*
  * NactXMLReader class definition.
  *
- * This is the base class for importing into and exporting from GConf
- * storage subsystem.
+ * This is the base class for importing actions from XML files.
  */
 
-#include "nact-window.h"
+#include "common/na-obj-action-class.h"
+#include "base-assistant.h"
 
 G_BEGIN_DECLS
 
@@ -65,9 +65,9 @@ typedef struct {
 }
 	NactXMLReaderClass;
 
-GType     nact_xml_reader_get_type( void );
+GType           nact_xml_reader_get_type( void );
 
-NAAction *nact_xml_reader_import( NactWindow *window, const gchar *uri, GSList **msg );
+NAObjectAction *nact_xml_reader_import( BaseWindow *window, const gchar *uri, GSList **msg );
 
 G_END_DECLS
 
diff --git a/src/nact/nautilus-actions-config-tool.actions b/src/nact/nautilus-actions-config-tool.actions
index 61ac0d8..b1c1228 100644
--- a/src/nact/nautilus-actions-config-tool.actions
+++ b/src/nact/nautilus-actions-config-tool.actions
@@ -2,14 +2,17 @@
 <ui>
     <menubar name="MainMenubar">
         <menu action="FileMenu">
+            <menuitem action="NewMenuItem" />
             <menuitem action="NewActionItem" />
             <menuitem action="NewProfileItem" />
-            <menuitem action="NewMenuItem" />
             <menuitem action="SaveItem" />
             <separator />
             <menuitem action="QuitItem" />
         </menu>
         <menu action="EditMenu">
+            <menuitem action="CutItem" />
+            <menuitem action="CopyItem" />
+            <menuitem action="PasteItem" />
             <menuitem action="DuplicateItem" />
             <menuitem action="DeleteItem" />
             <separator />
diff --git a/src/nact/nautilus-actions-config-tool.ui b/src/nact/nautilus-actions-config-tool.ui
index 3857952..6d4e72d 100644
--- a/src/nact/nautilus-actions-config-tool.ui
+++ b/src/nact/nautilus-actions-config-tool.ui
@@ -29,7 +29,7 @@
           </packing>
         </child>
         <child>
-          <object class="GtkVBox" id="vbox16">
+          <object class="GtkVBox" id="MainVBox">
             <property name="visible">True</property>
             <child>
               <object class="GtkHPaned" id="MainPaned">
@@ -114,6 +114,7 @@
                                   <object class="GtkLabel" id="ActionLabelLabel">
                                     <property name="visible">True</property>
                                     <property name="xalign">1</property>
+                                    <property name="label" translatable="yes">_Label :</property>
                                     <property name="use_underline">True</property>
                                     <property name="mnemonic_widget">ActionLabelEntry</property>
                                   </object>
@@ -259,7 +260,7 @@
                             <property name="visible">True</property>
                             <property name="spacing">10</property>
                             <child>
-                              <object class="GtkLabel" id="label3">
+                              <object class="GtkLabel" id="ActionPropertiesGroupTitle">
                                 <property name="visible">True</property>
                                 <property name="xalign">0</property>
                                 <property name="label" translatable="yes">&lt;b&gt;Action properties&lt;/b&gt;</property>
@@ -277,7 +278,7 @@
                                 <property name="n_columns">2</property>
                                 <child>
                                   <object class="GtkCheckButton" id="ActionEnabledButton">
-                                    <property name="label" translatable="yes">_Enabled</property>
+                                    <property name="label" translatable="yes">E_nabled</property>
                                     <property name="visible">True</property>
                                     <property name="can_focus">True</property>
                                     <property name="receives_default">False</property>
@@ -385,6 +386,7 @@
                                       <object class="GtkLabel" id="ProfileLabelLabel">
                                         <property name="visible">True</property>
                                         <property name="xalign">1</property>
+                                        <property name="label" translatable="yes">_Label :</property>
                                         <property name="use_underline">True</property>
                                         <property name="mnemonic_widget">ProfileLabelEntry</property>
                                       </object>
@@ -1009,10 +1011,10 @@ Defining several profiles lets you have several commands, each applying with a d
     <child>
       <object class="GtkFileChooserWidget" id="filechooserwidget1">
         <property name="visible">True</property>
-        <property name="select_multiple">True</property>
-        <property name="local_only">False</property>
-        <property name="use_preview_label">False</property>
         <property name="preview_widget_active">False</property>
+        <property name="use_preview_label">False</property>
+        <property name="local_only">False</property>
+        <property name="select_multiple">True</property>
       </object>
     </child>
     <child>
@@ -1115,9 +1117,9 @@ to extend a selection.</property>
         <child>
           <object class="GtkFileChooserWidget" id="ExportFolderChooser">
             <property name="visible">True</property>
-            <property name="local_only">False</property>
-            <property name="use_preview_label">False</property>
             <property name="preview_widget_active">False</property>
+            <property name="use_preview_label">False</property>
+            <property name="local_only">False</property>
             <property name="action">select-folder</property>
           </object>
           <packing>
@@ -1839,16 +1841,16 @@ The exported file may later be imported via :
   </object>
   <object class="GtkSizeGroup" id="CommandLabelSizeGroup">
     <widgets>
-      <widget name="CommandExamplePreLabel"/>
-      <widget name="CommandParametersLabel"/>
-      <widget name="CommandPathLabel"/>
       <widget name="ProfileLabelLabel"/>
+      <widget name="CommandPathLabel"/>
+      <widget name="CommandParametersLabel"/>
+      <widget name="CommandExamplePreLabel"/>
     </widgets>
   </object>
   <object class="GtkSizeGroup" id="CommandButtonSizeGroup">
     <widgets>
-      <widget name="CommandLegendButton"/>
       <widget name="CommandPathButton"/>
+      <widget name="CommandLegendButton"/>
     </widgets>
   </object>
 </interface>
diff --git a/src/plugin/nautilus-actions.c b/src/plugin/nautilus-actions.c
index 711b8a9..cc9f89c 100644
--- a/src/plugin/nautilus-actions.c
+++ b/src/plugin/nautilus-actions.c
@@ -39,11 +39,12 @@
 #include <libnautilus-extension/nautilus-menu-provider.h>
 
 #include <common/na-about.h>
-#include <common/na-action.h>
-#include <common/na-action-profile.h>
+#include <common/na-object-api.h>
+#include <common/na-obj-action.h>
+#include <common/na-obj-profile.h>
 #include <common/na-pivot.h>
-#include <common/na-ipivot-consumer.h>
 #include <common/na-iprefs.h>
+#include <common/na-ipivot-consumer.h>
 
 #include "nautilus-actions.h"
 
@@ -65,18 +66,18 @@ static GType         st_actions_type = 0;
 
 static void              class_init( NautilusActionsClass *klass );
 static void              menu_provider_iface_init( NautilusMenuProviderIface *iface );
-static void              pivot_consumer_iface_init( NAIPivotConsumerInterface *iface );
-static void              prefs_iface_init( NAIPrefsInterface *iface );
+static void              ipivot_consumer_iface_init( NAIPivotConsumerInterface *iface );
+static void              iprefs_iface_init( NAIPrefsInterface *iface );
 static void              instance_init( GTypeInstance *instance, gpointer klass );
 static void              instance_dispose( GObject *object );
 static void              instance_finalize( GObject *object );
 
 static GList            *get_background_items( NautilusMenuProvider *provider, GtkWidget *window, NautilusFileInfo *current_folder );
 static GList            *get_file_items( NautilusMenuProvider *provider, GtkWidget *window, GList *files );
-static NautilusMenuItem *create_menu_item( NAAction *action, NAActionProfile *profile, GList *files );
+static NautilusMenuItem *create_menu_item( NAObjectAction *action, NAObjectProfile *profile, GList *files );
 /*static NautilusMenuItem *create_sub_menu( NautilusMenu **menu );*/
 static void              add_about_item( NautilusMenu *menu );
-static void              execute_action( NautilusMenuItem *item, NAActionProfile *profile );
+static void              execute_action( NautilusMenuItem *item, NAObjectProfile *profile );
 static void              actions_changed_handler( NAIPivotConsumer *instance, gpointer user_data );
 
 GType
@@ -109,14 +110,14 @@ nautilus_actions_register_type( GTypeModule *module )
 		NULL
 	};
 
-	static const GInterfaceInfo pivot_consumer_iface_info = {
-		( GInterfaceInitFunc ) pivot_consumer_iface_init,
+	static const GInterfaceInfo ipivot_consumer_iface_info = {
+		( GInterfaceInitFunc ) ipivot_consumer_iface_init,
 		NULL,
 		NULL
 	};
 
-	static const GInterfaceInfo prefs_iface_info = {
-		( GInterfaceInitFunc ) prefs_iface_init,
+	static const GInterfaceInfo iprefs_iface_info = {
+		( GInterfaceInitFunc ) iprefs_iface_init,
 		NULL,
 		NULL
 	};
@@ -128,9 +129,9 @@ nautilus_actions_register_type( GTypeModule *module )
 
 	g_type_module_add_interface( module, st_actions_type, NAUTILUS_TYPE_MENU_PROVIDER, &menu_provider_iface_info );
 
-	g_type_module_add_interface( module, st_actions_type, NA_IPIVOT_CONSUMER_TYPE, &pivot_consumer_iface_info );
+	g_type_module_add_interface( module, st_actions_type, NA_IPIVOT_CONSUMER_TYPE, &ipivot_consumer_iface_info );
 
-	g_type_module_add_interface( module, st_actions_type, NA_IPREFS_TYPE, &prefs_iface_info );
+	g_type_module_add_interface( module, st_actions_type, NA_IPREFS_TYPE, &iprefs_iface_info );
 }
 
 static void
@@ -162,9 +163,9 @@ menu_provider_iface_init( NautilusMenuProviderIface *iface )
 }
 
 static void
-pivot_consumer_iface_init( NAIPivotConsumerInterface *iface )
+ipivot_consumer_iface_init( NAIPivotConsumerInterface *iface )
 {
-	static const gchar *thisfn = "nautilus_actions_pivot_consumer_iface_init";
+	static const gchar *thisfn = "nautilus_actions_ipivot_consumer_iface_init";
 
 	g_debug( "%s: iface=%p", thisfn, ( void * ) iface );
 
@@ -172,9 +173,9 @@ pivot_consumer_iface_init( NAIPivotConsumerInterface *iface )
 }
 
 static void
-prefs_iface_init( NAIPrefsInterface *iface )
+iprefs_iface_init( NAIPrefsInterface *iface )
 {
-	static const gchar *thisfn = "nautilus_actions_prefs_iface_init";
+	static const gchar *thisfn = "nautilus_actions_iprefs_iface_init";
 
 	g_debug( "%s: iface=%p", thisfn, ( void * ) iface );
 }
@@ -187,14 +188,17 @@ instance_init( GTypeInstance *instance, gpointer klass )
 
 	g_debug( "%s: instance=%p, klass=%p", thisfn, ( void * ) instance, ( void * ) klass );
 
-	g_assert( NAUTILUS_IS_ACTIONS( instance ));
+	g_return_if_fail( NAUTILUS_IS_ACTIONS( instance ));
+	g_return_if_fail( NA_IS_IPIVOT_CONSUMER( instance ));
+
 	self = NAUTILUS_ACTIONS( instance );
 
 	self->private = g_new0( NautilusActionsPrivate, 1 );
 	self->private->dispose_has_run = FALSE;
 
 	/* from na-pivot */
-	self->private->pivot = na_pivot_new( G_OBJECT( self ));
+	self->private->pivot = na_pivot_new( NA_IPIVOT_CONSUMER( self ));
+	na_pivot_set_automatic_reload( self->private->pivot, TRUE );
 }
 
 static void
@@ -208,12 +212,15 @@ instance_dispose( GObject *object )
 	self = NAUTILUS_ACTIONS( object );
 
 	if( !self->private->dispose_has_run ){
-		self->private->dispose_has_run = TRUE;
 
 		g_object_unref( self->private->pivot );
 
 		/* chain up to the parent class */
-		G_OBJECT_CLASS( st_parent_class )->dispose( object );
+		if( G_OBJECT_CLASS( st_parent_class )->dispose ){
+			G_OBJECT_CLASS( st_parent_class )->dispose( object );
+		}
+
+		self->private->dispose_has_run = TRUE;
 	}
 }
 
@@ -230,7 +237,9 @@ instance_finalize( GObject *object )
 	g_free( self->private );
 
 	/* chain up to the parent class */
-	G_OBJECT_CLASS( st_parent_class )->finalize( object );
+	if( G_OBJECT_CLASS( st_parent_class )->finalize ){
+		G_OBJECT_CLASS( st_parent_class )->finalize( object );
+	}
 }
 
 /*
@@ -279,7 +288,7 @@ get_file_items( NautilusMenuProvider *provider, GtkWidget *window, GList *files
 	GSList *ia, *ip;
 	NautilusMenu *menu = NULL;
 	NautilusMenuItem *item;
-	GSList *actions = NULL;
+	GSList *tree = NULL;
 	gchar *label, *uuid;
 	gint submenus = 0;
 	gboolean add_about;
@@ -296,20 +305,20 @@ get_file_items( NautilusMenuProvider *provider, GtkWidget *window, GList *files
 	}
 
 	if( !self->private->dispose_has_run ){
-		actions = na_pivot_get_actions( self->private->pivot );
+		tree = na_pivot_get_items_tree( self->private->pivot );
 
-		for( ia = actions ; ia ; ia = ia->next ){
+		for( ia = tree ; ia ; ia = ia->next ){
 
-			NAAction *action = NA_ACTION( ia->data );
+			NAObjectAction *action = NA_OBJECT_ACTION( ia->data );
 
-			if( !na_action_is_enabled( action )){
+			if( !na_object_is_enabled( action )){
 				continue;
 			}
 
-			label = na_action_get_label( action );
+			label = na_object_get_label( action );
 
 			if( !label || !g_utf8_strlen( label, -1 )){
-				uuid = na_action_get_uuid( action );
+				uuid = na_object_get_id( action );
 				g_warning( "%s: label null or empty for uuid=%s", thisfn, uuid );
 				g_free( uuid );
 				continue;
@@ -318,19 +327,19 @@ get_file_items( NautilusMenuProvider *provider, GtkWidget *window, GList *files
 			g_debug( "%s: examining '%s' action", thisfn, label );
 			g_free( label );
 
-			profiles = na_action_get_profiles( action );
+			profiles = na_object_get_items( action );
 
 			for( ip = profiles ; ip ; ip = ip->next ){
 
-				NAActionProfile *profile = NA_ACTION_PROFILE( ip->data );
+				NAObjectProfile *profile = NA_OBJECT_PROFILE( ip->data );
 
 #ifdef NA_MAINTAINER_MODE
-				label = na_action_profile_get_label( profile );
+				label = na_object_get_label( profile );
 				g_debug( "%s: examining '%s' profile", thisfn, label );
 				g_free( label );
 #endif
 
-				if( na_action_profile_is_candidate( profile, files )){
+				if( na_object_profile_is_candidate( profile, files )){
 					item = create_menu_item( action, profile, files );
 					items = g_list_append( items, item );
 
@@ -345,9 +354,11 @@ get_file_items( NautilusMenuProvider *provider, GtkWidget *window, GList *files
 					break;
 				}
 			}
+
+			na_object_free_items( profiles );
 		}
 
-		add_about = na_iprefs_get_add_about_item( NA_IPREFS( self ));
+		add_about = FALSE; /*na_iprefs_get_add_about_item( NA_IPREFS( self ));*/
 		if( submenus == 1 && add_about ){
 			add_about_item( menu );
 		}
@@ -357,22 +368,22 @@ get_file_items( NautilusMenuProvider *provider, GtkWidget *window, GList *files
 }
 
 static NautilusMenuItem *
-create_menu_item( NAAction *action, NAActionProfile *profile, GList *files )
+create_menu_item( NAObjectAction *action, NAObjectProfile *profile, GList *files )
 {
 	static const gchar *thisfn = "nautilus_actions_create_menu_item";
 	NautilusMenuItem *item;
 	gchar *uuid, *name, *label, *tooltip, *icon_name;
-	NAActionProfile *dup4menu;
+	NAObjectProfile *dup4menu;
 
 	g_debug( "%s", thisfn );
 
-	uuid = na_action_get_uuid( action );
+	uuid = na_object_get_id( action );
 	name = g_strdup_printf( "NautilusActions::%s", uuid );
-	label = na_action_get_label( action );
-	tooltip = na_action_get_tooltip( action );
-	icon_name = na_action_get_verified_icon_name( action );
+	label = na_object_get_label( action );
+	tooltip = na_object_get_tooltip( action );
+	icon_name = na_object_item_get_verified_icon_name( NA_OBJECT_ITEM( action ));
 
-	dup4menu = NA_ACTION_PROFILE( na_object_duplicate( NA_OBJECT( profile )));
+	dup4menu = NA_OBJECT_PROFILE( na_object_duplicate( profile ));
 
 	item = nautilus_menu_item_new( name, label, tooltip, icon_name );
 
@@ -381,14 +392,12 @@ create_menu_item( NAAction *action, NAActionProfile *profile, GList *files )
 				G_CALLBACK( execute_action ),
 				dup4menu,
 				( GClosureNotify ) g_object_unref,
-				0
-	);
+				0 );
 
 	g_object_set_data_full( G_OBJECT( item ),
 			"files",
 			nautilus_file_info_list_copy( files ),
-			( GDestroyNotify ) nautilus_file_info_list_free
-	);
+			( GDestroyNotify ) nautilus_file_info_list_free );
 
 	g_free( icon_name );
 	g_free( tooltip );
@@ -437,8 +446,7 @@ add_about_item( NautilusMenu *menu )
 				G_CALLBACK( na_about_display ),
 				NULL,
 				NULL,
-				0
-	);
+				0 );
 
 	nautilus_menu_append_item( menu, item );
 
@@ -446,7 +454,7 @@ add_about_item( NautilusMenu *menu )
 }
 
 static void
-execute_action( NautilusMenuItem *item, NAActionProfile *profile )
+execute_action( NautilusMenuItem *item, NAObjectProfile *profile )
 {
 	static const gchar *thisfn = "nautilus_actions_execute_action";
 	GList *files;
@@ -457,10 +465,10 @@ execute_action( NautilusMenuItem *item, NAActionProfile *profile )
 
 	files = ( GList* ) g_object_get_data( G_OBJECT( item ), "files" );
 
-	path = na_action_profile_get_path( profile );
+	path = na_object_profile_get_path( profile );
 	cmd = g_string_new( path );
 
-	param = na_action_profile_parse_parameters( profile, files );
+	param = na_object_profile_parse_parameters( profile, files );
 
 	if( param != NULL ){
 		g_string_append_printf( cmd, " %s", param );
@@ -482,7 +490,7 @@ actions_changed_handler( NAIPivotConsumer *instance, gpointer user_data )
 	NautilusActions *self;
 
 	g_debug( "%s: instance=%p, user_data=%p", thisfn, ( void * ) instance, ( void * ) user_data );
-	g_assert( NAUTILUS_IS_ACTIONS( instance ));
+	g_return_if_fail( NAUTILUS_IS_ACTIONS( instance ));
 	self = NAUTILUS_ACTIONS( instance );
 
 	if( !self->private->dispose_has_run ){
diff --git a/src/test/.gitignore b/src/test/.gitignore
index 1b89f0a..e5300ab 100644
--- a/src/test/.gitignore
+++ b/src/test/.gitignore
@@ -1 +1,4 @@
 test-parse-uris
+test-virtuals
+test-virtuals-without-test
+test-iface
diff --git a/src/test/Makefile.am b/src/test/Makefile.am
index 58666f0..fdd0817 100644
--- a/src/test/Makefile.am
+++ b/src/test/Makefile.am
@@ -27,7 +27,10 @@
 #   ... and many others (see AUTHORS)
 
 noinst_PROGRAMS = \
+	test-iface										\
 	test-parse-uris									\
+	test-virtuals									\
+	test-virtuals-without-test						\
 	$(NULL)
 
 AM_CPPFLAGS += \
@@ -37,6 +40,20 @@ AM_CPPFLAGS += \
 	-DG_LOG_DOMAIN=\"${NA_LOGDOMAIN_TEST}\"			\
 	$(NULL)
 
+test_iface_SOURCES = \
+	test-iface.c									\
+	test-iface-iface.c								\
+	test-iface-iface.h								\
+	test-iface-base.c								\
+	test-iface-base.h								\
+	test-iface-derived.c							\
+	test-iface-derived.h							\
+	$(NULL)
+
+test_iface_LDADD = \
+	$(NAUTILUS_ACTIONS_LIBS)						\
+	$(NULL)
+
 test_parse_uris_SOURCES = \
 	test-parse-uris.c								\
 	$(NULL)
@@ -45,3 +62,22 @@ test_parse_uris_LDADD = \
 	$(top_builddir)/src/common/libnact.la			\
 	$(NAUTILUS_ACTIONS_LIBS)						\
 	$(NULL)
+
+test_virtuals_SOURCES = \
+	test-virtuals.c									\
+	$(NULL)
+
+test_virtuals_LDADD = \
+	$(top_builddir)/src/common/libnact.la			\
+	$(NAUTILUS_ACTIONS_LIBS)						\
+	$(NULL)
+
+test_virtuals_without_test_SOURCES = \
+	test-virtuals-without-test.c					\
+	$(NULL)
+
+test_virtuals_Lwithout_test_DADD = \
+	$(top_builddir)/src/common/libnact.la			\
+	$(NAUTILUS_ACTIONS_LIBS)						\
+	$(NULL)
+	
\ No newline at end of file
diff --git a/src/test/test-iface-base.c b/src/test/test-iface-base.c
new file mode 100644
index 0000000..c5120b1
--- /dev/null
+++ b/src/test/test-iface-base.c
@@ -0,0 +1,207 @@
+/*
+ * 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 "test-iface-base.h"
+#include "test-iface-iface.h"
+
+/* private class data
+ */
+struct TestBaseClassPrivate {
+	void *empty;						/* so that gcc -pedantic is happy */
+};
+
+/* private instance data
+ */
+struct TestBasePrivate {
+	gboolean dispose_has_run;
+};
+
+static GObjectClass *st_parent_class = NULL;
+
+static GType register_type( void );
+static void  class_init( TestBaseClass *klass );
+static void  iface_iface_init( TestIFaceInterface *iface );
+static void  instance_init( GTypeInstance *instance, gpointer klass );
+static void  instance_dispose( GObject *object );
+static void  instance_finalize( GObject *object );
+
+static void  iface_fna( TestIFace *object );
+static void  iface_fnb( TestIFace *object );
+
+GType
+test_base_get_type( void )
+{
+	static GType object_type = 0;
+
+	if( !object_type ){
+		object_type = register_type();
+	}
+
+	return( object_type );
+}
+
+static GType
+register_type( void )
+{
+	static const gchar *thisfn = "test_iface_base_register_type";
+	GType type;
+
+	static GTypeInfo info = {
+		sizeof( TestBaseClass ),
+		( GBaseInitFunc ) NULL,
+		( GBaseFinalizeFunc ) NULL,
+		( GClassInitFunc ) class_init,
+		NULL,
+		NULL,
+		sizeof( TestBase ),
+		0,
+		( GInstanceInitFunc ) instance_init
+	};
+
+	static const GInterfaceInfo iface_iface_info = {
+		( GInterfaceInitFunc ) iface_iface_init,
+		NULL,
+		NULL
+	};
+
+	g_debug( "%s", thisfn );
+
+	type = g_type_register_static( G_TYPE_OBJECT, "TestBase", &info, 0 );
+
+	g_type_add_interface_static( type, TEST_IFACE_TYPE, &iface_iface_info );
+
+	return( type );
+}
+
+static void
+class_init( TestBaseClass *klass )
+{
+	static const gchar *thisfn = "test_iface_base_class_init";
+	GObjectClass *object_class;
+
+	g_debug( "%s: klass=%p", thisfn, ( void * ) klass );
+
+	st_parent_class = g_type_class_peek_parent( klass );
+
+	object_class = G_OBJECT_CLASS( klass );
+	object_class->dispose = instance_dispose;
+	object_class->finalize = instance_finalize;
+
+	klass->private = g_new0( TestBaseClassPrivate, 1 );
+}
+
+static void
+iface_iface_init( TestIFaceInterface *iface )
+{
+	static const gchar *thisfn = "test_iface_base_iface_iface_init";
+
+	g_debug( "%s: iface=%p", thisfn, ( void * ) iface );
+
+	iface->fna = iface_fna;
+	iface->fnb = iface_fnb;
+}
+
+static void
+instance_init( GTypeInstance *instance, gpointer klass )
+{
+	static const gchar *thisfn = "test_iface_base_instance_init";
+	TestBase *self;
+
+	g_debug( "%s: instance=%p, klass=%p", thisfn, ( void * ) instance, ( void * ) klass );
+	g_assert( TEST_IS_BASE( instance ));
+	self = TEST_BASE( instance );
+
+	self->private = g_new0( TestBasePrivate, 1 );
+
+	self->private->dispose_has_run = FALSE;
+}
+
+static void
+instance_dispose( GObject *object )
+{
+	static const gchar *thisfn = "test_iface_base_instance_dispose";
+	TestBase *self;
+
+	g_debug( "%s: object=%p", thisfn, ( void * ) object );
+	g_assert( TEST_IS_BASE( object ));
+	self = TEST_BASE( object );
+
+	if( !self->private->dispose_has_run ){
+
+		self->private->dispose_has_run = TRUE;
+
+		/* chain up to the parent class */
+		if( G_OBJECT_CLASS( st_parent_class )->dispose ){
+			G_OBJECT_CLASS( st_parent_class )->dispose( object );
+		}
+	}
+}
+
+static void
+instance_finalize( GObject *object )
+{
+	TestBase *self;
+
+	g_assert( TEST_IS_BASE( object ));
+	self = ( TestBase * ) object;
+
+	g_free( self->private );
+
+	/* chain call to parent class */
+	if( G_OBJECT_CLASS( st_parent_class )->finalize ){
+		G_OBJECT_CLASS( st_parent_class )->finalize( object );
+	}
+}
+
+TestBase *
+test_base_new( void )
+{
+	TestBase *object = g_object_new( TEST_BASE_TYPE, NULL );
+
+	return( object );
+}
+
+static void
+iface_fna( TestIFace *object )
+{
+	static const gchar *thisfn = "test_iface_base_iface_fna";
+	g_debug( "%s: %s at %p", thisfn, G_OBJECT_TYPE_NAME( object ), ( void * ) object );
+}
+
+static void
+iface_fnb( TestIFace *object )
+{
+	static const gchar *thisfn = "test_iface_base_iface_fnb";
+	g_debug( "%s: %s at %p", thisfn, G_OBJECT_TYPE_NAME( object ), ( void * ) object );
+}
diff --git a/src/common/na-gconf.h b/src/test/test-iface-base.h
similarity index 53%
rename from src/common/na-gconf.h
rename to src/test/test-iface-base.h
index 0a96487..375566d 100644
--- a/src/common/na-gconf.h
+++ b/src/test/test-iface-base.h
@@ -28,49 +28,48 @@
  *   ... and many others (see AUTHORS)
  */
 
-#ifndef __NA_GCONF_H__
-#define __NA_GCONF_H__
+#ifndef __TEST_IFACE_BASE_H__
+#define __TEST_IFACE_BASE_H__
 
 /**
- * SECTION: na_gconf
- * @short_description: #NAGConf class definition.
- * @include: common/na-gconf.h
+ * SECTION: test_iface_base
+ * @short_description: #TestBase class definition.
+ * @include: test-iface-base.h
  *
- * This class manages the GConf I/O storage subsystem.
- * It should only be used through the NAIIOProvider interface.
+ * A base class which implements TestIFace interface.
  */
 
 #include <glib-object.h>
 
 G_BEGIN_DECLS
 
-#define NA_GCONF_TYPE					( na_gconf_get_type())
-#define NA_GCONF( object )				( G_TYPE_CHECK_INSTANCE_CAST( object, NA_GCONF_TYPE, NAGConf ))
-#define NA_GCONF_CLASS( klass )			( G_TYPE_CHECK_CLASS_CAST( klass, NA_GCONF_TYPE, NAGConfClass ))
-#define NA_IS_GCONF( object )			( G_TYPE_CHECK_INSTANCE_TYPE( object, NA_GCONF_TYPE ))
-#define NA_IS_GCONF_CLASS( klass )		( G_TYPE_CHECK_CLASS_TYPE(( klass ), NA_GCONF_TYPE ))
-#define NA_GCONF_GET_CLASS( object )	( G_TYPE_INSTANCE_GET_CLASS(( object ), NA_GCONF_TYPE, NAGConfClass ))
+#define TEST_BASE_TYPE					( test_base_get_type())
+#define TEST_BASE( object )				( G_TYPE_CHECK_INSTANCE_CAST( object, TEST_BASE_TYPE, TestBase ))
+#define TEST_BASE_CLASS( klass )		( G_TYPE_CHECK_CLASS_CAST( klass, TEST_BASE_TYPE, TestBaseClass ))
+#define TEST_IS_BASE( object )			( G_TYPE_CHECK_INSTANCE_TYPE( object, TEST_BASE_TYPE ))
+#define TEST_IS_BASE_CLASS( klass )		( G_TYPE_CHECK_CLASS_TYPE(( klass ), TEST_BASE_TYPE ))
+#define TEST_BASE_GET_CLASS( object )	( G_TYPE_INSTANCE_GET_CLASS(( object ), TEST_BASE_TYPE, TestBaseClass ))
 
-typedef struct NAGConfPrivate NAGConfPrivate;
+typedef struct TestBasePrivate TestBasePrivate;
 
 typedef struct {
-	GObject         parent;
-	NAGConfPrivate *private;
+	GObject          parent;
+	TestBasePrivate *private;
 }
-	NAGConf;
+	TestBase;
 
-typedef struct NAGConfClassPrivate NAGConfClassPrivate;
+typedef struct TestBaseClassPrivate TestBaseClassPrivate;
 
 typedef struct {
-	GObjectClass         parent;
-	NAGConfClassPrivate *private;
+	GObjectClass          parent;
+	TestBaseClassPrivate *private;
 }
-	NAGConfClass;
+	TestBaseClass;
 
-GType    na_gconf_get_type( void );
+GType     test_base_get_type( void );
 
-NAGConf *na_gconf_new( const GObject *notified );
+TestBase *test_base_new( void );
 
 G_END_DECLS
 
-#endif /* __NA_GCONF_H__ */
+#endif /* __TEST_IFACE_BASE_H__ */
diff --git a/src/test/test-iface-derived.c b/src/test/test-iface-derived.c
new file mode 100644
index 0000000..6f71ddc
--- /dev/null
+++ b/src/test/test-iface-derived.c
@@ -0,0 +1,225 @@
+/*
+ * 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 <string.h>
+
+#include "test-iface-derived.h"
+#include "test-iface-iface.h"
+
+/* private class data
+ */
+struct TestDerivedClassPrivate {
+	void *empty;						/* so that gcc -pedantic is happy */
+};
+
+/* private instance data
+ */
+struct TestDerivedPrivate {
+	gboolean  dispose_has_run;
+};
+
+static TestBaseClass *st_parent_class = NULL;
+
+static GType register_type( void );
+static void  class_init( TestDerivedClass *klass );
+static void  iface_iface_init( TestDerivedClass *klass );
+static void  instance_init( GTypeInstance *instance, gpointer klass );
+static void  instance_dispose( GObject *object );
+static void  instance_finalize( GObject *object );
+
+static void  iface_fna( TestIFace *object );
+static void  iface_fnb( TestIFace *object );
+
+GType
+test_derived_get_type( void )
+{
+	static GType object_type = 0;
+
+	if( !object_type ){
+		object_type = register_type();
+	}
+
+	return( object_type );
+}
+
+static GType
+register_type( void )
+{
+	static const gchar *thisfn = "test_iface_derived_register_type";
+
+	static GTypeInfo info = {
+		sizeof( TestDerivedClass ),
+		( GBaseInitFunc ) NULL,
+		( GBaseFinalizeFunc ) NULL,
+		( GClassInitFunc ) class_init,
+		NULL,
+		NULL,
+		sizeof( TestDerived ),
+		0,
+		( GInstanceInitFunc ) instance_init
+	};
+
+	g_debug( "%s", thisfn );
+
+	return( g_type_register_static( TEST_BASE_TYPE, "TestDerived", &info, 0 ));
+}
+
+static void
+class_init( TestDerivedClass *klass )
+{
+	static const gchar *thisfn = "test_derived_class_init";
+	GObjectClass *object_class;
+
+	g_debug( "%s: klass=%p", thisfn, ( void * ) klass );
+
+	st_parent_class = g_type_class_peek_parent( klass );
+
+	object_class = G_OBJECT_CLASS( klass );
+	object_class->dispose = instance_dispose;
+	object_class->finalize = instance_finalize;
+
+	klass->private = g_new0( TestDerivedClassPrivate, 1 );
+
+	if( 1 ){
+		iface_iface_init( klass );
+	}
+
+	/* there is no error message but this has no effect
+	 * event in a TestDerived object, these are TestBase functions which are called
+	 */
+	if( 0 ){
+		(( TestIFaceInterface * ) klass )->fna = iface_fna;
+		(( TestIFaceInterface * ) klass )->fnb = iface_fnb;
+	}
+}
+
+static void
+iface_iface_init( TestDerivedClass *klass )
+{
+	static const gchar *thisfn = "test_iface_derived_iface_iface_init";
+
+	/* this has the effect of totally overriding the interface api
+	 * and both TestBase and TestDerived objects will only call TestDerived functions
+	 */
+	/*GTypeInterface *iface;
+	iface = g_type_interface_peek( klass, TEST_IFACE_TYPE );
+	g_debug( "%s: iface=%s at %p", thisfn, g_type_name( G_TYPE_FROM_INTERFACE( iface )), ( void * ) iface );
+	(( TestIFaceInterface * ) iface )->fna = iface_fna;
+	(( TestIFaceInterface * ) iface )->fnb = iface_fnb;*/
+
+	GTypeInterface *iface;
+	iface = g_type_interface_peek( klass, TEST_IFACE_TYPE );
+	g_debug( "%s: iface=%p", thisfn, ( void * ) iface );
+	iface = g_type_interface_peek_parent( iface );
+	g_debug( "%s: iface=%p", thisfn, ( void * ) iface );
+	g_debug( "%s: iface=%s at %p", thisfn, g_type_name( G_TYPE_FROM_INTERFACE( iface )), ( void * ) iface );
+	(( TestIFaceInterface * ) iface )->fna = iface_fna;
+	(( TestIFaceInterface * ) iface )->fnb = iface_fnb;
+}
+
+static void
+instance_init( GTypeInstance *instance, gpointer klass )
+{
+	/*static const gchar *thisfn = "test_derived_instance_init";*/
+	TestDerived *self;
+
+	/*g_debug( "%s: instance=%p, klass=%p", thisfn, ( void * ) instance, ( void * ) klass );*/
+	g_assert( TEST_IS_DERIVED( instance ));
+	self = TEST_DERIVED( instance );
+
+	self->private = g_new0( TestDerivedPrivate, 1 );
+
+	self->private->dispose_has_run = FALSE;
+}
+
+static void
+instance_dispose( GObject *object )
+{
+	/*static const gchar *thisfn = "test_derived_instance_dispose";*/
+	TestDerived *self;
+
+	/*g_debug( "%s: object=%p", thisfn, ( void * ) object );*/
+	g_assert( TEST_IS_DERIVED( object ));
+	self = TEST_DERIVED( object );
+
+	if( !self->private->dispose_has_run ){
+
+		self->private->dispose_has_run = TRUE;
+
+		/* chain up to the parent class */
+		if( G_OBJECT_CLASS( st_parent_class )->dispose ){
+			G_OBJECT_CLASS( st_parent_class )->dispose( object );
+		}
+	}
+}
+
+static void
+instance_finalize( GObject *object )
+{
+	/*static const gchar *thisfn = "test_derived_instance_finalize";*/
+	TestDerived *self;
+
+	/*g_debug( "%s: object=%p", thisfn, (void * ) object );*/
+	g_assert( TEST_IS_DERIVED( object ));
+	self = ( TestDerived * ) object;
+
+	g_free( self->private );
+
+	/* chain call to parent class */
+	if( G_OBJECT_CLASS( st_parent_class )->finalize ){
+		G_OBJECT_CLASS( st_parent_class )->finalize( object );
+	}
+}
+
+TestDerived *
+test_derived_new( void )
+{
+	TestDerived *object = g_object_new( TEST_DERIVED_TYPE, NULL );
+
+	return( object );
+}
+
+static void
+iface_fna( TestIFace *object )
+{
+	static const gchar *thisfn = "test_iface_derived_iface_fna";
+	g_debug( "%s: %s at %p", thisfn, G_OBJECT_TYPE_NAME( object ), ( void * ) object );
+}
+
+static void
+iface_fnb( TestIFace *object )
+{
+	static const gchar *thisfn = "test_iface_derived_iface_fnb";
+	g_debug( "%s: %s at %p", thisfn, G_OBJECT_TYPE_NAME( object ), ( void * ) object );
+}
diff --git a/src/test/test-iface-derived.h b/src/test/test-iface-derived.h
new file mode 100644
index 0000000..fad90df
--- /dev/null
+++ b/src/test/test-iface-derived.h
@@ -0,0 +1,76 @@
+/*
+ * 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 __TEST_IFACE_DERIVED_H__
+#define __TEST_IFACE_DERIVED_H__
+
+/**
+ * SECTION: test_iface_derived
+ * @short_description: #TestDerived class definition.
+ * @include: test-iface-derived.h
+ *
+ * Derivation of TestDerived class.
+ * Are we able to define our own implementation of testIFace interface ?
+ */
+
+#include "test-iface-base.h"
+
+G_BEGIN_DECLS
+
+#define TEST_DERIVED_TYPE				( test_derived_get_type())
+#define TEST_DERIVED( object )			( G_TYPE_CHECK_INSTANCE_CAST( object, TEST_DERIVED_TYPE, TestDerived ))
+#define TEST_DERIVED_CLASS( klass )		( G_TYPE_CHECK_CLASS_CAST( klass, TEST_DERIVED_TYPE, TestDerivedClass ))
+#define TEST_IS_DERIVED( object )		( G_TYPE_CHECK_INSTANCE_TYPE( object, TEST_DERIVED_TYPE ))
+#define TEST_IS_DERIVED_CLASS( klass )	( G_TYPE_CHECK_CLASS_TYPE(( klass ), TEST_DERIVED_TYPE ))
+#define TEST_DERIVED_GET_CLASS( object )( G_TYPE_INSTANCE_GET_CLASS(( object ), TEST_DERIVED_TYPE, TestDerivedClass ))
+
+typedef struct TestDerivedPrivate TestDerivedPrivate;
+
+typedef struct {
+	TestBase            parent;
+	TestDerivedPrivate *private;
+}
+	TestDerived;
+
+typedef struct TestDerivedClassPrivate TestDerivedClassPrivate;
+
+typedef struct {
+	TestBaseClass            parent;
+	TestDerivedClassPrivate *private;
+}
+	TestDerivedClass;
+
+GType        test_derived_get_type( void );
+
+TestDerived *test_derived_new( void );
+
+G_END_DECLS
+
+#endif /* __TEST_IFACE_DERIVED_H__ */
diff --git a/src/test/test-iface-iface.c b/src/test/test-iface-iface.c
new file mode 100644
index 0000000..7a79478
--- /dev/null
+++ b/src/test/test-iface-iface.c
@@ -0,0 +1,203 @@
+/*
+ * 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 "test-iface-iface.h"
+#include "test-iface-base.h"
+
+/* private interface data
+ */
+struct TestIFaceInterfacePrivate {
+	void *empty;						/* so that gcc -pedantic is happy */
+};
+
+static GType register_type( void );
+static void  interface_base_init( TestIFaceInterface *klass );
+static void  interface_base_finalize( TestIFaceInterface *klass );
+
+static void  v_fna( TestIFace *object );
+
+static void  do_fna( TestIFace *object );
+
+GType
+test_iface_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 = "test_iface_iface_register_type";
+	GType type;
+
+	static const GTypeInfo info = {
+		sizeof( TestIFaceInterface ),
+		( GBaseInitFunc ) interface_base_init,
+		( GBaseFinalizeFunc ) interface_base_finalize,
+		NULL,
+		NULL,
+		NULL,
+		0,
+		0,
+		NULL
+	};
+
+	g_debug( "%s", thisfn );
+
+	type = g_type_register_static( G_TYPE_INTERFACE, "TestIFace", &info, 0 );
+
+	g_type_interface_add_prerequisite( type, G_TYPE_OBJECT );
+
+	return( type );
+}
+
+static void
+interface_base_init( TestIFaceInterface *klass )
+{
+	static const gchar *thisfn = "test_iface_iface_interface_base_init";
+	static gboolean initialized = FALSE;
+
+	if( !initialized ){
+		g_debug( "%s: klass=%p", thisfn, ( void * ) klass );
+
+		klass->private = g_new0( TestIFaceInterfacePrivate, 1 );
+
+		initialized = TRUE;
+	}
+}
+
+static void
+interface_base_finalize( TestIFaceInterface *klass )
+{
+	static const gchar *thisfn = "test_iface_iface_interface_base_finalize";
+	static gboolean finalized = FALSE ;
+
+	if( !finalized ){
+		finalized = TRUE;
+
+		g_debug( "%s: klass=%p", thisfn, ( void * ) klass );
+
+		g_free( klass->private );
+	}
+}
+
+/*
+ * only call the implementation of the most-derived class (if any)
+ * if the most-derived class has not implemented the function,
+ * then fallback to local default
+ */
+void
+test_iface_fna( TestIFace *object )
+{
+	static const gchar *thisfn = "test_iface_iface_fna";
+	g_debug( "%s: %s at %p", thisfn, G_OBJECT_TYPE_NAME( object ), ( void * ) object );
+	v_fna( object );
+}
+
+static void
+v_fna( TestIFace *object )
+{
+	static const gchar *thisfn = "test_iface_iface_v_fna";
+	g_debug( "%s: %s at %p", thisfn, G_OBJECT_TYPE_NAME( object ), ( void * ) object );
+	if( TEST_IFACE_GET_INTERFACE( object )->fna ){
+		TEST_IFACE_GET_INTERFACE( object )->fna( object );
+	} else {
+		do_fna( object );
+	}
+}
+
+static void
+do_fna( TestIFace *object )
+{
+	static const gchar *thisfn = "test_iface_iface_do_fna";
+	g_debug( "%s: %s at %p", thisfn, G_OBJECT_TYPE_NAME( object ), ( void * ) object );
+}
+
+/*
+ * successively call the implementation (if any) of each derived class
+ * in the hierarchy order, from topmost base class to most-derived class
+ * if any of class in the hierarchy has not implemented the function, the
+ * do nothing and go to next class
+ */
+void
+test_iface_fnb( TestIFace *object )
+{
+	static const gchar *thisfn = "test_iface_iface_fnb";
+	GSList *hierarchy;
+	GObjectClass *class;
+	GType type;
+	GType base_type;
+	GSList *ic;
+	GTypeInterface *iface;
+
+	g_debug( "%s: %s at %p", thisfn, G_OBJECT_TYPE_NAME( object ), ( void * ) object );
+	g_debug( "%s: g_type_from_instance=%u", thisfn, G_TYPE_FROM_INSTANCE( object ));
+	g_debug( "%s: g_type_from_interface=%u", thisfn, G_TYPE_FROM_INTERFACE( object ));
+
+	hierarchy = NULL;
+	base_type = TEST_BASE_TYPE;
+	type = G_OBJECT_TYPE( object );
+	g_debug( "%s: type=%u %s", thisfn, type, G_OBJECT_TYPE_NAME( object ));
+	while( TRUE ){
+		/*hierarchy = g_slist_prepend( hierarchy, class );*/
+		hierarchy = g_slist_prepend( hierarchy, GINT_TO_POINTER( type ));
+		/*type = G_TYPE_FROM_CLASS( class );*/
+		if( type == base_type ){
+			break;
+		}
+		type = g_type_parent( type );
+		if( !type ){
+			g_debug( "%s: GOT ZERO TYPE", thisfn );
+			break;
+		}
+	}
+
+	for( ic = hierarchy ; ic ; ic = ic->next ){
+		type = GPOINTER_TO_INT( ic->data );
+		g_debug( "%s: iterating on %u type", thisfn, type );
+		class = g_type_class_peek_static( type );
+		g_debug( "%s: class is %s at %p", thisfn, G_OBJECT_CLASS_NAME( class ), ( void * ) class );
+		iface = g_type_interface_peek( class, TEST_IFACE_TYPE );
+		g_debug( "%s: iface at %p", thisfn, ( void * ) iface );
+		if( (( TestIFaceInterface * ) iface )->fnb ){
+			(( TestIFaceInterface * ) iface )->fnb( object );
+		}
+	}
+}
diff --git a/src/test/test-iface-iface.h b/src/test/test-iface-iface.h
new file mode 100644
index 0000000..77fe5ab
--- /dev/null
+++ b/src/test/test-iface-iface.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 __TEST_IFACE_IFACE_H__
+#define __TEST_IFACE_IFACE_H__
+
+/**
+ * SECTION: test_iface
+ * @short_description: #TestIFace interface definition.
+ * @include: test-iface-iface.h
+ *
+ * Test to see if a derived class can directly beneficiate of the
+ * interface implemented by its base class, or if we have to implement
+ * virtual functions in the base class.
+ */
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define TEST_IFACE_TYPE						( test_iface_get_type())
+#define TEST_IFACE( object )				( G_TYPE_CHECK_INSTANCE_CAST( object, TEST_IFACE_TYPE, TestIFace ))
+#define TEST_IS_IFACE( object )				( G_TYPE_CHECK_INSTANCE_TYPE( object, TEST_IFACE_TYPE ))
+#define TEST_IFACE_GET_INTERFACE( instance )( G_TYPE_INSTANCE_GET_INTERFACE(( instance ), TEST_IFACE_TYPE, TestIFaceInterface ))
+
+typedef struct TestIFace TestIFace;
+
+typedef struct TestIFaceInterfacePrivate TestIFaceInterfacePrivate;
+
+typedef struct {
+	GTypeInterface             parent;
+	TestIFaceInterfacePrivate *private;
+
+	/**
+	 * fna:
+	 * @target: the #TestIFace target of the copy.
+	 * @source: the #TestIFace source of the copy
+	 *
+	 * Copies data from @source to @ŧarget, so that @target becomes an
+	 * exact copy of @source.
+	 */
+	void ( *fna )( TestIFace *object );
+	void ( *fnb )( TestIFace *object );
+}
+	TestIFaceInterface;
+
+GType test_iface_get_type( void );
+
+void  test_iface_fna( TestIFace *object );
+
+void  test_iface_fnb( TestIFace *object );
+
+G_END_DECLS
+
+#endif /* __TEST_IFACE_IFACE_H__ */
diff --git a/src/test/test-iface.c b/src/test/test-iface.c
new file mode 100755
index 0000000..fd882a2
--- /dev/null
+++ b/src/test/test-iface.c
@@ -0,0 +1,72 @@
+/*
+ * 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)
+ */
+
+/* We verify here that derived class can also use interfaces implemented
+ * in base class.
+ */
+
+#include <glib.h>
+
+#include "test-iface-derived.h"
+#include "test-iface-iface.h"
+
+int
+main( int argc, char **argv )
+{
+	TestBase *base, *base2;
+	TestDerived *derived;
+
+	g_type_init();
+
+	g_debug( "allocating TestBase -------------------------------------" );
+	base = test_base_new();
+	g_debug( "calling test_iface_fna on Base object -------------------" );
+	test_iface_fna( TEST_IFACE( base ));
+	g_debug( "calling test_iface_fnb on Base object -------------------" );
+	test_iface_fnb( TEST_IFACE( base ));
+
+	g_debug( "allocating TestDerived ----------------------------------" );
+	derived = test_derived_new();
+	g_debug( "calling test_iface_fna on Derived object ----------------" );
+	test_iface_fna( TEST_IFACE( derived ));
+	g_debug( "calling test_iface_fnb on Derived object ----------------" );
+	test_iface_fnb( TEST_IFACE( derived ));
+
+	g_debug( "allocating TestBase -------------------------------------" );
+	base2 = test_base_new();
+	g_debug( "calling test_iface_fna on Base object -------------------" );
+	test_iface_fna( TEST_IFACE( base2 ));
+	g_debug( "calling test_iface_fnb on Base object -------------------" );
+	test_iface_fnb( TEST_IFACE( base2 ));
+
+	g_debug( "end -----------------------------------------------------" );
+
+	return( 0 );
+}
diff --git a/src/test/test-virtuals-without-test.c b/src/test/test-virtuals-without-test.c
new file mode 100755
index 0000000..91318d0
--- /dev/null
+++ b/src/test/test-virtuals-without-test.c
@@ -0,0 +1,604 @@
+/*
+ * 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)
+ */
+
+/* We want test here what is the exact behavior of virtual functions in
+ * derived classes, whether or not base class has implemented them or
+ * not.
+ *
+ * We define three classes, and some virtual functions :
+ * class A: fn1, fn2, fn3
+ * class AB: implements fn1, fn2
+ * class ABC: implements fn1, fn3
+ *
+ * Public entry points are defined in class A: we check that calling
+ * public entry points with an object of each class actually calls the
+ * relevant virtual function.
+ *
+ * Also we check that calling the parent class is possible even if the
+ * parent class has not explicitely defined the virtual function.
+ *
+ * Same as test-virtuals.c, without the test for existance of function.
+ */
+
+#include <glib-object.h>
+#include <glib.h>
+
+#define PWI_FIRST_TYPE			( pwi_first_get_type())
+#define PWI_FIRST( object )		( G_TYPE_CHECK_INSTANCE_CAST( object, PWI_FIRST_TYPE, PwiFirst ))
+#define PWI_FIRST_CLASS( klass )	( G_TYPE_CHECK_CLASS_CAST( klass, PWI_FIRST_TYPE, PwiFirstClass ))
+#define PWI_IS_FIRST( object )		( G_TYPE_CHECK_INSTANCE_TYPE( object, PWI_FIRST_TYPE ))
+#define PWI_IS_FIRST_CLASS( klass )	( G_TYPE_CHECK_CLASS_TYPE(( klass ), PWI_FIRST_TYPE ))
+#define PWI_FIRST_GET_CLASS( object )	( G_TYPE_INSTANCE_GET_CLASS(( object ), PWI_FIRST_TYPE, PwiFirstClass ))
+
+typedef struct PwiFirstPrivate PwiFirstPrivate;
+
+typedef struct {
+	GObject          parent;
+	PwiFirstPrivate *private;
+}
+	PwiFirst;
+
+typedef struct PwiFirstClassPrivate PwiFirstClassPrivate;
+
+typedef struct {
+	GObjectClass          parent;
+	PwiFirstClassPrivate *private;
+
+	/* virtual functions */
+	void ( *fn_a )( PwiFirst *instance );
+	void ( *fn_b )( PwiFirst *instance );
+	void ( *fn_c )( PwiFirst *instance );
+}
+	PwiFirstClass;
+
+GType pwi_first_get_type( void );
+
+void pwi_first_fn_a( PwiFirst *instance );
+void pwi_first_fn_b( PwiFirst *instance );
+void pwi_first_fn_c( PwiFirst *instance );
+
+#define PWI_FIRST_SECOND_TYPE			( pwi_first_second_get_type())
+#define PWI_FIRST_SECOND( object )		( G_TYPE_CHECK_INSTANCE_CAST( object, PWI_FIRST_SECOND_TYPE, PwiFirstSecond ))
+#define PWI_FIRST_SECOND_CLASS( klass )		( G_TYPE_CHECK_CLASS_CAST( klass, PWI_FIRST_SECOND_TYPE, PwiFirstSecondClass ))
+#define PWI_IS_FIRST_SECOND( object )		( G_TYPE_CHECK_INSTANCE_TYPE( object, PWI_FIRST_SECOND_TYPE ))
+#define PWI_IS_FIRST_SECOND_CLASS( klass )	( G_TYPE_CHECK_CLASS_TYPE(( klass ), PWI_FIRST_SECOND_TYPE ))
+#define PWI_FIRST_SECOND_GET_CLASS( object )	( G_TYPE_INSTANCE_GET_CLASS(( object ), PWI_FIRST_SECOND_TYPE, PwiFirstSecondClass ))
+
+typedef struct PwiFirstSecondPrivate PwiFirstSecondPrivate;
+
+typedef struct {
+	PwiFirst               parent;
+	PwiFirstSecondPrivate *private;
+}
+	PwiFirstSecond;
+
+typedef struct PwiFirstSecondClassPrivate PwiFirstSecondClassPrivate;
+
+typedef struct {
+	PwiFirstClass               parent;
+	PwiFirstSecondClassPrivate *private;
+}
+	PwiFirstSecondClass;
+
+GType pwi_first_second_get_type( void );
+
+#define PWI_FIRST_SECOND_THREE_TYPE			( pwi_first_second_three_get_type())
+#define PWI_FIRST_SECOND_THREE( object )		( G_TYPE_CHECK_INSTANCE_CAST( object, PWI_FIRST_SECOND_THREE_TYPE, PwiFirstSecondThree ))
+#define PWI_FIRST_SECOND_THREE_CLASS( klass )		( G_TYPE_CHECK_CLASS_CAST( klass, PWI_FIRST_SECOND_THREE_TYPE, PwiFirstSecondThreeClass ))
+#define PWI_IS_FIRST_SECOND_THREE( object )		( G_TYPE_CHECK_INSTANCE_TYPE( object, PWI_FIRST_SECOND_THREE_TYPE ))
+#define PWI_IS_FIRST_SECOND_THREE_CLASS( klass )	( G_TYPE_CHECK_CLASS_TYPE(( klass ), PWI_FIRST_SECOND_THREE_TYPE ))
+#define PWI_FIRST_SECOND_THREE_GET_CLASS( object )	( G_TYPE_INSTANCE_GET_CLASS(( object ), PWI_FIRST_SECOND_THREE_TYPE, PwiFirstSecondThreeClass ))
+
+typedef struct PwiFirstSecondThreePrivate PwiFirstSecondThreePrivate;
+
+typedef struct {
+	PwiFirstSecond              parent;
+	PwiFirstSecondThreePrivate *private;
+}
+	PwiFirstSecondThree;
+
+typedef struct PwiFirstSecondThreeClassPrivate PwiFirstSecondThreeClassPrivate;
+
+typedef struct {
+	PwiFirstSecondClass              parent;
+	PwiFirstSecondThreeClassPrivate *private;
+}
+	PwiFirstSecondThreeClass;
+
+GType pwi_first_second_three_get_type( void );
+
+struct PwiFirstClassPrivate {
+	void *empty;						/* so that gcc -pedantic is happy */
+};
+
+struct PwiFirstPrivate {
+	void *empty;						/* so that gcc -pedantic is happy */
+};
+
+static GObjectClass *st_first_parent_class = NULL;
+
+static GType first_register_type( void );
+static void  first_class_init( PwiFirstClass *klass );
+static void  first_instance_init( GTypeInstance *instance, gpointer klass );
+static void  first_instance_dispose( GObject *application );
+static void  first_instance_finalize( GObject *application );
+
+static void  do_first_fn_a( PwiFirst *instance );
+static void  do_first_fn_b( PwiFirst *instance );
+static void  do_first_fn_c( PwiFirst *instance );
+
+GType
+pwi_first_get_type( void )
+{
+	static GType type = 0;
+
+	if( !type ){
+		type = first_register_type();
+	}
+
+	return( type );
+}
+
+static GType
+first_register_type( void )
+{
+	static const gchar *thisfn = "first_register_type";
+
+	static GTypeInfo info = {
+		sizeof( PwiFirstClass ),
+		( GBaseInitFunc ) NULL,
+		( GBaseFinalizeFunc ) NULL,
+		( GClassInitFunc ) first_class_init,
+		NULL,
+		NULL,
+		sizeof( PwiFirst ),
+		0,
+		( GInstanceInitFunc ) first_instance_init
+	};
+
+	g_debug( "%s", thisfn );
+	return( g_type_register_static( G_TYPE_OBJECT, "PwiFirst", &info, 0 ));
+}
+
+static void
+first_class_init( PwiFirstClass *klass )
+{
+	static const gchar *thisfn = "first_class_init";
+	GObjectClass *object_class;
+
+	g_debug( "%s: klass=%p", thisfn, ( void * ) klass );
+
+	st_first_parent_class = g_type_class_peek_parent( klass );
+
+	object_class = G_OBJECT_CLASS( klass );
+	object_class->dispose = first_instance_dispose;
+	object_class->finalize = first_instance_finalize;
+
+	klass->private = g_new0( PwiFirstClassPrivate, 1 );
+
+	klass->fn_a = do_first_fn_a;
+	klass->fn_b = do_first_fn_b;
+	klass->fn_c = do_first_fn_c;
+}
+
+static void
+first_instance_init( GTypeInstance *instance, gpointer klass )
+{
+	static const gchar *thisfn = "first_instance_init";
+	PwiFirst *self;
+
+	g_debug( "%s: instance=%p, klass=%p", thisfn, ( void * ) instance, ( void * ) klass );
+	g_assert( PWI_IS_FIRST( instance ));
+	self = PWI_FIRST( instance );
+
+	self->private = g_new0( PwiFirstPrivate, 1 );
+}
+
+static void
+first_instance_dispose( GObject *instance )
+{
+	static const gchar *thisfn = "first_instance_dispose";
+	PwiFirst *self;
+
+	g_debug( "%s: instance=%p", thisfn, ( void * ) instance );
+	g_assert( PWI_IS_FIRST( instance ));
+	self = PWI_FIRST( instance );
+
+	/* chain up to the parent class */
+	G_OBJECT_CLASS( st_first_parent_class )->dispose( instance );
+}
+
+static void
+first_instance_finalize( GObject *instance )
+{
+	static const gchar *thisfn = "first_instance_finalize";
+	PwiFirst *self;
+
+	g_debug( "%s: instance=%p", thisfn, ( void * ) instance );
+	g_assert( PWI_IS_FIRST( instance ));
+	self = PWI_FIRST( instance );
+
+	g_free( self->private );
+
+	/* chain call to parent class */
+	G_OBJECT_CLASS( st_first_parent_class )->finalize( instance );
+}
+
+void
+pwi_first_fn_a( PwiFirst *instance )
+{
+	g_debug( "pwi_first_fn_a: instance=%p", ( void * ) instance );
+	g_assert( PWI_IS_FIRST( instance ));
+
+	PWI_FIRST_GET_CLASS( instance )->fn_a( instance );
+}
+
+static void
+do_first_fn_a( PwiFirst *instance )
+{
+	g_debug( "do_first_fn_a: instance=%p", ( void * ) instance );
+}
+
+void
+pwi_first_fn_b( PwiFirst *instance )
+{
+	g_debug( "pwi_first_fn_b: instance=%p", ( void * ) instance );
+	g_assert( PWI_IS_FIRST( instance ));
+
+	PWI_FIRST_GET_CLASS( instance )->fn_b( instance );
+}
+
+static void
+do_first_fn_b( PwiFirst *instance )
+{
+	g_debug( "do_first_fn_b: instance=%p", ( void * ) instance );
+}
+
+void
+pwi_first_fn_c( PwiFirst *instance )
+{
+	g_debug( "pwi_first_fn_c: instance=%p", ( void * ) instance );
+	g_assert( PWI_IS_FIRST( instance ));
+
+	PWI_FIRST_GET_CLASS( instance )->fn_c( instance );
+}
+
+static void
+do_first_fn_c( PwiFirst *instance )
+{
+	g_debug( "do_first_fn_c: instance=%p", ( void * ) instance );
+}
+
+struct PwiFirstSecondClassPrivate {
+	void *empty;						/* so that gcc -pedantic is happy */
+};
+
+struct PwiFirstSecondPrivate {
+	void *empty;						/* so that gcc -pedantic is happy */
+};
+
+static PwiFirstClass *st_first_second_parent_class = NULL;
+
+static GType first_second_register_type( void );
+static void  first_second_class_init( PwiFirstSecondClass *klass );
+static void  first_second_instance_init( GTypeInstance *instance, gpointer klass );
+static void  first_second_instance_dispose( GObject *application );
+static void  first_second_instance_finalize( GObject *application );
+
+static void  do_first_second_fn_a( PwiFirst *instance );
+static void  do_first_second_fn_b( PwiFirst *instance );
+
+GType
+pwi_first_second_get_type( void )
+{
+	static GType type = 0;
+
+	if( !type ){
+		type = first_second_register_type();
+	}
+
+	return( type );
+}
+
+static GType
+first_second_register_type( void )
+{
+	static const gchar *thisfn = "first_second_register_type";
+
+	static GTypeInfo info = {
+		sizeof( PwiFirstSecondClass ),
+		( GBaseInitFunc ) NULL,
+		( GBaseFinalizeFunc ) NULL,
+		( GClassInitFunc ) first_second_class_init,
+		NULL,
+		NULL,
+		sizeof( PwiFirstSecond ),
+		0,
+		( GInstanceInitFunc ) first_second_instance_init
+	};
+
+	g_debug( "%s", thisfn );
+	return( g_type_register_static( PWI_FIRST_TYPE, "PwiFirstSecond", &info, 0 ));
+}
+
+static void
+first_second_class_init( PwiFirstSecondClass *klass )
+{
+	static const gchar *thisfn = "first_second_class_init";
+	GObjectClass *object_class;
+	PwiFirstClass *first_class;
+
+	g_debug( "%s: klass=%p", thisfn, ( void * ) klass );
+
+	st_first_second_parent_class = g_type_class_peek_parent( klass );
+
+	object_class = G_OBJECT_CLASS( klass );
+	object_class->dispose = first_second_instance_dispose;
+	object_class->finalize = first_second_instance_finalize;
+
+	klass->private = g_new0( PwiFirstSecondClassPrivate, 1 );
+
+	first_class = PWI_FIRST_CLASS( klass );
+	first_class->fn_a = do_first_second_fn_a;
+	first_class->fn_b = do_first_second_fn_b;
+	first_class->fn_c = NULL;
+}
+
+static void
+first_second_instance_init( GTypeInstance *instance, gpointer klass )
+{
+	static const gchar *thisfn = "first_second_instance_init";
+	PwiFirstSecond *self;
+
+	g_debug( "%s: instance=%p, klass=%p", thisfn, ( void * ) instance, ( void * ) klass );
+	g_assert( PWI_IS_FIRST_SECOND( instance ));
+	self = PWI_FIRST_SECOND( instance );
+
+	self->private = g_new0( PwiFirstSecondPrivate, 1 );
+}
+
+static void
+first_second_instance_dispose( GObject *instance )
+{
+	static const gchar *thisfn = "first_second_instance_dispose";
+	PwiFirstSecond *self;
+
+	g_debug( "%s: instance=%p", thisfn, ( void * ) instance );
+	g_assert( PWI_IS_FIRST_SECOND( instance ));
+	self = PWI_FIRST_SECOND( instance );
+
+	/* chain up to the parent class */
+	G_OBJECT_CLASS( st_first_second_parent_class )->dispose( instance );
+}
+
+static void
+first_second_instance_finalize( GObject *instance )
+{
+	static const gchar *thisfn = "first_second_instance_finalize";
+	PwiFirstSecond *self;
+
+	g_debug( "%s: instance=%p", thisfn, ( void * ) instance );
+	g_assert( PWI_IS_FIRST_SECOND( instance ));
+	self = PWI_FIRST_SECOND( instance );
+
+	g_free( self->private );
+
+	/* chain call to parent class */
+	G_OBJECT_CLASS( st_first_second_parent_class )->finalize( instance );
+}
+
+static void
+do_first_second_fn_a( PwiFirst *instance )
+{
+	g_debug( "do_first_second_fn_a: instance=%p", ( void * ) instance );
+	PWI_FIRST_CLASS( st_first_second_parent_class )->fn_a( instance );
+}
+
+static void
+do_first_second_fn_b( PwiFirst *instance )
+{
+	g_debug( "do_first_second_fn_b: instance=%p", ( void * ) instance );
+	PWI_FIRST_CLASS( st_first_second_parent_class )->fn_b( instance );
+}
+
+struct PwiFirstSecondThreeClassPrivate {
+	void *empty;						/* so that gcc -pedantic is happy */
+};
+
+struct PwiFirstSecondThreePrivate {
+	void *empty;						/* so that gcc -pedantic is happy */
+};
+
+static PwiFirstSecondClass *st_first_second_three_parent_class = NULL;
+
+static GType first_second_three_register_type( void );
+static void  first_second_three_class_init( PwiFirstSecondThreeClass *klass );
+static void  first_second_three_instance_init( GTypeInstance *instance, gpointer klass );
+static void  first_second_three_instance_dispose( GObject *application );
+static void  first_second_three_instance_finalize( GObject *application );
+
+static void  do_first_second_three_fn_a( PwiFirst *instance );
+static void  do_first_second_three_fn_c( PwiFirst *instance );
+
+GType
+pwi_first_second_three_get_type( void )
+{
+	static GType type = 0;
+
+	if( !type ){
+		type = first_second_three_register_type();
+	}
+
+	return( type );
+}
+
+static GType
+first_second_three_register_type( void )
+{
+	static const gchar *thisfn = "first_second_three_register_type";
+
+	static GTypeInfo info = {
+		sizeof( PwiFirstSecondThreeClass ),
+		( GBaseInitFunc ) NULL,
+		( GBaseFinalizeFunc ) NULL,
+		( GClassInitFunc ) first_second_three_class_init,
+		NULL,
+		NULL,
+		sizeof( PwiFirstSecondThree ),
+		0,
+		( GInstanceInitFunc ) first_second_three_instance_init
+	};
+
+	g_debug( "%s", thisfn );
+	return( g_type_register_static( PWI_FIRST_SECOND_TYPE, "PwiFirstSecondThree", &info, 0 ));
+}
+
+static void
+first_second_three_class_init( PwiFirstSecondThreeClass *klass )
+{
+	static const gchar *thisfn = "first_second_three_class_init";
+	GObjectClass *object_class;
+	PwiFirstClass *first_class;
+
+	g_debug( "%s: klass=%p", thisfn, ( void * ) klass );
+
+	st_first_second_three_parent_class = g_type_class_peek_parent( klass );
+
+	object_class = G_OBJECT_CLASS( klass );
+	object_class->dispose = first_second_three_instance_dispose;
+	object_class->finalize = first_second_three_instance_finalize;
+
+	klass->private = g_new0( PwiFirstSecondThreeClassPrivate, 1 );
+
+	first_class = PWI_FIRST_CLASS( klass );
+	first_class->fn_a = do_first_second_three_fn_a;
+	first_class->fn_b = NULL;
+	first_class->fn_c = do_first_second_three_fn_c;
+}
+
+static void
+first_second_three_instance_init( GTypeInstance *instance, gpointer klass )
+{
+	static const gchar *thisfn = "first_second_three_instance_init";
+	PwiFirstSecondThree *self;
+
+	g_debug( "%s: instance=%p, klass=%p", thisfn, ( void * ) instance, ( void * ) klass );
+	g_assert( PWI_IS_FIRST_SECOND_THREE( instance ));
+	self = PWI_FIRST_SECOND_THREE( instance );
+
+	self->private = g_new0( PwiFirstSecondThreePrivate, 1 );
+}
+
+static void
+first_second_three_instance_dispose( GObject *instance )
+{
+	static const gchar *thisfn = "first_second_three_instance_dispose";
+	PwiFirstSecondThree *self;
+
+	g_debug( "%s: instance=%p", thisfn, ( void * ) instance );
+	g_assert( PWI_IS_FIRST_SECOND_THREE( instance ));
+	self = PWI_FIRST_SECOND_THREE( instance );
+
+	/* chain up to the parent class */
+	G_OBJECT_CLASS( st_first_second_three_parent_class )->dispose( instance );
+}
+
+static void
+first_second_three_instance_finalize( GObject *instance )
+{
+	static const gchar *thisfn = "first_second_three_instance_finalize";
+	PwiFirstSecondThree *self;
+
+	g_debug( "%s: instance=%p", thisfn, ( void * ) instance );
+	g_assert( PWI_IS_FIRST_SECOND_THREE( instance ));
+	self = PWI_FIRST_SECOND_THREE( instance );
+
+	g_free( self->private );
+
+	/* chain call to parent class */
+	G_OBJECT_CLASS( st_first_second_three_parent_class )->finalize( instance );
+}
+
+static void
+do_first_second_three_fn_a( PwiFirst *instance )
+{
+	g_debug( "do_first_second_three_fn_a: instance=%p", ( void * ) instance );
+	PWI_FIRST_CLASS( st_first_second_three_parent_class )->fn_a( instance );
+}
+
+static void
+do_first_second_three_fn_c( PwiFirst *instance )
+{
+	g_debug( "do_first_second_three_fn_c: instance=%p", ( void * ) instance );
+	PWI_FIRST_CLASS( st_first_second_three_parent_class )->fn_c( instance );
+}
+
+int
+main( int argc, char **argv )
+{
+	PwiFirst *a;
+	PwiFirstSecond *b;
+	PwiFirstSecondThree *c;
+
+	g_type_init();
+
+	a = g_object_new( PWI_FIRST_TYPE, NULL );
+	b = g_object_new( PWI_FIRST_SECOND_TYPE, NULL );
+	c = g_object_new( PWI_FIRST_SECOND_THREE_TYPE, NULL );
+
+	g_debug( "expected pwi_first_fn_a, do_first_fn_a" );
+	pwi_first_fn_a( PWI_FIRST( a ));
+	g_debug( "expected pwi_first_fn_a, do_first_second_fn_a, do_first_fn_a" );
+	pwi_first_fn_a( PWI_FIRST( b ));
+	g_debug( "expected pwi_first_fn_a, do_first_second_three_fn_a, do_first_second_fn_a, do_first_fn_a" );
+	pwi_first_fn_a( PWI_FIRST( c ));
+
+	g_debug( "%s", "" );
+
+	g_debug( "expected pwi_first_fn_b, do_first_fn_b" );
+	pwi_first_fn_b( PWI_FIRST( a ));
+	g_debug( "expected pwi_first_fn_b, do_first_second_fn_b, do_first_fn_b" );
+	pwi_first_fn_b( PWI_FIRST( b ));
+	g_debug( "expected pwi_first_fn_b, do_first_second_fn_b, do_first_fn_b" );
+	/* NOT OK
+	 * segmentation fault after pwi_first_fn_b */
+	pwi_first_fn_b( PWI_FIRST( c ));
+
+	g_debug( "%s", "" );
+
+	g_debug( "expected pwi_first_fn_c, do_first_fn_c" );
+	pwi_first_fn_c( PWI_FIRST( a ));
+	g_debug( "expected pwi_first_fn_c, do_first_fn_c" );
+	pwi_first_fn_c( PWI_FIRST( b ));
+	g_debug( "expected pwi_first_fn_c, do_first_second_three_fn_c, do_first_fn_c" );
+	pwi_first_fn_c( PWI_FIRST( c ));
+
+	return( 0 );
+}
diff --git a/src/test/test-virtuals.c b/src/test/test-virtuals.c
new file mode 100755
index 0000000..b59874f
--- /dev/null
+++ b/src/test/test-virtuals.c
@@ -0,0 +1,624 @@
+/*
+ * 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)
+ */
+
+/* We want test here what is the exact behavior of virtual functions in
+ * derived classes, whether or not base class has implemented them or
+ * not.
+ *
+ * We define three classes, and some virtual functions :
+ * class A: fn1, fn2, fn3
+ * class AB: implements fn1, fn2
+ * class ABC: implements fn1, fn3
+ *
+ * Public entry points are defined in class A: we check that calling
+ * public entry points with an object of each class actually calls the
+ * relevant virtual function.
+ *
+ * Also we check that calling the parent class is possible even if the
+ * parent class has not explicitely defined the virtual function.
+ */
+
+#include <glib-object.h>
+#include <glib.h>
+
+#define PWI_FIRST_TYPE			( pwi_first_get_type())
+#define PWI_FIRST( object )		( G_TYPE_CHECK_INSTANCE_CAST( object, PWI_FIRST_TYPE, PwiFirst ))
+#define PWI_FIRST_CLASS( klass )	( G_TYPE_CHECK_CLASS_CAST( klass, PWI_FIRST_TYPE, PwiFirstClass ))
+#define PWI_IS_FIRST( object )		( G_TYPE_CHECK_INSTANCE_TYPE( object, PWI_FIRST_TYPE ))
+#define PWI_IS_FIRST_CLASS( klass )	( G_TYPE_CHECK_CLASS_TYPE(( klass ), PWI_FIRST_TYPE ))
+#define PWI_FIRST_GET_CLASS( object )	( G_TYPE_INSTANCE_GET_CLASS(( object ), PWI_FIRST_TYPE, PwiFirstClass ))
+
+typedef struct PwiFirstPrivate PwiFirstPrivate;
+
+typedef struct {
+	GObject          parent;
+	PwiFirstPrivate *private;
+}
+	PwiFirst;
+
+typedef struct PwiFirstClassPrivate PwiFirstClassPrivate;
+
+typedef struct {
+	GObjectClass          parent;
+	PwiFirstClassPrivate *private;
+
+	/* virtual functions */
+	void ( *fn_a )( PwiFirst *instance );
+	void ( *fn_b )( PwiFirst *instance );
+	void ( *fn_c )( PwiFirst *instance );
+}
+	PwiFirstClass;
+
+GType pwi_first_get_type( void );
+
+void pwi_first_fn_a( PwiFirst *instance );
+void pwi_first_fn_b( PwiFirst *instance );
+void pwi_first_fn_c( PwiFirst *instance );
+
+#define PWI_FIRST_SECOND_TYPE			( pwi_first_second_get_type())
+#define PWI_FIRST_SECOND( object )		( G_TYPE_CHECK_INSTANCE_CAST( object, PWI_FIRST_SECOND_TYPE, PwiFirstSecond ))
+#define PWI_FIRST_SECOND_CLASS( klass )		( G_TYPE_CHECK_CLASS_CAST( klass, PWI_FIRST_SECOND_TYPE, PwiFirstSecondClass ))
+#define PWI_IS_FIRST_SECOND( object )		( G_TYPE_CHECK_INSTANCE_TYPE( object, PWI_FIRST_SECOND_TYPE ))
+#define PWI_IS_FIRST_SECOND_CLASS( klass )	( G_TYPE_CHECK_CLASS_TYPE(( klass ), PWI_FIRST_SECOND_TYPE ))
+#define PWI_FIRST_SECOND_GET_CLASS( object )	( G_TYPE_INSTANCE_GET_CLASS(( object ), PWI_FIRST_SECOND_TYPE, PwiFirstSecondClass ))
+
+typedef struct PwiFirstSecondPrivate PwiFirstSecondPrivate;
+
+typedef struct {
+	PwiFirst               parent;
+	PwiFirstSecondPrivate *private;
+}
+	PwiFirstSecond;
+
+typedef struct PwiFirstSecondClassPrivate PwiFirstSecondClassPrivate;
+
+typedef struct {
+	PwiFirstClass               parent;
+	PwiFirstSecondClassPrivate *private;
+}
+	PwiFirstSecondClass;
+
+GType pwi_first_second_get_type( void );
+
+#define PWI_FIRST_SECOND_THREE_TYPE			( pwi_first_second_three_get_type())
+#define PWI_FIRST_SECOND_THREE( object )		( G_TYPE_CHECK_INSTANCE_CAST( object, PWI_FIRST_SECOND_THREE_TYPE, PwiFirstSecondThree ))
+#define PWI_FIRST_SECOND_THREE_CLASS( klass )		( G_TYPE_CHECK_CLASS_CAST( klass, PWI_FIRST_SECOND_THREE_TYPE, PwiFirstSecondThreeClass ))
+#define PWI_IS_FIRST_SECOND_THREE( object )		( G_TYPE_CHECK_INSTANCE_TYPE( object, PWI_FIRST_SECOND_THREE_TYPE ))
+#define PWI_IS_FIRST_SECOND_THREE_CLASS( klass )	( G_TYPE_CHECK_CLASS_TYPE(( klass ), PWI_FIRST_SECOND_THREE_TYPE ))
+#define PWI_FIRST_SECOND_THREE_GET_CLASS( object )	( G_TYPE_INSTANCE_GET_CLASS(( object ), PWI_FIRST_SECOND_THREE_TYPE, PwiFirstSecondThreeClass ))
+
+typedef struct PwiFirstSecondThreePrivate PwiFirstSecondThreePrivate;
+
+typedef struct {
+	PwiFirstSecond              parent;
+	PwiFirstSecondThreePrivate *private;
+}
+	PwiFirstSecondThree;
+
+typedef struct PwiFirstSecondThreeClassPrivate PwiFirstSecondThreeClassPrivate;
+
+typedef struct {
+	PwiFirstSecondClass              parent;
+	PwiFirstSecondThreeClassPrivate *private;
+}
+	PwiFirstSecondThreeClass;
+
+GType pwi_first_second_three_get_type( void );
+
+struct PwiFirstClassPrivate {
+	void *empty;						/* so that gcc -pedantic is happy */
+};
+
+struct PwiFirstPrivate {
+	void *empty;						/* so that gcc -pedantic is happy */
+};
+
+static GObjectClass *st_first_parent_class = NULL;
+
+static GType first_register_type( void );
+static void  first_class_init( PwiFirstClass *klass );
+static void  first_instance_init( GTypeInstance *instance, gpointer klass );
+static void  first_instance_dispose( GObject *application );
+static void  first_instance_finalize( GObject *application );
+
+static void  do_first_fn_a( PwiFirst *instance );
+static void  do_first_fn_b( PwiFirst *instance );
+static void  do_first_fn_c( PwiFirst *instance );
+
+GType
+pwi_first_get_type( void )
+{
+	static GType type = 0;
+
+	if( !type ){
+		type = first_register_type();
+	}
+
+	return( type );
+}
+
+static GType
+first_register_type( void )
+{
+	static const gchar *thisfn = "first_register_type";
+
+	static GTypeInfo info = {
+		sizeof( PwiFirstClass ),
+		( GBaseInitFunc ) NULL,
+		( GBaseFinalizeFunc ) NULL,
+		( GClassInitFunc ) first_class_init,
+		NULL,
+		NULL,
+		sizeof( PwiFirst ),
+		0,
+		( GInstanceInitFunc ) first_instance_init
+	};
+
+	g_debug( "%s", thisfn );
+	return( g_type_register_static( G_TYPE_OBJECT, "PwiFirst", &info, 0 ));
+}
+
+static void
+first_class_init( PwiFirstClass *klass )
+{
+	static const gchar *thisfn = "first_class_init";
+	GObjectClass *object_class;
+
+	g_debug( "%s: klass=%p", thisfn, ( void * ) klass );
+
+	st_first_parent_class = g_type_class_peek_parent( klass );
+
+	object_class = G_OBJECT_CLASS( klass );
+	object_class->dispose = first_instance_dispose;
+	object_class->finalize = first_instance_finalize;
+
+	klass->private = g_new0( PwiFirstClassPrivate, 1 );
+
+	klass->fn_a = do_first_fn_a;
+	klass->fn_b = do_first_fn_b;
+	klass->fn_c = do_first_fn_c;
+}
+
+static void
+first_instance_init( GTypeInstance *instance, gpointer klass )
+{
+	static const gchar *thisfn = "first_instance_init";
+	PwiFirst *self;
+
+	g_debug( "%s: instance=%p, klass=%p", thisfn, ( void * ) instance, ( void * ) klass );
+	g_assert( PWI_IS_FIRST( instance ));
+	self = PWI_FIRST( instance );
+
+	self->private = g_new0( PwiFirstPrivate, 1 );
+}
+
+static void
+first_instance_dispose( GObject *instance )
+{
+	static const gchar *thisfn = "first_instance_dispose";
+	PwiFirst *self;
+
+	g_debug( "%s: instance=%p", thisfn, ( void * ) instance );
+	g_assert( PWI_IS_FIRST( instance ));
+	self = PWI_FIRST( instance );
+
+	/* chain up to the parent class */
+	G_OBJECT_CLASS( st_first_parent_class )->dispose( instance );
+}
+
+static void
+first_instance_finalize( GObject *instance )
+{
+	static const gchar *thisfn = "first_instance_finalize";
+	PwiFirst *self;
+
+	g_debug( "%s: instance=%p", thisfn, ( void * ) instance );
+	g_assert( PWI_IS_FIRST( instance ));
+	self = PWI_FIRST( instance );
+
+	g_free( self->private );
+
+	/* chain call to parent class */
+	G_OBJECT_CLASS( st_first_parent_class )->finalize( instance );
+}
+
+void
+pwi_first_fn_a( PwiFirst *instance )
+{
+	g_debug( "pwi_first_fn_a: instance=%p", ( void * ) instance );
+	g_assert( PWI_IS_FIRST( instance ));
+
+	if( PWI_FIRST_GET_CLASS( instance )->fn_a ){
+		PWI_FIRST_GET_CLASS( instance )->fn_a( instance );
+	} else {
+		do_first_fn_a( instance );
+	}
+}
+
+static void
+do_first_fn_a( PwiFirst *instance )
+{
+	g_debug( "do_first_fn_a: instance=%p", ( void * ) instance );
+}
+
+void
+pwi_first_fn_b( PwiFirst *instance )
+{
+	g_debug( "pwi_first_fn_b: instance=%p", ( void * ) instance );
+	g_assert( PWI_IS_FIRST( instance ));
+
+	if( PWI_FIRST_GET_CLASS( instance )->fn_b ){
+		PWI_FIRST_GET_CLASS( instance )->fn_b( instance );
+	} else {
+		do_first_fn_b( instance );
+	}
+}
+
+static void
+do_first_fn_b( PwiFirst *instance )
+{
+	g_debug( "do_first_fn_b: instance=%p", ( void * ) instance );
+}
+
+void
+pwi_first_fn_c( PwiFirst *instance )
+{
+	g_debug( "pwi_first_fn_c: instance=%p", ( void * ) instance );
+	g_assert( PWI_IS_FIRST( instance ));
+
+	if( PWI_FIRST_GET_CLASS( instance )->fn_c ){
+		PWI_FIRST_GET_CLASS( instance )->fn_c( instance );
+	} else {
+		do_first_fn_c( instance );
+	}
+}
+
+static void
+do_first_fn_c( PwiFirst *instance )
+{
+	g_debug( "do_first_fn_c: instance=%p", ( void * ) instance );
+}
+
+struct PwiFirstSecondClassPrivate {
+	void *empty;						/* so that gcc -pedantic is happy */
+};
+
+struct PwiFirstSecondPrivate {
+	void *empty;						/* so that gcc -pedantic is happy */
+};
+
+static PwiFirstClass *st_first_second_parent_class = NULL;
+
+static GType first_second_register_type( void );
+static void  first_second_class_init( PwiFirstSecondClass *klass );
+static void  first_second_instance_init( GTypeInstance *instance, gpointer klass );
+static void  first_second_instance_dispose( GObject *application );
+static void  first_second_instance_finalize( GObject *application );
+
+static void  do_first_second_fn_a( PwiFirst *instance );
+static void  do_first_second_fn_b( PwiFirst *instance );
+
+GType
+pwi_first_second_get_type( void )
+{
+	static GType type = 0;
+
+	if( !type ){
+		type = first_second_register_type();
+	}
+
+	return( type );
+}
+
+static GType
+first_second_register_type( void )
+{
+	static const gchar *thisfn = "first_second_register_type";
+
+	static GTypeInfo info = {
+		sizeof( PwiFirstSecondClass ),
+		( GBaseInitFunc ) NULL,
+		( GBaseFinalizeFunc ) NULL,
+		( GClassInitFunc ) first_second_class_init,
+		NULL,
+		NULL,
+		sizeof( PwiFirstSecond ),
+		0,
+		( GInstanceInitFunc ) first_second_instance_init
+	};
+
+	g_debug( "%s", thisfn );
+	return( g_type_register_static( PWI_FIRST_TYPE, "PwiFirstSecond", &info, 0 ));
+}
+
+static void
+first_second_class_init( PwiFirstSecondClass *klass )
+{
+	static const gchar *thisfn = "first_second_class_init";
+	GObjectClass *object_class;
+	PwiFirstClass *first_class;
+
+	g_debug( "%s: klass=%p", thisfn, ( void * ) klass );
+
+	st_first_second_parent_class = g_type_class_peek_parent( klass );
+
+	object_class = G_OBJECT_CLASS( klass );
+	object_class->dispose = first_second_instance_dispose;
+	object_class->finalize = first_second_instance_finalize;
+
+	klass->private = g_new0( PwiFirstSecondClassPrivate, 1 );
+
+	first_class = PWI_FIRST_CLASS( klass );
+	first_class->fn_a = do_first_second_fn_a;
+	first_class->fn_b = do_first_second_fn_b;
+	first_class->fn_c = NULL;
+}
+
+static void
+first_second_instance_init( GTypeInstance *instance, gpointer klass )
+{
+	static const gchar *thisfn = "first_second_instance_init";
+	PwiFirstSecond *self;
+
+	g_debug( "%s: instance=%p, klass=%p", thisfn, ( void * ) instance, ( void * ) klass );
+	g_assert( PWI_IS_FIRST_SECOND( instance ));
+	self = PWI_FIRST_SECOND( instance );
+
+	self->private = g_new0( PwiFirstSecondPrivate, 1 );
+}
+
+static void
+first_second_instance_dispose( GObject *instance )
+{
+	static const gchar *thisfn = "first_second_instance_dispose";
+	PwiFirstSecond *self;
+
+	g_debug( "%s: instance=%p", thisfn, ( void * ) instance );
+	g_assert( PWI_IS_FIRST_SECOND( instance ));
+	self = PWI_FIRST_SECOND( instance );
+
+	/* chain up to the parent class */
+	G_OBJECT_CLASS( st_first_second_parent_class )->dispose( instance );
+}
+
+static void
+first_second_instance_finalize( GObject *instance )
+{
+	static const gchar *thisfn = "first_second_instance_finalize";
+	PwiFirstSecond *self;
+
+	g_debug( "%s: instance=%p", thisfn, ( void * ) instance );
+	g_assert( PWI_IS_FIRST_SECOND( instance ));
+	self = PWI_FIRST_SECOND( instance );
+
+	g_free( self->private );
+
+	/* chain call to parent class */
+	G_OBJECT_CLASS( st_first_second_parent_class )->finalize( instance );
+}
+
+static void
+do_first_second_fn_a( PwiFirst *instance )
+{
+	g_debug( "do_first_second_fn_a: instance=%p", ( void * ) instance );
+	if( PWI_FIRST_CLASS( st_first_second_parent_class )->fn_a ){
+		PWI_FIRST_CLASS( st_first_second_parent_class )->fn_a( instance );
+	}
+}
+
+static void
+do_first_second_fn_b( PwiFirst *instance )
+{
+	g_debug( "do_first_second_fn_b: instance=%p", ( void * ) instance );
+	if( PWI_FIRST_CLASS( st_first_second_parent_class )->fn_b ){
+		PWI_FIRST_CLASS( st_first_second_parent_class )->fn_b( instance );
+	}
+}
+
+struct PwiFirstSecondThreeClassPrivate {
+	void *empty;						/* so that gcc -pedantic is happy */
+};
+
+struct PwiFirstSecondThreePrivate {
+	void *empty;						/* so that gcc -pedantic is happy */
+};
+
+static PwiFirstSecondClass *st_first_second_three_parent_class = NULL;
+
+static GType first_second_three_register_type( void );
+static void  first_second_three_class_init( PwiFirstSecondThreeClass *klass );
+static void  first_second_three_instance_init( GTypeInstance *instance, gpointer klass );
+static void  first_second_three_instance_dispose( GObject *application );
+static void  first_second_three_instance_finalize( GObject *application );
+
+static void  do_first_second_three_fn_a( PwiFirst *instance );
+static void  do_first_second_three_fn_c( PwiFirst *instance );
+
+GType
+pwi_first_second_three_get_type( void )
+{
+	static GType type = 0;
+
+	if( !type ){
+		type = first_second_three_register_type();
+	}
+
+	return( type );
+}
+
+static GType
+first_second_three_register_type( void )
+{
+	static const gchar *thisfn = "first_second_three_register_type";
+
+	static GTypeInfo info = {
+		sizeof( PwiFirstSecondThreeClass ),
+		( GBaseInitFunc ) NULL,
+		( GBaseFinalizeFunc ) NULL,
+		( GClassInitFunc ) first_second_three_class_init,
+		NULL,
+		NULL,
+		sizeof( PwiFirstSecondThree ),
+		0,
+		( GInstanceInitFunc ) first_second_three_instance_init
+	};
+
+	g_debug( "%s", thisfn );
+	return( g_type_register_static( PWI_FIRST_SECOND_TYPE, "PwiFirstSecondThree", &info, 0 ));
+}
+
+static void
+first_second_three_class_init( PwiFirstSecondThreeClass *klass )
+{
+	static const gchar *thisfn = "first_second_three_class_init";
+	GObjectClass *object_class;
+	PwiFirstClass *first_class;
+
+	g_debug( "%s: klass=%p", thisfn, ( void * ) klass );
+
+	st_first_second_three_parent_class = g_type_class_peek_parent( klass );
+
+	object_class = G_OBJECT_CLASS( klass );
+	object_class->dispose = first_second_three_instance_dispose;
+	object_class->finalize = first_second_three_instance_finalize;
+
+	klass->private = g_new0( PwiFirstSecondThreeClassPrivate, 1 );
+
+	first_class = PWI_FIRST_CLASS( klass );
+	first_class->fn_a = do_first_second_three_fn_a;
+	first_class->fn_b = NULL;
+	first_class->fn_c = do_first_second_three_fn_c;
+}
+
+static void
+first_second_three_instance_init( GTypeInstance *instance, gpointer klass )
+{
+	static const gchar *thisfn = "first_second_three_instance_init";
+	PwiFirstSecondThree *self;
+
+	g_debug( "%s: instance=%p, klass=%p", thisfn, ( void * ) instance, ( void * ) klass );
+	g_assert( PWI_IS_FIRST_SECOND_THREE( instance ));
+	self = PWI_FIRST_SECOND_THREE( instance );
+
+	self->private = g_new0( PwiFirstSecondThreePrivate, 1 );
+}
+
+static void
+first_second_three_instance_dispose( GObject *instance )
+{
+	static const gchar *thisfn = "first_second_three_instance_dispose";
+	PwiFirstSecondThree *self;
+
+	g_debug( "%s: instance=%p", thisfn, ( void * ) instance );
+	g_assert( PWI_IS_FIRST_SECOND_THREE( instance ));
+	self = PWI_FIRST_SECOND_THREE( instance );
+
+	/* chain up to the parent class */
+	G_OBJECT_CLASS( st_first_second_three_parent_class )->dispose( instance );
+}
+
+static void
+first_second_three_instance_finalize( GObject *instance )
+{
+	static const gchar *thisfn = "first_second_three_instance_finalize";
+	PwiFirstSecondThree *self;
+
+	g_debug( "%s: instance=%p", thisfn, ( void * ) instance );
+	g_assert( PWI_IS_FIRST_SECOND_THREE( instance ));
+	self = PWI_FIRST_SECOND_THREE( instance );
+
+	g_free( self->private );
+
+	/* chain call to parent class */
+	G_OBJECT_CLASS( st_first_second_three_parent_class )->finalize( instance );
+}
+
+static void
+do_first_second_three_fn_a( PwiFirst *instance )
+{
+	g_debug( "do_first_second_three_fn_a: instance=%p", ( void * ) instance );
+	if( PWI_FIRST_CLASS( st_first_second_three_parent_class )->fn_a ){
+		PWI_FIRST_CLASS( st_first_second_three_parent_class )->fn_a( instance );
+	}
+}
+
+static void
+do_first_second_three_fn_c( PwiFirst *instance )
+{
+	g_debug( "do_first_second_three_fn_c: instance=%p", ( void * ) instance );
+	if( PWI_FIRST_CLASS( st_first_second_three_parent_class )->fn_c ){
+		PWI_FIRST_CLASS( st_first_second_three_parent_class )->fn_c( instance );
+	}
+}
+
+int
+main( int argc, char **argv )
+{
+	PwiFirst *a;
+	PwiFirstSecond *b;
+	PwiFirstSecondThree *c;
+
+	g_type_init();
+
+	a = g_object_new( PWI_FIRST_TYPE, NULL );
+	b = g_object_new( PWI_FIRST_SECOND_TYPE, NULL );
+	c = g_object_new( PWI_FIRST_SECOND_THREE_TYPE, NULL );
+
+	g_debug( "expected pwi_first_fn_a, do_first_fn_a" );
+	pwi_first_fn_a( PWI_FIRST( a ));
+	g_debug( "expected pwi_first_fn_a, do_first_second_fn_a, do_first_fn_a" );
+	pwi_first_fn_a( PWI_FIRST( b ));
+	g_debug( "expected pwi_first_fn_a, do_first_second_three_fn_a, do_first_second_fn_a, do_first_fn_a" );
+	pwi_first_fn_a( PWI_FIRST( c ));
+
+	g_debug( "%s", "" );
+
+	g_debug( "expected pwi_first_fn_b, do_first_fn_b" );
+	pwi_first_fn_b( PWI_FIRST( a ));
+	g_debug( "expected pwi_first_fn_b, do_first_second_fn_b, do_first_fn_b" );
+	pwi_first_fn_b( PWI_FIRST( b ));
+	g_debug( "expected pwi_first_fn_b, do_first_second_fn_b, do_first_fn_b" );
+	/* NOT OK
+	 * result is pwi_first_fn_b, do_first_fn_b */
+	pwi_first_fn_b( PWI_FIRST( c ));
+
+	g_debug( "%s", "" );
+
+	g_debug( "expected pwi_first_fn_c, do_first_fn_c" );
+	pwi_first_fn_c( PWI_FIRST( a ));
+	g_debug( "expected pwi_first_fn_c, do_first_fn_c" );
+	pwi_first_fn_c( PWI_FIRST( b ));
+	g_debug( "expected pwi_first_fn_c, do_first_second_three_fn_c, do_first_fn_c" );
+	/* NOT OK
+	 * result is pwi_first_fn_c, do_first_second_three_fn_c */
+	pwi_first_fn_c( PWI_FIRST( c ));
+
+	return( 0 );
+}
diff --git a/src/utils/nautilus-actions-new.c b/src/utils/nautilus-actions-new.c
index 7ea70b9..1a1e359 100644
--- a/src/utils/nautilus-actions-new.c
+++ b/src/utils/nautilus-actions-new.c
@@ -36,9 +36,10 @@
 #include <glib/gi18n.h>
 #include <stdlib.h>
 
-#include <common/na-action.h>
-#include <common/na-action-profile.h>
-#include <common/na-gconf.h>
+#include <common/na-object-api.h>
+#include <common/na-obj-action.h>
+#include <common/na-obj-profile.h>
+#include <common/na-gconf-provider.h>
 #include <common/na-iio-provider.h>
 #include <common/na-xml-names.h>
 #include <common/na-xml-writer.h>
@@ -85,8 +86,8 @@ static GOptionEntry output_entries[] = {
 };
 
 static GOptionContext *init_options( void );
-static NAAction       *get_action_from_cmdline( void );
-static gboolean        write_to_gconf( NAAction *action, gchar **msg );
+static NAObjectAction *get_action_from_cmdline( void );
+static gboolean        write_to_gconf( NAObjectAction *action, gchar **msg );
 static void            exit_with_usage( void );
 
 int
@@ -95,7 +96,7 @@ main( int argc, char** argv )
 	int status = EXIT_SUCCESS;
 	GOptionContext *context;
 	GError *error = NULL;
-	NAAction *action;
+	NAObjectAction *action;
 	gchar *msg = NULL;
 	gchar *help;
 
@@ -136,7 +137,7 @@ main( int argc, char** argv )
 		}
 
 	} else {
-		gchar * output_fname = na_xml_writer_export( action, output_dir, FORMAT_GCONFENTRY, &msg );
+		gchar *output_fname = na_xml_writer_export( action, output_dir, FORMAT_GCONFENTRY, &msg );
 		if( output_fname ){
 			/* i18n: Action <action_label> written to <output_filename>...*/
 			g_print( _( "Action '%s' succesfully written to %s, and ready to be imported in NACT.\n" ), label, output_fname );
@@ -203,56 +204,61 @@ init_options( void )
 /*
  * allocate a new action, and fill it with values readen from command-line
  */
-static NAAction *
+static NAObjectAction *
 get_action_from_cmdline( void )
 {
-	NAAction *action = na_action_new_with_profile();
-	NAActionProfile *profile = NA_ACTION_PROFILE( na_action_get_profiles( action )->data );
+	NAObjectAction *action = na_object_action_new_with_profile();
+	GSList *profiles;
+	NAObjectProfile *profile;
 	int i = 0;
 	GSList *basenames = NULL;
 	GSList *mimetypes = NULL;
 	GSList *schemes = NULL;
 
-	na_action_set_label( action, label );
-	na_action_set_tooltip( action, tooltip );
-	na_action_set_icon( action, icon );
-	na_action_set_enabled( action, enabled );
+	profiles = na_object_get_items( action );
+	profile = NA_OBJECT_PROFILE( profiles->data );
+	na_object_free_items( profiles );
 
-	na_action_profile_set_path( profile, command );
-	na_action_profile_set_parameters( profile, parameters );
+	na_object_set_label( action, label );
+	na_object_set_tooltip( action, tooltip );
+	na_object_set_icon( action, icon );
+	na_object_set_enabled( NA_OBJECT_ITEM( action ), enabled );
+
+	na_object_profile_set_path( profile, command );
+	na_object_profile_set_parameters( profile, parameters );
 
 	while( basenames_array != NULL && basenames_array[i] != NULL ){
 		basenames = g_slist_append( basenames, g_strdup( basenames_array[i] ));
 		i++;
 	}
-	na_action_profile_set_basenames( profile, basenames );
+	na_object_profile_set_basenames( profile, basenames );
 	g_slist_foreach( basenames, ( GFunc ) g_free, NULL );
 	g_slist_free( basenames );
 
-	na_action_profile_set_matchcase( profile, matchcase );
+	na_object_profile_set_matchcase( profile, matchcase );
 
 	i = 0;
 	while( mimetypes_array != NULL && mimetypes_array[i] != NULL ){
 		mimetypes = g_slist_append( mimetypes, g_strdup( mimetypes_array[i] ));
 		i++;
 	}
-	na_action_profile_set_mimetypes( profile, mimetypes );
+	na_object_profile_set_mimetypes( profile, mimetypes );
 	g_slist_foreach( mimetypes, ( GFunc ) g_free, NULL );
 	g_slist_free( mimetypes );
 
 	if( !isfile && !isdir ){
 		isfile = TRUE;
 	}
-	na_action_profile_set_isfile( profile, isfile );
-	na_action_profile_set_isdir( profile, isdir );
-	na_action_profile_set_multiple( profile, accept_multiple );
+	na_object_profile_set_isfile( profile, isfile );
+	na_object_profile_set_isdir( profile, isdir );
+	na_object_profile_set_multiple( profile, accept_multiple );
 
 	i = 0;
 	while( schemes_array != NULL && schemes_array[i] != NULL ){
 		schemes = g_slist_append( schemes, g_strdup( schemes_array[i] ));
 		i++;
 	}
-	na_action_profile_set_schemes( profile, schemes );
+	na_object_profile_set_schemes( profile, schemes );
 	g_slist_foreach( schemes, ( GFunc ) g_free, NULL );
 	g_slist_free( schemes );
 
@@ -264,16 +270,16 @@ get_action_from_cmdline( void )
  * then writes the action
  */
 static gboolean
-write_to_gconf( NAAction *action, gchar **msg )
+write_to_gconf( NAObjectAction *action, gchar **msg )
 {
-	NAGConf *gconf;
+	NAGConfProvider *gconf;
 	guint ret;
 
-	gconf = na_gconf_new( NULL );
+	gconf = na_gconf_provider_new( NULL );
 
-	na_action_set_provider( action, NA_IIO_PROVIDER( gconf ));
+	na_object_set_provider( action, NA_IIO_PROVIDER( gconf ));
 
-	ret = na_iio_provider_write_action( NULL, action, msg );
+	ret = na_iio_provider_write_item( NULL, NA_OBJECT( action ), msg );
 
 	return( ret == NA_IIO_PROVIDER_WRITE_OK );
 }
diff --git a/src/utils/nautilus-actions-schemas.c b/src/utils/nautilus-actions-schemas.c
index 2ecc79d..6ab904d 100644
--- a/src/utils/nautilus-actions-schemas.c
+++ b/src/utils/nautilus-actions-schemas.c
@@ -38,7 +38,6 @@
 #include <glib/gi18n.h>
 #include <stdlib.h>
 
-#include <common/na-gconf-keys.h>
 #include <common/na-xml-names.h>
 #include <common/na-xml-writer.h>
 
@@ -159,8 +158,8 @@ write_to_gconf( gchar **msg )
 {
 	GConfClient *gconf = gconf_client_get_default();
 
-	gchar *prefix_config = g_strdup_printf( "%s%s", NA_GCONF_SCHEMA_PREFIX, NA_GCONF_CONFIG_PATH );
-	gchar *prefix_prefs = g_strdup_printf( "%s%s/%s", NA_GCONF_SCHEMA_PREFIX, NAUTILUS_ACTIONS_CONFIG_GCONF_BASEDIR, NA_GCONF_SCHEMA_PREFERENCES );
+	gchar *prefix_config = g_strdup_printf( "%s%s", NAUTILUS_ACTIONS_GCONF_SCHEMASDIR, NA_GCONF_CONFIG_PATH );
+	gchar *prefix_prefs = g_strdup_printf( "%s%s/%s", NAUTILUS_ACTIONS_GCONF_SCHEMASDIR, NAUTILUS_ACTIONS_GCONF_BASEDIR, NA_GCONF_PREFERENCES );
 
 	gboolean ret =
 		write_schema( gconf, prefix_config, GCONF_VALUE_STRING, ACTION_VERSION_ENTRY, ACTION_VERSION_DESC_SHORT, ACTION_VERSION_DESC_LONG, NAUTILUS_ACTIONS_CONFIG_VERSION, msg ) &&



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