[nautilus-actions] Implements drag and drop



commit b6bc948a165c81145ea95db57486f17569028be9
Author: Pierre Wieser <pwieser trychlos org>
Date:   Sun Aug 30 16:49:04 2009 +0200

    Implements drag and drop
    
    For now, only drag to external applications (file-manager, text editor, ...) is implemented.
    A new NAActionMenu class is defined, derived from new NAObjectItem class.
    Preferences 'Add About item' and 'Display in alphabetical order'.

 ChangeLog                                     |  116 ++++
 NEWS                                          |   10 +-
 TODO                                          |    6 +-
 data/nautilus-actions.schemas.in              |   33 +-
 doc/objects-hierarchy.odg                     |  Bin 14360 -> 14610 bytes
 src/common/Makefile.am                        |    4 +
 src/common/na-action-class.h                  |    6 +-
 src/common/na-action-menu.c                   |  288 ++++++++++
 src/common/na-action-menu.h                   |   78 +++
 src/common/na-action-profile.c                |  267 +++++------
 src/common/na-action.c                        |  340 ++++---------
 src/common/na-action.h                        |    5 +-
 src/common/na-gconf.c                         |   42 ++-
 src/common/na-iduplicable.c                   |  171 ++++---
 src/common/na-iduplicable.h                   |   74 ++--
 src/common/na-iio-provider.c                  |   38 +-
 src/common/na-iio-provider.h                  |    5 +-
 src/common/na-ipivot-consumer.c               |   34 ++-
 src/common/na-ipivot-consumer.h               |   28 +-
 src/common/na-iprefs.c                        |   81 +++-
 src/common/na-iprefs.h                        |   70 +++-
 src/common/na-object-item.c                   |  448 ++++++++++++++++
 src/common/na-object-item.h                   |   89 ++++
 src/common/na-object.c                        |  260 ++++++----
 src/common/na-object.h                        |   68 +--
 src/common/na-pivot.c                         |   64 +++-
 src/common/na-utils.c                         |   85 +++
 src/common/na-utils.h                         |    7 +
 src/common/na-xml-writer.c                    |  220 +++++++-
 src/common/na-xml-writer.h                    |    8 +-
 src/nact/Makefile.am                          |    6 +
 src/nact/egg-tree-multi-dnd.c                 |  505 ++++++++++++++++++
 src/nact/egg-tree-multi-dnd.h                 |   98 ++++
 src/nact/nact-application.c                   |    4 +-
 src/nact/nact-assistant-export.c              |   55 +--
 src/nact/nact-iaction-tab.c                   |   34 +-
 src/nact/nact-iaction-tab.h                   |    2 +-
 src/nact/nact-iactions-list.c                 |  199 +++----
 src/nact/nact-iactions-list.h                 |    4 +-
 src/nact/nact-imenubar.c                      |   57 +--
 src/nact/nact-imenubar.h                      |    2 +-
 src/nact/nact-main-window.c                   |  160 +++++--
 src/nact/nact-preferences-editor.c            |   39 +-
 src/nact/nact-selection.c                     |  180 +++++++
 src/nact/nact-selection.h                     |   45 ++
 src/nact/nact-tree-model.c                    |  694 +++++++++++++++++++++++++
 src/nact/nact-tree-model.h                    |   95 ++++
 src/nact/nact-window.h                        |    1 +
 src/nact/nautilus-actions-config-tool.actions |    1 +
 src/nact/nautilus-actions-config-tool.ui      |   37 +-
 src/plugin/nautilus-actions.c                 |   27 +-
 51 files changed, 4177 insertions(+), 1013 deletions(-)
---
diff --git a/ChangeLog b/ChangeLog
index dbb54bb..2a85832 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,119 @@
+2009-08-30 Pierre Wieser <pwieser trychlos org>
+
+	* data/nautilus-actions.schemas.in:
+	Remove schema for 'Use submenu' preference.
+	Add schemas for 'Add About' and 'Alphabetical order' preferences.
+
+	* doc/objects-hierarchy.odg:
+	Update doc to show new NAObjectItem and NAActionMenu classes.
+
+	* src/common/na-action-class.h:
+	NAAction is now derived from NAObjectItem.
+
+	* src/common/na-action-profile.c:
+	Remove PROP_NAPROFILE_NAME and PROP_NAPROFILE_LABEL properties.
+	Remove duplicate() virtual function.
+	Add new() and get_clipboard_id() virtual functions.
+
+	* src/common/na-action.c:
+	Remove PROP_NAACTION_UUID, PROP_NAACTION_LABEL,
+	PROP_NAACTION_TOOLTIP and PROP_NAACTION_ICON properties.
+	Remove duplicate() and check_edited_status() virtual functions.
+	Add new() and get_clipboard_id() virtual functions.
+
+	* src/common/na-action-menu.c:
+	* src/common/na-action-menu.h: New files.
+
+	* src/common/na-gconf.c:
+	Now watches for preferences directory to manage display mode in
+	Nautilus.
+
+	* src/common/na-iduplicable.c:
+	* src/common/na-iduplicable.h:
+	Replace duplicate() virtual function with copy() and new().
+	All interface is now declared with NAIDuplicable instead of NAObject.
+
+	* src/common/na-iio-provider.c:
+	* src/common/na-iio-provider.h:
+	Temporarily sort read actions.
+	Define NA_IIO_PROVIDER_SIGNAL_DISPLAY_ORDER_CHANGED and
+	NA_IIO_PROVIDER_SIGNAL_DISPLAY_ABOUT_CHANGED new signals.
+
+	* src/common/na-ipivot-consumer.c:
+	Take advantage of new signals defined in na-iio-provider.h.
+	Define on_display_about_changed() and on_display_order_changed()
+	new virtual functions.
+
+	* src/common/na-iprefs.c:
+	* src/common/na-iprefs.h (na_iprefs_get_alphabetical_order,
+	na_iprefs_get_add_about_item): New functions.
+
+	* src/common/na-object.c:
+	* src/common/na-object.h (new, copy, get_clipboard_id):
+	New virtual functions.
+
+	* src/common/na-object-item.c:
+	* src/common/na-object-item.h: New files.
+
+	* src/common/na-pivot.c:
+	Take advantage of new signals defined in na-iio-provider.h.
+
+	* src/common/na-utils.c:
+	* src/common/na-utils.h (na_utils_remove_last_level_from_path,
+	na_utils_is_writable_dir, na_utils_exist_file): New functions.
+
+	* src/common/na-xml-writer.c:
+	* src/common/na-xml-writer.h (na_xml_writer_get_output_fname,
+	na_xml_writer_get_xml_buffer, na_xml_writer_output_xml):
+	New functions.
+
+	* src/nact/egg-tree-multi-dnd.c:
+	* src/nact/egg-tree-multi-dnd.h: New files.
+
+	* src/nact/nact-application.c:
+	No more display debug message in appli_get_application_name().
+
+	* src/nact/nact-assistant-export.c
+	(on_actions_list_selection_changed): Use actual parameters types.
+	(is_writable_dir): Removed function.
+
+	* src/nact/nact-iaction-tab.c:
+	* src/nact/nact-iaction-tab.h
+	(get_selected): Removed virtual function.
+	(nact_iaction_tab_set_action): Add selected items parameter.
+
+	* src/nact/nact-iactions-list.c:
+	* src/nact/nact-iactions-list.h:
+	Implements drag from the tree view based on a dedicated
+	NactTreeModel.
+	Remove virtual function on_selection_changed().
+	nact_iactions_list_get_selected_items(),
+	nact_iactions_list_set_dnd_mode(): New functions.
+
+	* nact/nact-imenubar.c:
+	* nact/nact-imenubar.h:
+	Add 'New menu' item in the menubar.
+	Define new insert_item() virtual function.
+
+	* src/nact/nact-main-window.c:
+	* src/nact/nact-main-window.h:
+	Implements NaIPrefs interface.
+	Be kept informed of preferences modifications.
+
+	* src/nact/nact-preferences-editor.c:
+	Replace 'Display as submenu' by 'Add About' and 'Display in
+	alphabetical order' preferences.
+
+	* src/nact/nact-selection.c:
+	* src/nact/nact-selection.h: New files.
+
+	* src/nact/nact-tree-model.c:
+	* src/nact/nact-tree-model.h: New files.
+
+	* src/plugin/nautilus-actions.c:
+	Creates submenus if asked for.
+	Adds 'About Nautilus Actions' item is asked for.
+
 2009-08-25 Pierre Wieser <pwieser trychlos org>
 
 	* configure.ac: Add a comment about bug #589745.
diff --git a/NEWS b/NEWS
index 306004d..e986f00 100644
--- a/NEWS
+++ b/NEWS
@@ -3,8 +3,14 @@ Version xxxxxx
 
 	Release date
 
-	Displays actions as a submenu of Nautilus context menu.
-	Menu items have now keyboard accelerators.
+	Actions can be displayed as Nautilus submenus.
+	An 'About Nautilus Actions' item can be added to Nautilus context
+	menu.
+	Menubar items have now keyboard accelerators.
+	Preferences can be edited in NACT user interface.
+	Actions can be freely reordered in NACT user interface.
+	Actions can be exported as XML files by drag and drop to file-
+	manager, text editor, ...
 
 	Bugfixes
 
diff --git a/TODO b/TODO
index 285825a..e1a401f 100644
--- a/TODO
+++ b/TODO
@@ -28,8 +28,6 @@
 - changing conditions in IConditionsTab should trigger an update of the
   example label
 
-- use GtkUIManager
-
 - propose a patch for GOptions so that the help for an option could be
   multiline (by defining an optional maximum width)
 
@@ -43,3 +41,7 @@
      impact on Nautilus behavior
   -> send a DBus message would be the most elegant solution
 
+- open a bug against glib for g_utf8_collate_key_for_filename()
+  (see the 26 exported actions, and the screenshot of Nautilus view)
+
+- open a bug against gnome-packagekit: keep the last window size and position
diff --git a/data/nautilus-actions.schemas.in b/data/nautilus-actions.schemas.in
index 2166c97..79cf694 100644
--- a/data/nautilus-actions.schemas.in
+++ b/data/nautilus-actions.schemas.in
@@ -217,17 +217,6 @@ All schemes used by Nautilus can be used here.</long>
     <!-- schemas for preferences -->
 
     <schema>
-      <key>/schemas/apps/nautilus-actions/preferences/display-as-submenu</key>
-      <owner>nautilus-actions</owner>
-      <type>bool</type>
-      <locale name="C">
-        <short>Display actions as a Nautilus submenu</short>
-        <long>When TRUE, the available Nautilus-Actions actions are displayed as a submenu of the Nautilus context menu</long>
-      </locale>
-      <default>false</default>
-    </schema>
-
-    <schema>
       <key>/schemas/apps/nautilus-actions/preferences/export-assistant</key>
       <owner>nautilus-actions</owner>
       <type>list</type>
@@ -343,5 +332,27 @@ All schemes used by Nautilus can be used here.</long>
       <default>[]</default>
     </schema>
 
+    <schema>
+      <key>/schemas/apps/nautilus-actions/preferences/preferences-add-about-item</key>
+      <owner>nautilus-actions</owner>
+      <type>bool</type>
+      <locale name="C">
+        <short>Add an 'About' item in the Nautilus context menu</short>
+        <long>If TRUE, and if the user has defined a single root menu for its actions, then an 'About Nautilus Actions' will be displayed at end of the first submenu.</long>
+      </locale>
+      <default>true</default>
+    </schema>
+
+    <schema>
+      <key>/schemas/apps/nautilus-actions/preferences/preferences-alphabetical-order</key>
+      <owner>nautilus-actions</owner>
+      <type>bool</type>
+      <locale name="C">
+        <short>Sort actions in alphabetical order</short>
+        <long>When TRUE, the actions are maintained in alphabetical order (historical behavior). When FALSE, user is free to reorder them via Nautilus-Actions configuration tool.</long>
+      </locale>
+      <default>true</default>
+    </schema>
+
   </schemalist>
 </gconfschemafile>
diff --git a/doc/objects-hierarchy.odg b/doc/objects-hierarchy.odg
index 7e4b757..2a2881d 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 e40fa0b..dede517 100644
--- a/src/common/Makefile.am
+++ b/src/common/Makefile.am
@@ -40,6 +40,8 @@ libnact_la_SOURCES = \
 	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					\
@@ -58,6 +60,8 @@ libnact_la_SOURCES = \
 	na-iprefs.h									\
 	na-object.c									\
 	na-object.h									\
+	na-object-item.c							\
+	na-object-item.h							\
 	na-pivot.c									\
 	na-pivot.h									\
 	na-utils.c									\
diff --git a/src/common/na-action-class.h b/src/common/na-action-class.h
index a734f5b..38cf758 100644
--- a/src/common/na-action-class.h
+++ b/src/common/na-action-class.h
@@ -35,7 +35,7 @@
  * SECTION: na_action
  */
 
-#include "na-object.h"
+#include "na-object-item.h"
 
 G_BEGIN_DECLS
 
@@ -49,7 +49,7 @@ G_BEGIN_DECLS
 typedef struct NAActionPrivate NAActionPrivate;
 
 typedef struct {
-	NAObject         parent;
+	NAObjectItem     parent;
 	NAActionPrivate *private;
 }
 	NAAction;
@@ -57,7 +57,7 @@ typedef struct {
 typedef struct NAActionClassPrivate NAActionClassPrivate;
 
 typedef struct {
-	NAObjectClass         parent;
+	NAObjectItemClass     parent;
 	NAActionClassPrivate *private;
 }
 	NAActionClass;
diff --git a/src/common/na-action-menu.c b/src/common/na-action-menu.c
new file mode 100644
index 0000000..1230cdc
--- /dev/null
+++ b/src/common/na-action-menu.c
@@ -0,0 +1,288 @@
+/*
+ * 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-action.h"
+#include "na-action-menu.h"
+
+/* private class data
+ */
+struct NAActionMenuClassPrivate {
+	void *empty;						/* so that gcc -pedantic is happy */
+};
+
+/* private instance data
+ */
+struct NAActionMenuPrivate {
+	gboolean dispose_has_run;
+};
+
+static NAObjectClass *st_parent_class = NULL;
+
+static GType     register_type( void );
+static void      class_init( NAActionMenuClass *klass );
+static void      instance_init( GTypeInstance *instance, gpointer klass );
+static void      instance_dispose( GObject *object );
+static void      instance_finalize( GObject *object );
+
+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 )
+{
+	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_action_menu_register_type";
+
+	static GTypeInfo info = {
+		sizeof( NAActionMenuClass ),
+		( GBaseInitFunc ) NULL,
+		( GBaseFinalizeFunc ) NULL,
+		( GClassInitFunc ) class_init,
+		NULL,
+		NULL,
+		sizeof( NAActionMenu ),
+		0,
+		( GInstanceInitFunc ) instance_init
+	};
+
+	g_debug( "%s", thisfn );
+
+	return( g_type_register_static( NA_OBJECT_ITEM_TYPE, "NAActionMenu", &info, 0 ));
+}
+
+static void
+class_init( NAActionMenuClass *klass )
+{
+	static const gchar *thisfn = "na_action_menu_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( NAActionMenuClassPrivate, 1 );
+
+	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;
+
+	g_debug( "%s: instance=%p, klass=%p", thisfn, ( void * ) instance, ( void * ) klass );
+	g_assert( NA_IS_ACTION_MENU( instance ));
+	self = NA_ACTION_MENU( instance );
+
+	self->private = g_new0( NAActionMenuPrivate, 1 );
+
+	self->private->dispose_has_run = FALSE;
+}
+
+static void
+instance_dispose( GObject *object )
+{
+	static const gchar *thisfn = "na_action_menu_instance_dispose";
+	NAActionMenu *self;
+
+	g_debug( "%s: object=%p", thisfn, ( void * ) object );
+
+	g_assert( NA_IS_ACTION_MENU( object ));
+	self = NA_ACTION_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 );
+	}
+}
+
+static void
+instance_finalize( GObject *object )
+{
+	static const gchar *thisfn = "na_action_menu_instance_finalize";
+	NAActionMenu *self;
+
+	g_debug( "%s: object=%p", thisfn, ( void * ) object );
+	g_assert( NA_IS_ACTION_MENU( object ));
+	self = ( NAActionMenu * ) object;
+
+	g_free( self->private );
+
+	/* chain call to parent class */
+	if((( GObjectClass * ) st_parent_class )->finalize ){
+		G_OBJECT_CLASS( st_parent_class )->finalize( object );
+	}
+}
+
+/**
+ * na_action_menu_new:
+ *
+ * Allocates a new #NAActionMenu object.
+ *
+ * The new #NAActionMenu object is initialized with suitable default values,
+ * but without any profile.
+ *
+ * Returns: the newly allocated #NAActionMenu object.
+ */
+NAActionMenu *
+na_action_menu_new( void )
+{
+	NAActionMenu *menu;
+
+	menu = g_object_new( NA_ACTION_MENU_TYPE, NULL );
+
+	na_action_set_new_uuid( NA_ACTION( menu ));
+
+	na_object_set_label( NA_OBJECT( menu ), NA_ACTION_MENU_DEFAULT_LABEL );
+
+	return( menu );
+}
+
+static NAObject *
+object_new( const NAObject *menu )
+{
+	return( NA_OBJECT( na_action_menu_new()));
+}
+
+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 ));
+}
+
+static gboolean
+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 ));
+
+	return( equal );
+}
+
+/*
+ * a valid NAActionMenu requires a not null, not empty label
+ * this is checked here as NAObject doesn't have this condition
+ */
+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 ));
+
+	if( is_valid ){
+		label = na_object_get_label( menu );
+		is_valid = ( label && g_utf8_strlen( label, -1 ) > 0 );
+		g_free( label );
+	}
+
+	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-action-menu.h
new file mode 100644
index 0000000..15e380f
--- /dev/null
+++ b/src/common/na-action-menu.h
@@ -0,0 +1,78 @@
+/*
+ * 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_ACTION_MENU_H__
+#define __NA_ACTION_MENU_H__
+
+/**
+ * SECTION: na_action_menu
+ * @short_description: #NAActionMenu class definition.
+ * @include: common/na-action-menu.h
+ *
+ * This is a menu.
+ */
+
+#include "na-object-item.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 ))
+
+typedef struct NAActionMenuPrivate NAActionMenuPrivate;
+
+typedef struct {
+	NAObjectItem         parent;
+	NAActionMenuPrivate *private;
+}
+	NAActionMenu;
+
+typedef struct NAActionMenuClassPrivate NAActionMenuClassPrivate;
+
+typedef struct {
+	NAObjectItemClass         parent;
+	NAActionMenuClassPrivate *private;
+}
+	NAActionMenuClass;
+
+/* i18n: default label for a newly created menu */
+#define NA_ACTION_MENU_DEFAULT_LABEL	_( "New Nautilus Menu" )
+
+GType         na_action_menu_get_type( void );
+
+NAActionMenu *na_action_menu_new( void );
+
+G_END_DECLS
+
+#endif /* __NA_ACTION_MENU_H__ */
diff --git a/src/common/na-action-profile.c b/src/common/na-action-profile.c
index 3fab8bf..2c64f83 100644
--- a/src/common/na-action-profile.c
+++ b/src/common/na-action-profile.c
@@ -73,8 +73,6 @@ struct NAActionProfilePrivate {
  */
 enum {
 	PROP_NAPROFILE_ACTION = 1,
-	PROP_NAPROFILE_NAME,
-	PROP_NAPROFILE_LABEL,
 	PROP_NAPROFILE_PATH,
 	PROP_NAPROFILE_PARAMETERS,
 	PROP_NAPROFILE_BASENAMES,
@@ -87,8 +85,6 @@ enum {
 };
 
 #define PROP_NAPROFILE_ACTION_STR				"na-profile-action"
-#define PROP_NAPROFILE_NAME_STR					"na-profile-name"
-#define PROP_NAPROFILE_LABEL_STR				"na-profile-desc-name"
 #define PROP_NAPROFILE_PATH_STR					"na-profile-path"
 #define PROP_NAPROFILE_PARAMETERS_STR			"na-profile-parameters"
 #define PROP_NAPROFILE_BASENAMES_STR			"na-profile-basenames"
@@ -109,14 +105,15 @@ static void      instance_set_property( GObject *object, guint property_id, cons
 static void      instance_dispose( GObject *object );
 static void      instance_finalize( GObject *object );
 
-static void      object_dump( const NAObject *action );
-static void      object_dump_list( const gchar *thisfn, const gchar *label, GSList *list );
-static NAObject *object_duplicate( const NAObject *action );
+static int       validate_schemes( GSList* schemes2test, NautilusFileInfo* file );
+
+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 *action );
-
-static int       validate_schemes( GSList* schemes2test, NautilusFileInfo* file );
+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 )
@@ -177,20 +174,6 @@ class_init( NAActionProfileClass *klass )
 	g_object_class_install_property( object_class, PROP_NAPROFILE_ACTION, spec );
 
 	spec = g_param_spec_string(
-			PROP_NAPROFILE_NAME_STR,
-			"Profile name",
-			"Internal profile identifiant (ASCII, case insensitive)", "",
-			G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE );
-	g_object_class_install_property( object_class, PROP_NAPROFILE_NAME, spec );
-
-	spec = g_param_spec_string(
-			PROP_NAPROFILE_LABEL_STR,
-			"Profile label",
-			"Displayable profile's label (UTF-8, localizable)", "",
-			G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE );
-	g_object_class_install_property( object_class, PROP_NAPROFILE_LABEL, spec );
-
-	spec = g_param_spec_string(
 			PROP_NAPROFILE_PATH_STR,
 			"Command path",
 			"Command path", "",
@@ -255,21 +238,21 @@ class_init( NAActionProfileClass *klass )
 
 	klass->private = g_new0( NAActionProfileClassPrivate, 1 );
 
-	NA_OBJECT_CLASS( klass )->dump = object_dump;
-	NA_OBJECT_CLASS( klass )->duplicate = object_duplicate;
+	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";
-	g_debug( "%s: instance=%p, klass=%p", thisfn, instance, klass );*/
-
+	/*static const gchar *thisfn = "na_action_profile_instance_init";*/
 	NAActionProfile *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 );
 
@@ -307,14 +290,6 @@ instance_get_property( GObject *object, guint property_id, GValue *value, GParam
 			g_value_set_pointer( value, self->private->action );
 			break;
 
-		case PROP_NAPROFILE_NAME:
-			G_OBJECT_CLASS( st_parent_class )->get_property( object, PROP_NAOBJECT_ID, value, spec );
-			break;
-
-		case PROP_NAPROFILE_LABEL:
-			G_OBJECT_CLASS( st_parent_class )->get_property( object, PROP_NAOBJECT_LABEL, value, spec );
-			break;
-
 		case PROP_NAPROFILE_PATH:
 			g_value_set_string( value, self->private->path );
 			break;
@@ -373,14 +348,6 @@ instance_set_property( GObject *object, guint property_id, const GValue *value,
 			self->private->action = g_value_get_pointer( value );
 			break;
 
-		case PROP_NAPROFILE_NAME:
-			G_OBJECT_CLASS( st_parent_class )->set_property( object, PROP_NAOBJECT_ID, value, spec );
-			break;
-
-		case PROP_NAPROFILE_LABEL:
-			G_OBJECT_CLASS( st_parent_class )->set_property( object, PROP_NAOBJECT_LABEL, value, spec );
-			break;
-
 		case PROP_NAPROFILE_PATH:
 			g_free( self->private->path );
 			self->private->path = g_value_dup_string( value );
@@ -431,11 +398,10 @@ 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";
+	/*static const gchar *thisfn = "na_action_profile_instance_dispose";*/
 	NAActionProfile *self;
 
-	g_debug( "%s: object=%p", thisfn, ( void * ) object );
-
+	/*g_debug( "%s: object=%p", thisfn, ( void * ) object );*/
 	g_assert( NA_IS_ACTION_PROFILE( object ));
 	self = NA_ACTION_PROFILE( object );
 
@@ -444,18 +410,19 @@ instance_dispose( GObject *object )
 		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_profile_instance_finalize";
+	/*static const gchar *thisfn = "na_action_profile_instance_finalize";*/
 	NAActionProfile *self;
 
-	g_debug( "%s: object=%p", thisfn, (void * ) object );
-
+	/*g_debug( "%s: object=%p", thisfn, (void * ) object );*/
 	g_assert( NA_IS_ACTION_PROFILE( object ));
 	self = ( NAActionProfile * ) object;
 
@@ -468,7 +435,7 @@ instance_finalize( GObject *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 );
 	}
 }
@@ -531,13 +498,7 @@ na_action_profile_get_action( const NAActionProfile *profile )
 gchar *
 na_action_profile_get_name( const NAActionProfile *profile )
 {
-	gchar *id;
-
-	g_assert( NA_IS_ACTION_PROFILE( profile ));
-
-	g_object_get( G_OBJECT( profile ), PROP_NAPROFILE_NAME_STR, &id, NULL );
-
-	return( id );
+	return( na_object_get_id( NA_OBJECT( profile )));
 }
 
 /**
@@ -554,13 +515,7 @@ na_action_profile_get_name( const NAActionProfile *profile )
 gchar *
 na_action_profile_get_label( const NAActionProfile *profile )
 {
-	gchar *label;
-
-	g_assert( NA_IS_ACTION_PROFILE( profile ));
-
-	g_object_get( G_OBJECT( profile ), PROP_NAPROFILE_LABEL_STR, &label, NULL );
-
-	return( label );
+	return( na_object_get_label( NA_OBJECT( profile )));
 }
 
 /**
@@ -806,9 +761,7 @@ na_action_profile_set_action( NAActionProfile *profile, const NAAction *action )
 void
 na_action_profile_set_name( NAActionProfile *profile, const gchar *name )
 {
-	g_assert( NA_IS_ACTION_PROFILE( profile ));
-
-	g_object_set( G_OBJECT( profile ), PROP_NAPROFILE_NAME_STR, name, NULL );
+	na_object_set_id( NA_OBJECT( profile ), name );
 }
 
 /**
@@ -826,9 +779,7 @@ na_action_profile_set_name( NAActionProfile *profile, const gchar *name )
 void
 na_action_profile_set_label( NAActionProfile *profile, const gchar *label )
 {
-	g_assert( NA_IS_ACTION_PROFILE( profile ));
-
-	g_object_set( G_OBJECT( profile ), PROP_NAPROFILE_LABEL_STR, label, NULL );
+	na_object_set_label( NA_OBJECT( profile ), label );
 }
 
 /**
@@ -1480,51 +1431,36 @@ na_action_profile_parse_parameters( const NAActionProfile *profile, GList* files
 	return( parsed );
 }
 
-static void
-object_dump( const NAObject *object )
+static int
+validate_schemes( GSList* schemes2test, NautilusFileInfo* file )
 {
-	static const gchar *thisfn = "na_action_profile_object_dump";
-	NAActionProfile *self;
+	int retv = 0;
+	GSList* iter;
+	gboolean found = FALSE;
+	gchar *scheme;
 
-	g_assert( NA_IS_ACTION_PROFILE( object ));
-	self = NA_ACTION_PROFILE( object );
+	iter = schemes2test;
+	while (iter && !found)
+	{
+		scheme = nautilus_file_info_get_uri_scheme (file);
 
-	if( st_parent_class->dump ){
-		st_parent_class->dump( object );
-	}
+		if (g_ascii_strncasecmp (scheme, (gchar*)iter->data, strlen ((gchar*)iter->data)) == 0)
+		{
+			found = TRUE;
+			retv = 1;
+		}
 
-	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 );
-}
+		g_free (scheme);
+		iter = iter->next;
+	}
 
-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 );
+	return retv;
 }
 
 static NAObject *
-object_duplicate( const NAObject *profile )
+object_new( const NAObject *profile )
 {
-	NAObject *duplicate;
-
-	g_assert( NA_IS_ACTION_PROFILE( profile ));
-
-	duplicate = NA_OBJECT( na_action_profile_new());
-
-	na_object_copy( duplicate, profile );
-
-	return( duplicate );
+	return( NA_OBJECT( na_action_profile_new()));
 }
 
 static void
@@ -1534,6 +1470,10 @@ 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 ));
 
@@ -1566,10 +1506,6 @@ object_copy( NAObject *target, const NAObject *source )
 	na_utils_free_string_list( basenames );
 	na_utils_free_string_list( mimetypes );
 	na_utils_free_string_list( schemes );
-
-	if( st_parent_class->copy ){
-		st_parent_class->copy( target, source );
-	}
 }
 
 gboolean
@@ -1577,52 +1513,56 @@ object_are_equal( const NAObject *a, const NAObject *b )
 {
 	NAActionProfile *first = NA_ACTION_PROFILE( a );
 	NAActionProfile *second = NA_ACTION_PROFILE( b );
-	gboolean equal;
+	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 ));
 
-	equal =
-		( g_utf8_collate( first->private->path, second->private->path ) == 0 ) &&
-		( g_utf8_collate( first->private->parameters, second->private->parameters ) == 0 );
+	if( equal ){
+		equal =
+			( g_utf8_collate( first->private->path, second->private->path ) == 0 ) &&
+			( g_utf8_collate( first->private->parameters, second->private->parameters ) == 0 );
+	}
 
 	if( equal ){
 		equal = (( first->private->accept_multiple && second->private->accept_multiple ) ||
 				( !first->private->accept_multiple && !second->private->accept_multiple ));
 	}
+
 	if( equal ){
 		equal = (( first->private->is_dir && second->private->is_dir ) ||
 				( !first->private->is_dir && !second->private->is_dir ));
 	}
+
 	if( equal ){
 		equal = (( first->private->is_file && second->private->is_file ) ||
 				( !first->private->is_file && !second->private->is_file ));
 	}
+
 	if( equal ){
 		equal = na_utils_string_lists_are_equal( first->private->basenames, second->private->basenames ) &&
 				na_utils_string_lists_are_equal( first->private->mimetypes, second->private->mimetypes ) &&
 				na_utils_string_lists_are_equal( first->private->schemes, second->private->schemes );
 	}
-	if( equal ){
-		if( st_parent_class->are_equal ){
-			equal = st_parent_class->are_equal( a, b );
-		}
-	}
 
 	return( equal );
 }
 
+/*
+ * a valid NAActionProfile requires a not null, not empty label
+ * this is checked here as NAObject doesn't have this condition
+ */
 gboolean
 object_is_valid( const NAObject *profile )
 {
 	gchar *label;
-	gboolean is_valid;
-
-	g_assert( NA_IS_ACTION_PROFILE( profile ));
-
-	g_object_get( G_OBJECT( profile ), PROP_NAPROFILE_LABEL_STR, &label, NULL );
-	is_valid = ( label && g_utf8_strlen( label, -1 ) > 0 );
-	g_free( label );
+	gboolean is_valid = TRUE;
 
 	if( is_valid ){
 		if( st_parent_class->is_valid ){
@@ -1630,31 +1570,62 @@ object_is_valid( const NAObject *profile )
 		}
 	}
 
+	g_assert( NA_IS_ACTION_PROFILE( profile ));
+
+	if( is_valid ){
+		label = na_object_get_label( profile );
+		is_valid = ( label && g_utf8_strlen( label, -1 ) > 0 );
+		g_free( label );
+	}
+
 	return( is_valid );
 }
 
-static int
-validate_schemes( GSList* schemes2test, NautilusFileInfo* file )
+static void
+object_dump( const NAObject *object )
 {
-	int retv = 0;
-	GSList* iter;
-	gboolean found = FALSE;
-	gchar *scheme;
-
-	iter = schemes2test;
-	while (iter && !found)
-	{
-		scheme = nautilus_file_info_get_uri_scheme (file);
+	static const gchar *thisfn = "na_action_profile_object_dump";
+	NAActionProfile *self;
 
-		if (g_ascii_strncasecmp (scheme, (gchar*)iter->data, strlen ((gchar*)iter->data)) == 0)
-		{
-			found = TRUE;
-			retv = 1;
-		}
+	g_assert( NA_IS_ACTION_PROFILE( object ));
+	self = NA_ACTION_PROFILE( object );
 
-		g_free (scheme);
-		iter = iter->next;
+	if( st_parent_class->dump ){
+		st_parent_class->dump( object );
 	}
 
-	return retv;
+	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-action.c b/src/common/na-action.c
index 572a9e4..6538007 100644
--- a/src/common/na-action.c
+++ b/src/common/na-action.c
@@ -53,8 +53,6 @@ struct NAActionPrivate {
 	/* action properties
 	 */
 	gchar         *version;
-	gchar         *tooltip;
-	gchar         *icon;
 	gboolean       enabled;
 
 	/* list of action's profiles as NAActionProfile objects
@@ -77,21 +75,13 @@ struct NAActionPrivate {
 /* action properties
  */
 enum {
-	PROP_NAACTION_UUID = 1,
-	PROP_NAACTION_LABEL,
-	PROP_NAACTION_VERSION,
-	PROP_NAACTION_TOOLTIP,
-	PROP_NAACTION_ICON,
+	PROP_NAACTION_VERSION = 1,
 	PROP_NAACTION_ENABLED,
 	PROP_NAACTION_READONLY,
 	PROP_NAACTION_PROVIDER
 };
 
-#define PROP_NAACTION_UUID_STR			"na-action-uuid"
-#define PROP_NAACTION_LABEL_STR			"na-action-label"
 #define PROP_NAACTION_VERSION_STR		"na-action-version"
-#define PROP_NAACTION_TOOLTIP_STR		"na-action-tooltip"
-#define PROP_NAACTION_ICON_STR			"na-action-icon"
 #define PROP_NAACTION_ENABLED_STR		"na-action-enabled"
 #define PROP_NAACTION_READONLY_STR		"na-action-read-only"
 #define PROP_NAACTION_PROVIDER_STR		"na-action-provider"
@@ -108,12 +98,12 @@ static void      instance_set_property( GObject *object, guint property_id, cons
 static void      instance_dispose( GObject *object );
 static void      instance_finalize( GObject *object );
 
-static void      object_check_edited_status( const NAObject *action );
-static void      object_dump( const NAObject *action );
-static NAObject *object_duplicate( const NAObject *action );
+static NAObject *object_new( 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 *action );
+static void      object_dump( const NAObject *action );
+static gchar    *object_get_clipboard_id( const NAObject *object );
 
 static void      free_profiles( NAAction *action );
 
@@ -148,7 +138,7 @@ register_type( void )
 
 	g_debug( "%s", thisfn );
 
-	return( g_type_register_static( NA_OBJECT_TYPE, "NAAction", &info, 0 ));
+	return( g_type_register_static( NA_OBJECT_ITEM_TYPE, "NAAction", &info, 0 ));
 }
 
 static void
@@ -169,40 +159,12 @@ class_init( NAActionClass *klass )
 	object_class->get_property = instance_get_property;
 
 	spec = g_param_spec_string(
-			PROP_NAACTION_UUID_STR,
-			"Action UUID",
-			"Globally unique identifier (UUID) of the action", "",
-			G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE );
-	g_object_class_install_property( object_class, PROP_NAACTION_UUID, spec );
-
-	spec = g_param_spec_string(
-			PROP_NAACTION_LABEL_STR,
-			"Action label",
-			"Context menu displayable label", "",
-			G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE );
-	g_object_class_install_property( object_class, PROP_NAACTION_LABEL, spec );
-
-	spec = g_param_spec_string(
 			PROP_NAACTION_VERSION_STR,
 			"Version",
 			"Version of the schema", "",
 			G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE );
 	g_object_class_install_property( object_class, PROP_NAACTION_VERSION, spec );
 
-	spec = g_param_spec_string(
-			PROP_NAACTION_TOOLTIP_STR,
-			"Action tooltip",
-			"Context menu tooltip", "",
-			G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE );
-	g_object_class_install_property( object_class, PROP_NAACTION_TOOLTIP, spec );
-
-	spec = g_param_spec_string(
-			PROP_NAACTION_ICON_STR,
-			"Icon name",
-			"Context menu displayable icon", "",
-			G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE );
-	g_object_class_install_property( object_class, PROP_NAACTION_ICON, spec );
-
 	spec = g_param_spec_boolean(
 			PROP_NAACTION_ENABLED_STR,
 			"Enabled",
@@ -226,22 +188,21 @@ class_init( NAActionClass *klass )
 
 	klass->private = g_new0( NAActionClassPrivate, 1 );
 
-	NA_OBJECT_CLASS( klass )->dump = object_dump;
-	NA_OBJECT_CLASS( klass )->check_edited_status = object_check_edited_status;
-	NA_OBJECT_CLASS( klass )->duplicate = object_duplicate;
+	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_instance_init";
-	g_debug( "%s: instance=%p, klass=%p", thisfn, instance, klass );*/
-
+	/*static const gchar *thisfn = "na_action_instance_init";*/
 	NAAction *self;
 
+	/*g_debug( "%s: instance=%p, klass=%p", thisfn, ( void * ) instance, ( void * ) klass );*/
 	g_assert( NA_IS_ACTION( instance ));
 	self = NA_ACTION( instance );
 
@@ -252,8 +213,6 @@ instance_init( GTypeInstance *instance, gpointer klass )
 	/* initialize suitable default values
 	 */
 	self->private->version = g_strdup( NA_ACTION_LATEST_VERSION );
-	self->private->tooltip = g_strdup( "" );
-	self->private->icon = g_strdup( "" );
 	self->private->enabled = TRUE;
 	self->private->read_only = FALSE;
 	self->private->provider = NULL;
@@ -268,26 +227,10 @@ instance_get_property( GObject *object, guint property_id, GValue *value, GParam
 	self = NA_ACTION( object );
 
 	switch( property_id ){
-		case PROP_NAACTION_UUID:
-			G_OBJECT_CLASS( st_parent_class )->get_property( object, PROP_NAOBJECT_ID, value, spec );
-			break;
-
-		case PROP_NAACTION_LABEL:
-			G_OBJECT_CLASS( st_parent_class )->get_property( object, PROP_NAOBJECT_LABEL, value, spec );
-			break;
-
 		case PROP_NAACTION_VERSION:
 			g_value_set_string( value, self->private->version );
 			break;
 
-		case PROP_NAACTION_TOOLTIP:
-			g_value_set_string( value, self->private->tooltip );
-			break;
-
-		case PROP_NAACTION_ICON:
-			g_value_set_string( value, self->private->icon );
-			break;
-
 		case PROP_NAACTION_ENABLED:
 			g_value_set_boolean( value, self->private->enabled );
 			break;
@@ -315,29 +258,11 @@ instance_set_property( GObject *object, guint property_id, const GValue *value,
 	self = NA_ACTION( object );
 
 	switch( property_id ){
-		case PROP_NAACTION_UUID:
-			G_OBJECT_CLASS( st_parent_class )->set_property( object, PROP_NAOBJECT_ID, value, spec );
-			break;
-
-		case PROP_NAACTION_LABEL:
-			G_OBJECT_CLASS( st_parent_class )->set_property( object, PROP_NAOBJECT_LABEL, value, spec );
-			break;
-
 		case PROP_NAACTION_VERSION:
 			g_free( self->private->version );
 			self->private->version = g_value_dup_string( value );
 			break;
 
-		case PROP_NAACTION_TOOLTIP:
-			g_free( self->private->tooltip );
-			self->private->tooltip = g_value_dup_string( value );
-			break;
-
-		case PROP_NAACTION_ICON:
-			g_free( self->private->icon );
-			self->private->icon = g_value_dup_string( value );
-			break;
-
 		case PROP_NAACTION_ENABLED:
 			self->private->enabled = g_value_get_boolean( value );
 			break;
@@ -359,10 +284,10 @@ instance_set_property( GObject *object, guint property_id, const GValue *value,
 static void
 instance_dispose( GObject *object )
 {
-	static const gchar *thisfn = "na_action_instance_dispose";
+	/*static const gchar *thisfn = "na_action_instance_dispose";*/
 	NAAction *self;
 
-	g_debug( "%s: object=%p", thisfn, ( void * ) object );
+	/*g_debug( "%s: object=%p", thisfn, ( void * ) object );*/
 
 	g_assert( NA_IS_ACTION( object ));
 	self = NA_ACTION( object );
@@ -375,29 +300,29 @@ instance_dispose( GObject *object )
 		free_profiles( self );
 
 		/* 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_instance_finalize";
+	/*static const gchar *thisfn = "na_action_instance_finalize";*/
 	NAAction *self;
 
-	g_debug( "%s: object=%p", thisfn, ( void * ) object );
+	/*g_debug( "%s: object=%p", thisfn, ( void * ) object );*/
 
 	g_assert( NA_IS_ACTION( object ));
 	self = ( NAAction * ) object;
 
 	g_free( self->private->version );
-	g_free( self->private->tooltip );
-	g_free( self->private->icon );
 
 	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 );
 	}
 }
@@ -463,13 +388,7 @@ na_action_new_with_profile( void )
 gchar *
 na_action_get_uuid( const NAAction *action )
 {
-	gchar *id;
-
-	g_assert( NA_IS_ACTION( action ));
-
-	g_object_get( G_OBJECT( action ), PROP_NAACTION_UUID_STR, &id, NULL );
-
-	return( id );
+	return( na_object_get_id( NA_OBJECT( action )));
 }
 
 /**
@@ -486,13 +405,7 @@ na_action_get_uuid( const NAAction *action )
 gchar *
 na_action_get_label( const NAAction *action )
 {
-	gchar *label;
-
-	g_assert( NA_IS_ACTION( action ));
-
-	g_object_get( G_OBJECT( action ), PROP_NAACTION_LABEL_STR, &label, NULL );
-
-	return( label );
+	return( na_object_get_label( NA_OBJECT( action )));
 }
 
 /**
@@ -532,13 +445,7 @@ na_action_get_version( const NAAction *action )
 gchar *
 na_action_get_tooltip( const NAAction *action )
 {
-	gchar *tooltip;
-
-	g_assert( NA_IS_ACTION( action ));
-
-	g_object_get( G_OBJECT( action ), PROP_NAACTION_TOOLTIP_STR, &tooltip, NULL );
-
-	return( tooltip );
+	return( na_object_item_get_tooltip( NA_OBJECT_ITEM( action )));
 }
 
 /**
@@ -554,13 +461,7 @@ na_action_get_tooltip( const NAAction *action )
 gchar *
 na_action_get_icon( const NAAction *action )
 {
-	gchar *icon;
-
-	g_assert( NA_IS_ACTION( action ));
-
-	g_object_get( G_OBJECT( action ), PROP_NAACTION_ICON_STR, &icon, NULL );
-
-	return( icon );
+	return( na_object_item_get_icon( NA_OBJECT_ITEM( action )));
 }
 
 /*
@@ -569,23 +470,7 @@ na_action_get_icon( const NAAction *action )
 gchar *
 na_action_get_verified_icon_name( const NAAction *action )
 {
-	gchar *icon_name;
-
-	g_assert( NA_IS_ACTION( action ));
-
-	g_object_get( G_OBJECT( action ), PROP_NAACTION_ICON_STR, &icon_name, NULL );
-
-	if( icon_name[0] == '/' ){
-		if( !g_file_test( icon_name, G_FILE_TEST_IS_REGULAR )){
-			g_free( icon_name );
-			return NULL;
-		}
-	} else if( strlen( icon_name ) == 0 ){
-		g_free( icon_name );
-		return NULL;
-	}
-
-	return( icon_name );
+	return( na_object_item_get_verified_icon_name( NA_OBJECT_ITEM( action )));
 }
 
 /**
@@ -673,7 +558,7 @@ na_action_set_new_uuid( NAAction *action )
 	uuid_generate( uuid );
 	uuid_unparse_lower( uuid, uuid_str );
 
-	g_object_set( G_OBJECT( action ), PROP_NAACTION_UUID_STR, uuid_str, NULL );
+	na_object_set_id( NA_OBJECT( action ), uuid_str );
 }
 
 /**
@@ -700,9 +585,7 @@ na_action_set_new_uuid( NAAction *action )
 void
 na_action_set_uuid( NAAction *action, const gchar *uuid )
 {
-	g_assert( NA_IS_ACTION( action ));
-
-	g_object_set( G_OBJECT( action ), PROP_NAACTION_UUID_STR, uuid, NULL );
+	na_object_set_id( NA_OBJECT( action ), uuid );
 }
 
 /**
@@ -722,9 +605,7 @@ na_action_set_uuid( NAAction *action, const gchar *uuid )
 void
 na_action_set_label( NAAction *action, const gchar *label )
 {
-	g_assert( NA_IS_ACTION( action ));
-
-	g_object_set( G_OBJECT( action ), PROP_NAACTION_LABEL_STR, label, NULL );
+	na_object_set_label( NA_OBJECT( action ), label );
 }
 
 /**
@@ -768,9 +649,7 @@ na_action_set_version( NAAction *action, const gchar *version )
 void
 na_action_set_tooltip( NAAction *action, const gchar *tooltip )
 {
-	g_assert( NA_IS_ACTION( action ));
-
-	g_object_set( G_OBJECT( action ), PROP_NAACTION_TOOLTIP_STR, tooltip, NULL );
+	na_object_item_set_tooltip( NA_OBJECT_ITEM( action ), tooltip );
 }
 
 /**
@@ -786,9 +665,7 @@ na_action_set_tooltip( NAAction *action, const gchar *tooltip )
 void
 na_action_set_icon( NAAction *action, const gchar *icon )
 {
-	g_assert( NA_IS_ACTION( action ));
-
-	g_object_set( G_OBJECT( action ), PROP_NAACTION_ICON_STR, icon, NULL );
+	na_object_item_set_icon( NA_OBJECT_ITEM( action ), icon );
 }
 
 /**
@@ -1024,78 +901,30 @@ na_action_get_profiles_count( const NAAction *action )
 	return( g_slist_length( action->private->profiles ));
 }
 
-static void
-object_check_edited_status( const NAObject *action )
-{
-	GSList *ip;
-
-	if( st_parent_class->check_edited_status ){
-		st_parent_class->check_edited_status( action );
-	}
-
-	for( ip = NA_ACTION( action )->private->profiles ; ip ; ip = ip->next ){
-		na_object_check_edited_status( NA_OBJECT( ip->data ));
-	}
-}
-
-static void
-object_dump( const NAObject *action )
-{
-	static const gchar *thisfn = "na_action_object_dump";
-	NAAction *self;
-	GSList *item;
-
-	g_assert( NA_IS_ACTION( action ));
-	self = NA_ACTION( action );
-
-	if( st_parent_class->dump ){
-		st_parent_class->dump( action );
-	}
-
-	g_debug( "%s:   version='%s'", thisfn, self->private->version );
-	g_debug( "%s:   tooltip='%s'", thisfn, self->private->tooltip );
-	g_debug( "%s:      icon='%s'", thisfn, self->private->icon );
-	g_debug( "%s:   enabled='%s'", thisfn, self->private->enabled ? "True" : "False" );
-	g_debug( "%s: read-only='%s'", thisfn, self->private->read_only ? "True" : "False" );
-	g_debug( "%s:  provider=%p", thisfn, ( void * ) self->private->provider );
-
-	/* dump profiles */
-	g_debug( "%s: %d profile(s) at %p", thisfn, na_action_get_profiles_count( self ), ( void * ) self->private->profiles );
-	for( item = self->private->profiles ;	item != NULL ; item = item->next ){
-		na_object_dump(( const NAObject * ) item->data );
-	}
-}
-
 static NAObject *
-object_duplicate( const NAObject *action )
+object_new( const NAObject *action )
 {
-	NAObject *duplicate;
-
-	g_assert( NA_IS_ACTION( action ));
-
-	duplicate = NA_OBJECT( na_action_new());
-
-	na_object_copy( duplicate, action );
-
-	return( duplicate );
+	return( NA_OBJECT( na_action_new()));
 }
 
 void
 object_copy( NAObject *target, const NAObject *source )
 {
-	gchar *version, *tooltip, *icon;
+	gchar *version;
 	gboolean enabled, readonly;
 	gpointer provider;
 	GSList *ip;
 	NAActionProfile *profile;
 
+	if( st_parent_class->copy ){
+		st_parent_class->copy( target, source );
+	}
+
 	g_assert( NA_IS_ACTION( source ));
 	g_assert( NA_IS_ACTION( target ));
 
 	g_object_get( G_OBJECT( source ),
 			PROP_NAACTION_VERSION_STR, &version,
-			PROP_NAACTION_TOOLTIP_STR, &tooltip,
-			PROP_NAACTION_ICON_STR, &icon,
 			PROP_NAACTION_ENABLED_STR, &enabled,
 			PROP_NAACTION_READONLY_STR, &readonly,
 			PROP_NAACTION_PROVIDER_STR, &provider,
@@ -1103,50 +932,52 @@ object_copy( NAObject *target, const NAObject *source )
 
 	g_object_set( G_OBJECT( target ),
 			PROP_NAACTION_VERSION_STR, version,
-			PROP_NAACTION_TOOLTIP_STR, tooltip,
-			PROP_NAACTION_ICON_STR, icon,
 			PROP_NAACTION_ENABLED_STR, enabled,
 			PROP_NAACTION_READONLY_STR, readonly,
 			PROP_NAACTION_PROVIDER_STR, provider,
 			NULL );
 
-	g_free( tooltip );
 	g_free( version );
 
 	for( ip = NA_ACTION( source )->private->profiles ; ip ; ip = ip->next ){
 		profile = NA_ACTION_PROFILE( na_object_duplicate( NA_OBJECT( ip->data )));
 		na_action_attach_profile( NA_ACTION( target ), profile );
 	}
-
-	if( st_parent_class->copy ){
-		st_parent_class->copy( target, source );
-	}
 }
 
 static gboolean
 object_are_equal( const NAObject *a, const NAObject *b )
 {
-	NAAction *first = NA_ACTION( a );
-	NAAction *second = NA_ACTION( b );
-	gboolean equal;
+	NAAction *first, *second;
+	gboolean equal = TRUE;
 	NAActionProfile *first_profile, *second_profile;
 	gchar *first_name, *second_name;
 
+	if( equal ){
+		if( st_parent_class->are_equal ){
+			equal = st_parent_class->are_equal( a, b );
+		}
+	}
+
 	g_assert( NA_IS_ACTION( a ));
+	first = NA_ACTION( a );
+
 	g_assert( NA_IS_ACTION( b ));
+	second = NA_ACTION( b );
 
-	equal =
-		( g_utf8_collate( first->private->version, second->private->version ) == 0 ) &&
-		( g_utf8_collate( first->private->tooltip, second->private->tooltip ) == 0 ) &&
-		( g_utf8_collate( first->private->icon, second->private->icon ) == 0 );
+	if( equal ){
+		equal = ( g_utf8_collate( first->private->version, second->private->version ) == 0 );
+	}
 
 	if( equal ){
 		equal = ( first->private->enabled && second->private->enabled ) ||
 				( !first->private->enabled && !second->private->enabled );
 	}
+
 	if( equal ){
 		equal = ( g_slist_length( first->private->profiles ) == g_slist_length( second->private->profiles ));
 	}
+
 	if( equal ){
 		GSList *ip;
 		for( ip = first->private->profiles ; ip && equal ; ip = ip->next ){
@@ -1161,6 +992,7 @@ object_are_equal( const NAObject *a, const NAObject *b )
 			g_free( first_name );
 		}
 	}
+
 	if( equal ){
 		GSList *ip;
 		for( ip = second->private->profiles ; ip && equal ; ip = ip->next ){
@@ -1175,39 +1007,66 @@ object_are_equal( const NAObject *a, const NAObject *b )
 			g_free( second_name );
 		}
 	}
-	if( equal ){
-		if( st_parent_class->are_equal ){
-			equal = st_parent_class->are_equal( a, b );
-		}
-	}
 
 	return( equal );
 }
 
+/*
+ * a valid NAAction 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;
+	gboolean is_valid = TRUE;
 	GSList *ip;
 
+	if( is_valid ){
+		if( st_parent_class->is_valid ){
+			is_valid = st_parent_class->is_valid( action );
+		}
+	}
+
 	g_assert( NA_IS_ACTION( action ));
 
-	g_object_get( G_OBJECT( action ), PROP_NAACTION_LABEL_STR, &label, NULL );
-	is_valid = ( label && g_utf8_strlen( label, -1 ) > 0 );
-	g_free( label );
+	if( is_valid ){
+		label = na_action_get_label( NA_ACTION( action ));
+		is_valid = ( label && g_utf8_strlen( label, -1 ) > 0 );
+		g_free( label );
+	}
 
 	for( ip = NA_ACTION( action )->private->profiles ; ip && is_valid ; ip = ip->next ){
 		is_valid = na_object_is_valid( NA_OBJECT( ip->data ));
 	}
 
-	if( is_valid ){
-		if( st_parent_class->is_valid ){
-			is_valid = st_parent_class->is_valid( action );
-		}
+	return( is_valid );
+}
+
+static void
+object_dump( const NAObject *action )
+{
+	static const gchar *thisfn = "na_action_object_dump";
+	NAAction *self;
+	GSList *item;
+
+	if( st_parent_class->dump ){
+		st_parent_class->dump( action );
 	}
 
-	return( is_valid );
+	g_assert( NA_IS_ACTION( action ));
+	self = NA_ACTION( action );
+
+	g_debug( "%s:   version='%s'", thisfn, self->private->version );
+	g_debug( "%s:   enabled='%s'", thisfn, self->private->enabled ? "True" : "False" );
+	g_debug( "%s: read-only='%s'", thisfn, self->private->read_only ? "True" : "False" );
+	g_debug( "%s:  provider=%p", thisfn, ( void * ) self->private->provider );
+
+	/* dump profiles */
+	g_debug( "%s: %d profile(s) at %p", thisfn, na_action_get_profiles_count( self ), ( void * ) self->private->profiles );
+	for( item = self->private->profiles ;	item != NULL ; item = item->next ){
+		na_object_dump(( const NAObject * ) item->data );
+	}
 }
 
 static void
@@ -1217,3 +1076,16 @@ free_profiles( NAAction *action )
 
 	action->private->profiles = NULL;
 }
+
+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 );
+}
diff --git a/src/common/na-action.h b/src/common/na-action.h
index c9a80a8..9b0f525 100644
--- a/src/common/na-action.h
+++ b/src/common/na-action.h
@@ -48,7 +48,10 @@
 
 G_BEGIN_DECLS
 
+/* i18n: default label for a newly created action */
 #define NA_ACTION_DEFAULT_LABEL			_( "New Nautilus action" )
+
+/* i18n: default label for a newly created profile */
 #define NA_ACTION_PROFILE_DEFAULT_LABEL	_( "Default profile" )
 
 NAAction        *na_action_new( void );
@@ -69,7 +72,7 @@ void             na_action_set_uuid( NAAction *action, const gchar *uuid );
 void             na_action_set_label( NAAction *action, const gchar *label );
 void             na_action_set_version( NAAction *action, const gchar *version );
 void             na_action_set_tooltip( NAAction *action, const gchar *tooltip );
-void             na_action_set_icon( NAAction *action, const gchar *icon_name );
+void             na_action_set_icon( NAAction *action, const gchar *icon );
 void             na_action_set_enabled( NAAction *action, gboolean enabled );
 void             na_action_set_readonly( NAAction *action, gboolean readonly );
 void             na_action_set_provider( NAAction *action, const NAIIOProvider *provider );
diff --git a/src/common/na-gconf.c b/src/common/na-gconf.c
index 80656b1..42a5b0c 100644
--- a/src/common/na-gconf.c
+++ b/src/common/na-gconf.c
@@ -41,6 +41,7 @@
 #include "na-gconf.h"
 #include "na-gconf-keys.h"
 #include "na-iio-provider.h"
+#include "na-iprefs.h"
 #include "na-utils.h"
 
 /* private class data
@@ -115,7 +116,7 @@ static guint          install_gconf_watch( NAGConf *gconf );
 static void           install_gconf_watched_dir( NAGConf *gconf );
 static void           remove_gconf_watch( NAGConf *gconf );
 static void           remove_gconf_watched_dir( NAGConf *gconf );
-static void           action_changed_cb( GConfClient *client, guint cnxn_id, GConfEntry *entry, gpointer user_data );
+static void           gconf_dir_changed_cb( GConfClient *client, guint cnxn_id, GConfEntry *entry, gpointer user_data );
 
 GType
 na_gconf_get_type( void )
@@ -1115,7 +1116,7 @@ install_gconf_watch( NAGConf *gconf )
 		gconf_client_notify_add(
 			gconf->private->gconf,
 			NA_GCONF_CONFIG_PATH,
-			( GConfClientNotifyFunc ) action_changed_cb,
+			( GConfClientNotifyFunc ) gconf_dir_changed_cb,
 			gconf,
 			NULL,
 			&error
@@ -1140,7 +1141,15 @@ install_gconf_watched_dir( NAGConf *gconf )
 			gconf->private->gconf, NA_GCONF_CONFIG_PATH, GCONF_CLIENT_PRELOAD_RECURSIVE, &error );
 
 	if( error ){
-		g_warning( "%s: error=%s", thisfn, error->message );
+		g_warning( "%s: path=%s, error=%s", thisfn, NA_GCONF_CONFIG_PATH, error->message );
+		g_error_free( error );
+	}
+
+	gconf_client_add_dir(
+			gconf->private->gconf, NA_GCONF_PREFS_PATH, GCONF_CLIENT_PRELOAD_ONELEVEL, &error );
+
+	if( error ){
+		g_warning( "%s: path=%s, error=%s", thisfn, NA_GCONF_PREFS_PATH, error->message );
 		g_error_free( error );
 	}
 }
@@ -1188,20 +1197,41 @@ remove_gconf_watched_dir( NAGConf *gconf )
  * 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 watch mechanism
+ *
+ * Please note that this handler is also called when a preference is
+ * changed, in order to advertise Nautilus when the display mode of
+ * actions is modified. So we have to check the entry to see if a
+ * message is needed to be sent.
  */
 static void
-action_changed_cb( GConfClient *client, guint cnxn_id, GConfEntry *entry, gpointer user_data )
+gconf_dir_changed_cb( GConfClient *client, guint cnxn_id, GConfEntry *entry, gpointer user_data )
 {
 	/*static const gchar *thisfn = "action_changed_cb";*/
 	/*g_debug( "%s: client=%p, cnxnid=%u, entry=%p, user_data=%p", thisfn, client, cnxn_id, entry, user_data );*/
 	NAGConf *gconf;
 	NAPivotNotify *npn;
+	const char *key;
 
 	g_assert( NA_IS_GCONF( user_data ));
 
 	gconf = NA_GCONF( user_data );
 	g_assert( NA_IS_IIO_PROVIDER( gconf ));
 
-	npn = entry_to_notify( entry );
-	g_signal_emit_by_name( gconf->private->notified, NA_IIO_PROVIDER_SIGNAL_ACTION_CHANGED, npn );
+	key = gconf_entry_get_key( entry );
+
+	if( !strncmp( key, NA_GCONF_CONFIG_PATH, strlen( NA_GCONF_CONFIG_PATH ))){
+		npn = entry_to_notify( entry );
+		g_signal_emit_by_name( gconf->private->notified, NA_IIO_PROVIDER_SIGNAL_ACTION_CHANGED, npn );
+		return;
+	}
+
+	if( strstr( key, PREFS_DISPLAY_ALPHABETICAL_ORDER ) != NULL ){
+		g_signal_emit_by_name( gconf->private->notified, NA_IIO_PROVIDER_SIGNAL_DISPLAY_ORDER_CHANGED, NULL );
+		return;
+	}
+
+	if( strstr( key, PREFS_ADD_ABOUT_ITEM ) != NULL ){
+		g_signal_emit_by_name( gconf->private->notified, NA_IIO_PROVIDER_SIGNAL_DISPLAY_ABOUT_CHANGED, NULL );
+		return;
+	}
 }
diff --git a/src/common/na-iduplicable.c b/src/common/na-iduplicable.c
index 3ba412e..d443940 100644
--- a/src/common/na-iduplicable.c
+++ b/src/common/na-iduplicable.c
@@ -40,26 +40,27 @@ struct NAIDuplicableInterfacePrivate {
 	void *empty;						/* so that gcc -pedantic is happy */
 };
 
-/* data set against GObject
+/* 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"
 
-static GType     register_type( void );
-static void      interface_base_init( NAIDuplicableInterface *klass );
-static void      interface_base_finalize( NAIDuplicableInterface *klass );
+static GType          register_type( void );
+static void           interface_base_init( NAIDuplicableInterface *klass );
+static void           interface_base_finalize( NAIDuplicableInterface *klass );
 
-static NAObject *v_duplicate( const NAObject *object );
-static gboolean  v_are_equal( const NAObject *a, const NAObject *b );
-static gboolean  v_is_valid( const NAObject *object );
+static void           v_copy( NAIDuplicable *target, const NAIDuplicable *source );
+static NAIDuplicable *v_new( const NAIDuplicable *object );
+static gboolean       v_are_equal( const NAIDuplicable *a, const NAIDuplicable *b );
+static gboolean       v_is_valid( const NAIDuplicable *object );
 
-static NAObject *get_origin( const NAObject *object );
-static void      set_origin( const NAObject *object, const NAObject *origin );
-static gboolean  get_modified( const NAObject *object );
-static void      set_modified( const NAObject *object, gboolean is_modified );
-static gboolean  get_valid( const NAObject *object );
-static void      set_valid( const NAObject *object, gboolean is_valid );
+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 gboolean       get_valid( const NAIDuplicable *object );
+static void           set_valid( const NAIDuplicable *object, gboolean is_valid );
 
 GType
 na_iduplicable_get_type( void )
@@ -132,17 +133,17 @@ interface_base_finalize( NAIDuplicableInterface *klass )
 
 /**
  * na_iduplicable_init:
- * @object: the #NAObject object to be initialized.
+ * @object: the #NAIDuplicable object to be initialized.
  *
  * Initializes the properties of a IDuplicable object.
  *
- * This function should be called when creating the object, e.g. from
- * instance_init().
+ * This function should be called by the implementor when creating the
+ * object, e.g. from instance_init().
  */
 void
-na_iduplicable_init( NAObject *object )
+na_iduplicable_init( NAIDuplicable *object )
 {
-	g_assert( NA_IS_OBJECT( object ));
+	g_assert( G_IS_OBJECT( object ));
 	g_assert( NA_IS_IDUPLICABLE( object ));
 
 	set_origin( object, NULL );
@@ -152,20 +153,23 @@ na_iduplicable_init( NAObject *object )
 
 /**
  * na_iduplicable_dump:
- * @object: the #NAObject object to be duplicated.
+ * @object: the #NAIDuplicable object to be dumped.
  *
  * Dumps via g_debug the properties of the object.
+ *
+ * We ouput here only the data we set ourselves againt the
+ * #NAIDuplicable-implemented object.
  */
 void
-na_iduplicable_dump( const NAObject *object )
+na_iduplicable_dump( const NAIDuplicable *object )
 {
 	static const gchar *thisfn = "na_iduplicable_dump";
-	NAObject *origin = NULL;
+	NAIDuplicable *origin = NULL;
 	gboolean modified = FALSE;
-	gboolean valid = TRUE;
+	gboolean valid = FALSE;				/* may a NULL object be valid ? */
 
 	if( object ){
-		g_assert( NA_IS_OBJECT( object ));
+		g_assert( G_IS_OBJECT( object ));
 		g_assert( NA_IS_IDUPLICABLE( object ));
 
 		origin = get_origin( object );
@@ -180,9 +184,9 @@ na_iduplicable_dump( const NAObject *object )
 
 /**
  * na_iduplicable_duplicate:
- * @object: the #NAObject object to be duplicated.
+ * @object: the #NAIDuplicable object to be duplicated.
  *
- * Exactly duplicates a #NAObject-derived object.
+ * Exactly duplicates a #NAIDuplicable-implemented object.
  * Properties %PROP_IDUPLICABLE_ORIGIN, %PROP_IDUPLICABLE_ISMODIFIED
  * and %PROP_IDUPLICABLE_ISVALID are initialized to their default
  * values.
@@ -190,25 +194,28 @@ na_iduplicable_dump( const NAObject *object )
  * As %PROP_IDUPLICABLE_ISVALID property is set to %TRUE without any
  * further check, this suppose that only valid objects are duplicated.
  *
- * Returns: a new #NAObject.
+ * Returns: a new #NAIDuplicable.
  */
-NAObject *
-na_iduplicable_duplicate( const NAObject *object )
+NAIDuplicable *
+na_iduplicable_duplicate( const NAIDuplicable *object )
 {
 	static const gchar *thisfn = "na_iduplicable_duplicate";
-	NAObject *dup = NULL;
+	NAIDuplicable *dup = NULL;
 
 	g_debug( "%s: object=%p", thisfn, ( void * ) object );
 
 	if( object ){
-		g_assert( NA_IS_OBJECT( object ));
+		g_assert( G_IS_OBJECT( object ));
 		g_assert( NA_IS_IDUPLICABLE( object ));
 
-		dup = v_duplicate( object );
+		dup = v_new( 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 );
@@ -216,10 +223,10 @@ na_iduplicable_duplicate( const NAObject *object )
 
 /**
  * na_iduplicable_check_edited_status:
- * @object: the #NAObject object to be checked.
+ * @object: the #NAIDuplicable object to be checked.
  *
- * Checks the edition status of the #NAObject object, and set up the
- * corresponding %PROP_IDUPLICABLE_ISMODIFIED and
+ * Checks the edition status of the #NAIDuplicable object, and set up
+ * the corresponding %PROP_IDUPLICABLE_ISMODIFIED and
  * %PROP_IDUPLICABLE_ISVALID properties.
  *
  * This function is supposed to be called each time the object may have
@@ -228,16 +235,16 @@ na_iduplicable_duplicate( const NAObject *object )
  * then only return the current value of the properties.
  */
 void
-na_iduplicable_check_edited_status( const NAObject *object )
+na_iduplicable_check_edited_status( const NAIDuplicable *object )
 {
 	/*static const gchar *thisfn = "na_iduplicable_check_edited_status";
 	g_debug( "%s: object=%p", thisfn, object );*/
 	gboolean modified = TRUE;
-	NAObject *origin;
+	NAIDuplicable *origin;
 	gboolean valid;
 
 	if( object ){
-		g_assert( NA_IS_OBJECT( object ));
+		g_assert( G_IS_OBJECT( object ));
 		g_assert( NA_IS_IDUPLICABLE( object ));
 
 		origin = get_origin( object );
@@ -253,7 +260,7 @@ na_iduplicable_check_edited_status( const NAObject *object )
 
 /**
  * na_iduplicable_is_modified:
- * @object: the #NAObject object whose status is to be returned.
+ * @object: the #NAIDuplicable object whose status is to be returned.
  *
  * Returns the current value of the %PROP_IDUPLICABLE_ISMODIFIED
  * property without rechecking the edition status itself.
@@ -262,14 +269,14 @@ na_iduplicable_check_edited_status( const NAObject *object )
  * the original one.
  */
 gboolean
-na_iduplicable_is_modified( const NAObject *object )
+na_iduplicable_is_modified( const NAIDuplicable *object )
 {
 	/*static const gchar *thisfn = "na_iduplicable_is_modified";
 	g_debug( "%s: object=%p", thisfn, object );*/
 	gboolean is_modified = FALSE;
 
 	if( object ){
-		g_assert( NA_IS_OBJECT( object ));
+		g_assert( G_IS_OBJECT( object ));
 		g_assert( NA_IS_IDUPLICABLE( object ));
 
 		is_modified = get_modified( object );
@@ -280,7 +287,7 @@ na_iduplicable_is_modified( const NAObject *object )
 
 /**
  * na_iduplicable_is_valid:
- * @object: the #NAObject object whose status is to be returned.
+ * @object: the #NAIDuplicable object whose status is to be returned.
  *
  * Returns the current value of the %PROP_IDUPLICABLE_ISVALID property
  * without rechecking the edition status itself.
@@ -288,14 +295,14 @@ na_iduplicable_is_modified( const NAObject *object )
  * Returns: %TRUE is the provided object is valid.
  */
 gboolean
-na_iduplicable_is_valid( const NAObject *object )
+na_iduplicable_is_valid( const NAIDuplicable *object )
 {
 	/*static const gchar *thisfn = "na_iduplicable_is_valid";
 	g_debug( "%s: object=%p", thisfn, object );*/
 	gboolean is_valid = FALSE;
 
 	if( object ){
-		g_assert( NA_IS_OBJECT( object ));
+		g_assert( G_IS_OBJECT( object ));
 		g_assert( NA_IS_IDUPLICABLE( object ));
 
 		is_valid = get_valid( object );
@@ -306,21 +313,21 @@ na_iduplicable_is_valid( const NAObject *object )
 
 /**
  * na_iduplicable_get_origin:
- * @object: the #NAObject object whose origin is to be returned.
+ * @object: the #NAIDuplicable object whose origin is to be returned.
  *
- * Returns the origin of a duplicated #NAObject.
+ * Returns the origin of a duplicated #NAIDuplicable.
  *
- * Returns: the original #NAObject, or NULL.
+ * Returns: the original #NAIDuplicable, or NULL.
  */
-NAObject *
-na_iduplicable_get_origin( const NAObject *object )
+NAIDuplicable *
+na_iduplicable_get_origin( const NAIDuplicable *object )
 {
 	/*static const gchar *thisfn = "na_iduplicable_is_valid";
 	g_debug( "%s: object=%p", thisfn, object );*/
-	NAObject *origin = NULL;
+	NAIDuplicable *origin = NULL;
 
 	if( object ){
-		g_assert( NA_IS_OBJECT( object ));
+		g_assert( G_IS_OBJECT( object ));
 		g_assert( NA_IS_IDUPLICABLE( object ));
 
 		origin = get_origin( object );
@@ -331,93 +338,95 @@ na_iduplicable_get_origin( const NAObject *object )
 
 /**
  * na_iduplicable_set_origin:
- * @object: the #NAObject object whose origin is to be returned.
- * @origin: the new original #NAObject.
+ * @object: the #NAIDuplicable object whose origin is to be returned.
+ * @origin: the new original #NAIDuplicable.
  *
- * Sets the new origin of a duplicated #NAObject.
+ * Sets the new origin of a duplicated #NAIDuplicable.
  */
 void
-na_iduplicable_set_origin( NAObject *object, const NAObject *origin )
+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( NA_IS_OBJECT( object ));
+		g_assert( G_IS_OBJECT( object ));
 		g_assert( NA_IS_IDUPLICABLE( object ));
 
 		set_origin( object, origin );
 	}
 }
 
-static NAObject *
-v_duplicate( const NAObject *object )
+static void
+v_copy( NAIDuplicable *target, const NAIDuplicable *source )
 {
-	NAIDuplicable *instance = NA_IDUPLICABLE( object );
+	if( NA_IDUPLICABLE_GET_INTERFACE( target )->copy ){
+		NA_IDUPLICABLE_GET_INTERFACE( target )->copy( target, source );
+	}
+}
 
-	if( NA_IDUPLICABLE_GET_INTERFACE( instance )->duplicate ){
-		return( NA_IDUPLICABLE_GET_INTERFACE( instance )->duplicate( object ));
+static NAIDuplicable *
+v_new( const NAIDuplicable *object )
+{
+	if( NA_IDUPLICABLE_GET_INTERFACE( object )->new ){
+		return( NA_IDUPLICABLE_GET_INTERFACE( object )->new( object ));
 	}
 
 	return( NULL );
 }
 
 static gboolean
-v_are_equal( const NAObject *a, const NAObject *b )
+v_are_equal( const NAIDuplicable *a, const NAIDuplicable *b )
 {
-	NAIDuplicable *instance = NA_IDUPLICABLE( a );
-
-	if( NA_IDUPLICABLE_GET_INTERFACE( instance )->are_equal ){
-		return( NA_IDUPLICABLE_GET_INTERFACE( instance )->are_equal( a, b ));
+	if( NA_IDUPLICABLE_GET_INTERFACE( a )->are_equal ){
+		return( NA_IDUPLICABLE_GET_INTERFACE( a )->are_equal( a, b ));
 	}
 
 	return( TRUE );
 }
 
 static gboolean
-v_is_valid( const NAObject *object )
+v_is_valid( const NAIDuplicable *object )
 {
-	NAIDuplicable *instance = NA_IDUPLICABLE( object );
-
-	if( NA_IDUPLICABLE_GET_INTERFACE( instance )->is_valid ){
-		return( NA_IDUPLICABLE_GET_INTERFACE( instance )->is_valid( object ));
+	if( NA_IDUPLICABLE_GET_INTERFACE( object )->is_valid ){
+		return( NA_IDUPLICABLE_GET_INTERFACE( object )->is_valid( object ));
 	}
 
 	return( TRUE );
 }
 
-static NAObject *
-get_origin( const NAObject *object )
+static NAIDuplicable *
+get_origin( const NAIDuplicable *object )
 {
-	return( NA_OBJECT( g_object_get_data( G_OBJECT( object ), PROP_IDUPLICABLE_ORIGIN )));
+	return( NA_IDUPLICABLE( g_object_get_data( G_OBJECT( object ), PROP_IDUPLICABLE_ORIGIN )));
 }
 
 static void
-set_origin( const NAObject *object, const NAObject *origin )
+set_origin( const NAIDuplicable *object, const NAIDuplicable *origin )
 {
 	g_object_set_data( G_OBJECT( object ), PROP_IDUPLICABLE_ORIGIN, ( gpointer ) origin );
 }
 
 static gboolean
-get_modified( const NAObject *object )
+get_modified( const NAIDuplicable *object )
 {
 	return(( gboolean ) GPOINTER_TO_UINT( g_object_get_data( G_OBJECT( object ), PROP_IDUPLICABLE_ISMODIFIED )));
 }
 
 static void
-set_modified( const NAObject *object, gboolean is_modified )
+set_modified( const NAIDuplicable *object, gboolean is_modified )
 {
 	g_object_set_data( G_OBJECT( object ), PROP_IDUPLICABLE_ISMODIFIED, GUINT_TO_POINTER( is_modified ));
 }
 
 static gboolean
-get_valid( const NAObject *object )
+get_valid( const NAIDuplicable *object )
 {
 	return(( gboolean ) GPOINTER_TO_UINT( g_object_get_data( G_OBJECT( object ), PROP_IDUPLICABLE_ISVALID )));
 }
 
 static void
-set_valid( const NAObject *object, gboolean is_valid )
+set_valid( const NAIDuplicable *object, gboolean is_valid )
 {
 	g_object_set_data( G_OBJECT( object ), PROP_IDUPLICABLE_ISVALID, GUINT_TO_POINTER( is_valid ));
 }
diff --git a/src/common/na-iduplicable.h b/src/common/na-iduplicable.h
index 0536b46..65b7421 100644
--- a/src/common/na-iduplicable.h
+++ b/src/common/na-iduplicable.h
@@ -46,7 +46,7 @@
  * will stay in life at least as long as the duplicated one.
  */
 
-#include "na-object.h"
+#include <glib-object.h>
 
 G_BEGIN_DECLS
 
@@ -64,65 +64,75 @@ typedef struct {
 	NAIDuplicableInterfacePrivate *private;
 
 	/**
-	 * duplicate:
-	 * @object: the #NAObject object to be duplicated.
+	 * get_new_instance:
+	 * @nstance: a #NAIDuplicable instance of the klass of which we
+	 * want a new instance.
 	 *
-	 * Allocates an exact copy of the specified #NAObject object.
+	 * Returns a new instance of the same class.
 	 *
-	 * The implementor should define a duplicate()-equivalent virtual
-	 * function in order the new #NAObject-derived object be allocated
-	 * with the right most-derived class.
-	 *
-	 * The implementor should also define a copy()-equivalent virtual
-	 * function so that each class in the derivation hierarchy be able
-	 * to copy its own data and properties to the target instance.
+	 * Returns: a newly allocated #NAIDuplicable object.
+	 */
+	NAIDuplicable * ( *new )      ( const NAIDuplicable *object );
+
+	/**
+	 * copy:
+	 * @target: the #NAIDuplicable target of the copy.
+	 * @source: the #NAIDuplicable source of the copy
 	 *
-	 * Returns: a newly allocated #NAObject object, which is an exact
-	 * copy of @object.
+	 * Copies data from @source to @ŧarget, so that @target becomes an
+	 * exact copy of @source.
 	 */
-	NAObject * ( *duplicate )( const NAObject *object );
+	void            ( *copy )     ( NAIDuplicable *target, const NAIDuplicable *source );
 
 	/**
 	 * are_equal:
-	 * @a: a first #NAObject object.
-	 * @b: a second #NAObject object to be compared to the first one.
+	 * @a: a first #NAIDuplicable object.
+	 * @b: a second #NAIDuplicable object to be compared to the first
+	 * one.
 	 *
 	 * Compares the two objects.
 	 *
 	 * The implementor should define a are_equal()-equivalent virtual
-	 * function so that each #NAObject-derived class be able to check
-	 * for identity.
+	 * function so that each #NAIDuplicable-derived class be able to
+	 * check for identity.
 	 *
 	 * Returns: %TRUE if @a and @b are identical, %FALSE else.
 	 */
-	gboolean   ( *are_equal )( const NAObject *a, const NAObject *b );
+	gboolean        ( *are_equal )( const NAIDuplicable *a, const NAIDuplicable *b );
 
 	/**
 	 * is_valid:
-	 * @object: the #NAObject object to be checked.
+	 * @object: the #NAIDuplicable object to be checked.
 	 *
 	 * Checks @object for validity.
 	 *
 	 * The implementor should define a is_valid()-equivalent virtual
-	 * function so that each #NAObject-derived class be able to check
-	 * for validity.
+	 * function so that each #NAIDuplicable-derived class be able to
+	 * check for validity.
 	 *
 	 * Returns: %TRUE if @object is valid, %FALSE else.
 	 */
-	gboolean   ( *is_valid ) ( const NAObject *object );
+	gboolean        ( *is_valid ) ( const NAIDuplicable *object );
 }
 	NAIDuplicableInterface;
 
-GType     na_iduplicable_get_type( void );
+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 );
+
+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_init( NAObject *object );
-void      na_iduplicable_dump( const NAObject *object );
-NAObject *na_iduplicable_duplicate( const NAObject *object );
-void      na_iduplicable_check_edited_status( const NAObject *object );
-gboolean  na_iduplicable_is_modified( const NAObject *object );
-gboolean  na_iduplicable_is_valid( const NAObject *object );
-NAObject *na_iduplicable_get_origin( const NAObject *object );
-void      na_iduplicable_set_origin( NAObject *object, const NAObject *origin );
+void           na_iduplicable_set_origin( NAIDuplicable *object, const NAIDuplicable *origin );
 
 G_END_DECLS
 
diff --git a/src/common/na-iio-provider.c b/src/common/na-iio-provider.c
index 23b92f7..7f94f58 100644
--- a/src/common/na-iio-provider.c
+++ b/src/common/na-iio-provider.c
@@ -48,7 +48,6 @@ static void     interface_base_finalize( NAIIOProviderInterface *klass );
 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 GSList  *sort_actions( const NAPivot *pivot, GSList *actions );
 static gint     compare_actions_label_alpha_fn( const NAAction *a, const NAAction *b );
 
 /**
@@ -173,7 +172,28 @@ na_iio_provider_read_actions( const NAPivot *pivot )
 		}
 	}
 
-	return( sort_actions( pivot, actions ));
+	/* TODO: should be done only if prefs is set */
+	return( na_iio_provider_sort_actions( pivot, actions ));
+}
+
+/**
+ * na_iio_provider_sort_action:
+ * @pivot: the #NAPivot object which owns the list of registered I/O
+ * storage providers.
+ * @actions: the list of #NAAction action to be sorted.
+ *
+ * Sorts the list of actions in alphabetical order of their label.
+ *
+ * Returns: the sorted list.
+ */
+GSList *
+na_iio_provider_sort_actions( const NAPivot *pivot, GSList *actions )
+{
+	GSList *sorted;
+
+	sorted = g_slist_sort( actions, ( GCompareFunc ) compare_actions_label_alpha_fn );
+
+	return( sorted );
 }
 
 /**
@@ -319,20 +339,6 @@ write_action( const NAIIOProvider *provider, NAAction *action, gchar **message )
 	return( NA_IIO_PROVIDER_GET_INTERFACE( provider )->write_action( provider, action, message ));
 }
 
-/*
- * sort the actions so that they are in the same order than when they
- * are displayed in NACT
- */
-static GSList *
-sort_actions( const NAPivot *pivot, GSList *actions )
-{
-	GSList *sorted;
-
-	sorted = g_slist_sort( actions, ( GCompareFunc ) compare_actions_label_alpha_fn );
-
-	return( sorted );
-}
-
 static gint
 compare_actions_label_alpha_fn( const NAAction *a, const NAAction *b )
 {
diff --git a/src/common/na-iio-provider.h b/src/common/na-iio-provider.h
index 87481f3..cfbaca5 100644
--- a/src/common/na-iio-provider.h
+++ b/src/common/na-iio-provider.h
@@ -131,12 +131,15 @@ typedef struct {
 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 );
 
 /* modification notification message to NAPivot
  */
-#define NA_IIO_PROVIDER_SIGNAL_ACTION_CHANGED		"notify_pivot_of_action_changed"
+#define NA_IIO_PROVIDER_SIGNAL_ACTION_CHANGED			"notify-consumer-of-action-change"
+#define NA_IIO_PROVIDER_SIGNAL_DISPLAY_ORDER_CHANGED	"notify-consumer-of-display-order-change"
+#define NA_IIO_PROVIDER_SIGNAL_DISPLAY_ABOUT_CHANGED	"notify-consumer-of-display-about-change"
 
 /* return code of update/write/delete operations
  */
diff --git a/src/common/na-ipivot-consumer.c b/src/common/na-ipivot-consumer.c
index a98c554..a080329 100644
--- a/src/common/na-ipivot-consumer.c
+++ b/src/common/na-ipivot-consumer.c
@@ -151,7 +151,8 @@ na_ipivot_consumer_delay_notify( NAIPivotConsumer *instance )
  * @instance: the #NAIPivotConsumer instance to be notified of the end
  * of the modifications.
  *
- * Notifies the consumers that the actions have been modified.
+ * Notifies the consumers that the actions have been modified on one of
+ * the underlying storage subsystems.
  */
 void na_ipivot_consumer_notify( NAIPivotConsumer *instance )
 {
@@ -166,6 +167,37 @@ void na_ipivot_consumer_notify( NAIPivotConsumer *instance )
 	}
 }
 
+/**
+ * na_ipivot_consumer_notify:
+ * @instance: the #NAIPivotConsumer instance to be notified of the end
+ * of the modifications.
+ *
+ * Notifies the consumers that the display order has been changed.
+ */
+void
+na_ipivot_consumer_notify_display_order_change( NAIPivotConsumer *instance )
+{
+	if( NA_IPIVOT_CONSUMER_GET_INTERFACE( instance )->on_display_order_changed ){
+		NA_IPIVOT_CONSUMER_GET_INTERFACE( instance )->on_display_order_changed( instance, NULL );
+	}
+}
+
+/**
+ * na_ipivot_consumer_notify:
+ * @instance: the #NAIPivotConsumer instance to be notified of the end
+ * of the modifications.
+ *
+ * Notifies the consumers that the setting of the display of an 'About'
+ * item in the Nautilus context menu has been changed.
+ */
+void
+na_ipivot_consumer_notify_display_about_change( NAIPivotConsumer *instance )
+{
+	if( NA_IPIVOT_CONSUMER_GET_INTERFACE( instance )->on_display_about_changed ){
+		NA_IPIVOT_CONSUMER_GET_INTERFACE( instance )->on_display_about_changed( instance, NULL );
+	}
+}
+
 static gboolean
 is_notify_allowed( const NAIPivotConsumer *instance )
 {
diff --git a/src/common/na-ipivot-consumer.h b/src/common/na-ipivot-consumer.h
index dc3ce56..5d27b3b 100644
--- a/src/common/na-ipivot-consumer.h
+++ b/src/common/na-ipivot-consumer.h
@@ -69,7 +69,31 @@ typedef struct {
 	 * a bunch of modifications. At this time, the embedded list of
 	 * #NAAction has been updated to be up to date.
 	 */
-	void ( *on_actions_changed )( NAIPivotConsumer *instance, gpointer user_data );
+	void ( *on_actions_changed )      ( NAIPivotConsumer *instance, gpointer user_data );
+
+	/**
+	 * on_display_about_changed:
+	 * @instance: the #NAIPivotConsumer instance which implements this
+	 * interface.
+	 * user_data: user data set when emitting the message. Currently,
+	 * not used.
+	 *
+	 * This function is triggered each time the setting of the display
+	 * of an 'About' item in the Nautilus context menu is changed.
+	 */
+	void ( *on_display_about_changed )( NAIPivotConsumer *instance, gpointer user_data );
+
+	/**
+	 * on_display_order_changed:
+	 * @instance: the #NAIPivotConsumer instance which implements this
+	 * interface.
+	 * user_data: user data set when emitting the message. Currently,
+	 * not used.
+	 *
+	 * This function is triggered each time the display order preference
+	 * is changed.
+	 */
+	void ( *on_display_order_changed )( NAIPivotConsumer *instance, gpointer user_data );
 }
 	NAIPivotConsumerInterface;
 
@@ -78,6 +102,8 @@ GType na_ipivot_consumer_get_type( void );
 void  na_ipivot_consumer_delay_notify( NAIPivotConsumer *instance );
 
 void  na_ipivot_consumer_notify( NAIPivotConsumer *instance );
+void  na_ipivot_consumer_notify_display_order_change( NAIPivotConsumer *instance );
+void  na_ipivot_consumer_notify_display_about_change( NAIPivotConsumer *instance );
 
 G_END_DECLS
 
diff --git a/src/common/na-iprefs.c b/src/common/na-iprefs.c
index b4f0a6d..18a5ab1 100644
--- a/src/common/na-iprefs.c
+++ b/src/common/na-iprefs.c
@@ -48,7 +48,7 @@ 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 );
+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 );
 
 GType
@@ -123,41 +123,106 @@ interface_base_finalize( NAIPrefsInterface *klass )
 }
 
 /**
- * Get/set a named boolean.
+ * na_iprefs_get_alphabetical_order:
+ * @instance: this #NAIPrefs interface instance.
  *
- * @window: this NAWindow-derived window.
+ * Returns: #TRUE if the actions are to be maintained in alphabetical
+ * order of their label, #FALSE else.
+ *
+ * Note: this function returns a suitable default value if the key is
+ * not found in GConf preferences.
+ *
+ * Note: please take care of keeping the default value synchronized with
+ * those defined in schemas.
+ */
+gboolean na_iprefs_get_alphabetical_order( NAIPrefs *instance )
+{
+	return( read_key_bool( instance, PREFS_DISPLAY_ALPHABETICAL_ORDER, TRUE ));
+}
+
+/**
+ * na_iprefs_get_add_about_item:
+ * @instance: this #NAIPrefs interface instance.
+ *
+ * Returns: #TRUE if an "About Nautilus Actions" item may be added to
+ * the first level of Nautilus context submenus (if any), #FALSE else.
+ *
+ * Note: this function returns a suitable default value if the key is
+ * not found in GConf preferences.
+ *
+ * Note: please take care of keeping the default value synchronized with
+ * those defined in schemas.
+ */
+gboolean na_iprefs_get_add_about_item( NAIPrefs *instance )
+{
+	return( read_key_bool( instance, PREFS_ADD_ABOUT_ITEM, TRUE ));
+}
+
+/**
+ * Get a named boolean.
+ * @instance: this #NAIPrefs interface instance.
+ * @name: the name of the key to be read.
+ *
+ * Returns: the boolean attached to the @name key.
+ *
+ * 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 ));
+	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.
+ *
+ * Records the specified boolean in the GConf preferences.
+ */
 void
 na_iprefs_set_bool( NAIPrefs *instance, const gchar *name, gboolean value )
 {
 	write_key_bool( instance, name, value );
 }
 
+/*
+ * note that don't rely on having correctly installed the schema for the key
+ */
 static gboolean
-read_key_bool( NAIPrefs *instance, const gchar *name )
+read_key_bool( NAIPrefs *instance, const gchar *name, gboolean default_value )
 {
 	static const gchar *thisfn = "na_iprefs_read_key_bool";
 	GError *error = NULL;
 	gchar *path;
-	gboolean value;
+	GConfValue *value;
+	gboolean ret;
+
+	ret = default_value;
 
 	path = g_strdup_printf( "%s/%s", NA_GCONF_PREFS_PATH, name );
 
-	value = gconf_client_get_bool( NA_IPREFS_GET_INTERFACE( instance )->private->client, path, &error );
+	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;
+		}
+	}
+
+	if( value ){
+		ret = gconf_value_get_bool( value );
+		gconf_value_free( value );
 	}
 
 	g_free( path );
-	return( value );
+	return( ret );
 }
 
 static void
diff --git a/src/common/na-iprefs.h b/src/common/na-iprefs.h
index e8abe26..6d2ed40 100644
--- a/src/common/na-iprefs.h
+++ b/src/common/na-iprefs.h
@@ -31,11 +31,67 @@
 #ifndef __NA_IPREFS_H__
 #define __NA_IPREFS_H__
 
-/*
- * NAIPrefs interface definition.
+/**
+ * SECTION: na_iprefs
+ * @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.
+ * benefit of preferences management. It only manages preferences which
+ * are used by the plugin, and used/updated in the NACT user interface.
+ *
+ * Displaying the actions.
+ *
+ * - actions in alphabetical order: yes/no
+ *   Nautilus-Actions used to display the actions in alphabetical order.
+ *   Starting with 1.12.x, Nautilus-Actions lets the user rearrange
+ *   himself the order of its actions.
+ *   Defaults to yes to stay compatible with previous versions.
+ *
+ *   Actions can be organized in a set of submenus. In this case, the
+ *   'alphabetical order' preferences is also satisfied, on a level
+ *   basis.
+ *   This is not a preference: as submenus are available, user is free
+ *   to define some in NACT ; plugin will take care of them.
+ *
+ *   Defined order is saved in the same time than actions. So
+ *   considering the following operations:
+ *
+ *   a) set preference to 'no'
+ *   b) rearrange the items in any order
+ *   c) save
+ *   d) set preference to 'yes'
+ *      -> the items are reordered in alphabetical order
+ *   e) set preference to 'no'
+ *      -> the previous order is restaured (as it has been previously
+ *         saved)
+ *
+ *   but
+ *
+ *   a) set preference to 'no'
+ *   b) rearrange the items in any order
+ *   c) set preference to 'yes'
+ *      -> the items are reordered in alphabetical order
+ *   d) save
+ *   e) set preference to 'no'
+ *      -> the items stay in alphabetical order, as the previous save
+ *         has removed the previous order.
+ *
+ * - adding a 'About Nautilus Actions' item at end of actions: yes/no
+ *   This is used only when there is a root submenu, i.e. when the
+ *   Nautilus context menu will only display one item (the root
+ *   submenu). Only in this case, and if preference is 'yes', the we
+ *   will add the About item at the end of the first level of submenu.
+ *
+ *   Note that, as a convenience, the NACT user interface provides the
+ *   user with a standard item (Nautilus Actions actions) which can be
+ *   used as a root menu.
+ *
+ *   No 'About' item is added when user organize its actions so that
+ *   Nautilus context menu will have several entries at the first level.
+ *
+ * In all cases, the plugin takes care of providing actions to Nautilus
+ * if the same order than those they are displayed in NACT.
  */
 
 #include <glib-object.h>
@@ -61,6 +117,9 @@ 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 );
+
 gboolean na_iprefs_get_bool( NAIPrefs *instance, const gchar *key );
 void     na_iprefs_set_bool( NAIPrefs *instance, const gchar *key, gboolean value );
 
@@ -68,9 +127,10 @@ void     na_iprefs_set_bool( NAIPrefs *instance, const gchar *key, gboolean valu
  */
 #define NA_GCONF_PREFS_PATH		NAUTILUS_ACTIONS_CONFIG_GCONF_BASEDIR "/" NA_GCONF_SCHEMA_PREFERENCES
 
-/* Preference keys managed by IPrefs interface
+/* GConf Preference keys managed by IPrefs interface
  */
-#define PREFS_DISPLAY_AS_SUBMENU			"display-as-submenu"
+#define PREFS_DISPLAY_ALPHABETICAL_ORDER	"preferences-alphabetical-order"
+#define PREFS_ADD_ABOUT_ITEM				"preferences-add-about-item"
 
 G_END_DECLS
 
diff --git a/src/common/na-object-item.c b/src/common/na-object-item.c
new file mode 100644
index 0000000..326081e
--- /dev/null
+++ b/src/common/na-object-item.c
@@ -0,0 +1,448 @@
+/*
+ * Nautilus ObjectItems
+ * A Nautilus extension which offers configurable context menu object_items.
+ *
+ * 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-item.h"
+#include "na-utils.h"
+
+/* private class data
+ */
+struct NAObjectItemClassPrivate {
+	void *empty;						/* so that gcc -pedantic is happy */
+};
+
+/* private instance data
+ */
+struct NAObjectItemPrivate {
+	gboolean dispose_has_run;
+
+	/* object_item properties
+	 */
+	gchar   *tooltip;
+	gchar   *icon;
+};
+
+#define PROP_NAOBJECT_ITEM_TOOLTIP_STR		"na-object-item-tooltip"
+#define PROP_NAOBJECT_ITEM_ICON_STR			"na-object-item-icon"
+
+static NAObjectClass *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 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 );
+
+GType
+na_object_item_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_item_register_type";
+
+	static GTypeInfo info = {
+		sizeof( NAObjectItemClass ),
+		( GBaseInitFunc ) NULL,
+		( GBaseFinalizeFunc ) NULL,
+		( GClassInitFunc ) class_init,
+		NULL,
+		NULL,
+		sizeof( NAObjectItem ),
+		0,
+		( GInstanceInitFunc ) instance_init
+	};
+
+	g_debug( "%s", thisfn );
+
+	return( g_type_register_static( NA_OBJECT_TYPE, "NAObjectItem", &info, 0 ));
+}
+
+static void
+class_init( NAObjectItemClass *klass )
+{
+	static const gchar *thisfn = "na_object_item_class_init";
+	GObjectClass *object_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(
+			PROP_NAOBJECT_ITEM_TOOLTIP_STR,
+			"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 );
+
+	spec = g_param_spec_string(
+			PROP_NAOBJECT_ITEM_ICON_STR,
+			"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 );
+
+	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;
+}
+
+static void
+instance_init( GTypeInstance *instance, gpointer klass )
+{
+	/*static const gchar *thisfn = "na_object_item_instance_init";*/
+	NAObjectItem *self;
+
+	/*g_debug( "%s: instance=%p, klass=%p", thisfn, ( void * ) instance, ( void * ) klass );*/
+	g_assert( NA_IS_OBJECT_ITEM( instance ));
+	self = NA_OBJECT_ITEM( instance );
+
+	self->private = g_new0( NAObjectItemPrivate, 1 );
+
+	self->private->dispose_has_run = FALSE;
+
+	/* initialize suitable default values
+	 */
+	self->private->tooltip = g_strdup( "" );
+	self->private->icon = g_strdup( "" );
+}
+
+static void
+instance_get_property( GObject *object, guint property_id, GValue *value, GParamSpec *spec )
+{
+	NAObjectItem *self;
+
+	g_assert( NA_IS_OBJECT_ITEM( object ));
+	self = NA_OBJECT_ITEM( object );
+
+	switch( property_id ){
+		case PROP_NAOBJECT_ITEM_TOOLTIP:
+			g_value_set_string( value, self->private->tooltip );
+			break;
+
+		case PROP_NAOBJECT_ITEM_ICON:
+			g_value_set_string( value, self->private->icon );
+			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 )
+{
+	NAObjectItem *self;
+
+	g_assert( NA_IS_OBJECT_ITEM( object ));
+	self = NA_OBJECT_ITEM( object );
+
+	switch( property_id ){
+		case PROP_NAOBJECT_ITEM_TOOLTIP:
+			g_free( self->private->tooltip );
+			self->private->tooltip = g_value_dup_string( value );
+			break;
+
+		case PROP_NAOBJECT_ITEM_ICON:
+			g_free( self->private->icon );
+			self->private->icon = 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_item_instance_dispose";*/
+	NAObjectItem *self;
+
+	/*g_debug( "%s: object=%p", thisfn, ( void * ) object );*/
+	g_assert( NA_IS_OBJECT_ITEM( object ));
+	self = NA_OBJECT_ITEM( 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 = "na_object_item_instance_finalize";*/
+	NAObjectItem *self;
+
+	/*g_debug( "%s: object=%p", thisfn, ( void * ) object );*/
+	g_assert( NA_IS_OBJECT_ITEM( object ));
+	self = NA_OBJECT_ITEM( object );
+
+	g_free( self->private->tooltip );
+	g_free( self->private->icon );
+
+	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_item_get_tooltip:
+ * @item: the #NAObjectItem object to be requested.
+ *
+ * Returns the tooltip which will be display in the Nautilus context
+ * menu item for this @item.
+ *
+ * Returns: the tooltip of the @item as a newly allocated string. This
+ * returned string must be g_free() by the caller.
+ */
+gchar *
+na_object_item_get_tooltip( const NAObjectItem *item )
+{
+	gchar *tooltip;
+
+	g_assert( NA_IS_OBJECT_ITEM( item ));
+
+	g_object_get( G_OBJECT( item ), PROP_NAOBJECT_ITEM_TOOLTIP_STR, &tooltip, NULL );
+
+	return( tooltip );
+}
+
+/**
+ * na_object_item_get_icon:
+ * @item: the #NAObjectItem object to be requested.
+ *
+ * Returns the name of the icon attached to the Nautilus context menu
+ * item for this @item.
+ *
+ * Returns: the icon name as a newly allocated string. This returned
+ * string must be g_free() by the caller.
+ */
+gchar *
+na_object_item_get_icon( const NAObjectItem *item )
+{
+	gchar *icon;
+
+	g_assert( NA_IS_OBJECT_ITEM( item ));
+
+	g_object_get( G_OBJECT( item ), PROP_NAOBJECT_ITEM_ICON_STR, &icon, NULL );
+
+	return( icon );
+}
+
+/*
+ * TODO: remove this function
+ */
+gchar *
+na_object_item_get_verified_icon_name( const NAObjectItem *item )
+{
+	gchar *icon_name;
+
+	g_assert( NA_IS_OBJECT_ITEM( item ));
+
+	g_object_get( G_OBJECT( item ), PROP_NAOBJECT_ITEM_ICON_STR, &icon_name, NULL );
+
+	if( icon_name[0] == '/' ){
+		if( !g_file_test( icon_name, G_FILE_TEST_IS_REGULAR )){
+			g_free( icon_name );
+			return NULL;
+		}
+	} else if( strlen( icon_name ) == 0 ){
+		g_free( icon_name );
+		return NULL;
+	}
+
+	return( icon_name );
+}
+
+/**
+ * na_object_item_set_tooltip:
+ * @item: the #NAObjectItem object to be updated.
+ * @tooltip: the tooltip to be set.
+ *
+ * Sets a new tooltip for the @item. Tooltip will be displayed by
+ * Nautilus when the user move its mouse over the Nautilus context menu
+ * item.
+ *
+ * #NAObjectItem takes a copy of the provided tooltip. This later may
+ * so be g_free() by the caller after this function returns.
+ */
+void
+na_object_item_set_tooltip( NAObjectItem *item, const gchar *tooltip )
+{
+	g_assert( NA_IS_OBJECT_ITEM( item ));
+
+	g_object_set( G_OBJECT( item ), PROP_NAOBJECT_ITEM_TOOLTIP_STR, tooltip, NULL );
+}
+
+/**
+ * na_object_item_set_icon:
+ * @item: the #NAObjectItem object to be updated.
+ * @icon: the icon name to be set.
+ *
+ * Sets a new icon name for the @item.
+ *
+ * #NAObjectItem takes a copy of the provided icon name. This later may
+ * so be g_free() by the caller after this function returns.
+ */
+void
+na_object_item_set_icon( NAObjectItem *item, const gchar *icon )
+{
+	g_assert( NA_IS_OBJECT_ITEM( item ));
+
+	g_object_set( G_OBJECT( item ), PROP_NAOBJECT_ITEM_ICON_STR, icon, NULL );
+}
+
+void
+object_copy( NAObject *target, const NAObject *source )
+{
+	gchar *tooltip, *icon;
+
+	if( st_parent_class->copy ){
+		st_parent_class->copy( target, source );
+	}
+
+	g_assert( NA_IS_OBJECT_ITEM( source ));
+	g_assert( NA_IS_OBJECT_ITEM( target ));
+
+	g_object_get( G_OBJECT( source ),
+			PROP_NAOBJECT_ITEM_TOOLTIP_STR, &tooltip,
+			PROP_NAOBJECT_ITEM_ICON_STR, &icon,
+			NULL );
+
+	g_object_set( G_OBJECT( target ),
+			PROP_NAOBJECT_ITEM_TOOLTIP_STR, tooltip,
+			PROP_NAOBJECT_ITEM_ICON_STR, icon,
+			NULL );
+
+	g_free( tooltip );
+	g_free( icon );
+}
+
+static gboolean
+object_are_equal( const NAObject *a, const NAObject *b )
+{
+	NAObjectItem *first, *second;
+	gboolean equal = TRUE;
+
+	if( equal ){
+		if( st_parent_class->are_equal ){
+			equal = st_parent_class->are_equal( a, b );
+		}
+	}
+
+	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 );
+	}
+
+	return( equal );
+}
+
+gboolean
+object_is_valid( const NAObject *item )
+{
+	gboolean is_valid = TRUE;
+
+	if( is_valid ){
+		if( st_parent_class->is_valid ){
+			is_valid = st_parent_class->is_valid( item );
+		}
+	}
+
+	return( is_valid );
+}
+
+static void
+object_dump( const NAObject *item )
+{
+	static const gchar *thisfn = "na_object_item_object_dump";
+	NAObjectItem *self;
+
+	if( st_parent_class->dump ){
+		st_parent_class->dump( item );
+	}
+
+	g_assert( NA_IS_OBJECT_ITEM( item ));
+	self = NA_OBJECT_ITEM( item );
+
+	g_debug( "%s: tooltip='%s'", thisfn, self->private->tooltip );
+	g_debug( "%s:    icon='%s'", thisfn, self->private->icon );
+}
diff --git a/src/common/na-object-item.h b/src/common/na-object-item.h
new file mode 100644
index 0000000..a1dc710
--- /dev/null
+++ b/src/common/na-object-item.h
@@ -0,0 +1,89 @@
+/*
+ * 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_H__
+#define __NA_OBJECT_ITEM_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"
+
+G_BEGIN_DECLS
+
+#define NA_OBJECT_ITEM_TYPE					( na_object_item_get_type())
+#define NA_OBJECT_ITEM( object )			( G_TYPE_CHECK_INSTANCE_CAST( object, NA_OBJECT_ITEM_TYPE, NAObjectItem ))
+#define NA_OBJECT_ITEM_CLASS( klass )		( G_TYPE_CHECK_CLASS_CAST( klass, NA_OBJECT_ITEM_TYPE, NAObjectItemClass ))
+#define NA_IS_OBJECT_ITEM( object )			( G_TYPE_CHECK_INSTANCE_TYPE( object, NA_OBJECT_ITEM_TYPE ))
+#define NA_IS_OBJECT_ITEM_CLASS( klass )	( G_TYPE_CHECK_CLASS_TYPE(( klass ), NA_OBJECT_ITEM_TYPE ))
+#define NA_OBJECT_ITEM_GET_CLASS( object )	( G_TYPE_INSTANCE_GET_CLASS(( object ), NA_OBJECT_ITEM_TYPE, NAObjectItemClass ))
+
+typedef struct NAObjectItemPrivate NAObjectItemPrivate;
+
+typedef struct {
+	NAObject             parent;
+	NAObjectItemPrivate *private;
+}
+	NAObjectItem;
+
+typedef struct NAObjectItemClassPrivate NAObjectItemClassPrivate;
+
+typedef struct {
+	NAObjectClass             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 );
+
+G_END_DECLS
+
+#endif /* __NA_OBJECT_ITEM_H__ */
diff --git a/src/common/na-object.c b/src/common/na-object.c
index 2ce37b8..87d4023 100644
--- a/src/common/na-object.c
+++ b/src/common/na-object.c
@@ -58,31 +58,31 @@ struct NAObjectPrivate {
 
 static GObjectClass *st_parent_class = NULL;
 
-static GType     register_type( void );
-static void      class_init( NAObjectClass *klass );
-static void      iduplicable_iface_init( NAIDuplicableInterface *iface );
-static void      instance_init( GTypeInstance *instance, gpointer klass );
-static void      instance_constructed( GObject *object );
-static void      instance_get_property( GObject *object, guint property_id, GValue *value, GParamSpec *spec );
-static void      instance_set_property( GObject *object, guint property_id, const GValue *value, GParamSpec *spec );
-static void      instance_dispose( GObject *object );
-static void      instance_finalize( GObject *object );
-
-static void      v_check_edited_status( const NAObject *object );
-static NAObject *v_duplicate( const NAObject *object );
-static void      v_copy( NAObject *target, const NAObject *source );
-static gboolean  v_are_equal( const NAObject *a, const NAObject *b );
-static gboolean  v_is_valid( const NAObject *object );
-
-static void      do_dump( const NAObject *object );
-static void      do_check_edited_status( const NAObject *object );
-static void      do_copy( NAObject *target, const NAObject *source );
-static gboolean  do_are_equal( const NAObject *a, const NAObject *b );
-static gboolean  do_is_valid( const NAObject *object );
-
-static NAObject *iduplicable_duplicate( const NAObject *object );
-static gboolean  iduplicable_are_equal( const NAObject *a, const NAObject *b );
-static gboolean  iduplicable_is_valid( const NAObject *object );
+static GType          register_type( void );
+static void           class_init( NAObjectClass *klass );
+static void           iduplicable_iface_init( NAIDuplicableInterface *iface );
+static void           instance_init( GTypeInstance *instance, gpointer klass );
+static void           instance_constructed( GObject *object );
+static void           instance_get_property( GObject *object, guint property_id, GValue *value, GParamSpec *spec );
+static void           instance_set_property( GObject *object, guint property_id, const GValue *value, GParamSpec *spec );
+static void           instance_dispose( GObject *object );
+static void           instance_finalize( GObject *object );
+
+static NAIDuplicable *iduplicable_new( const NAIDuplicable *object );
+static void           iduplicable_copy( NAIDuplicable *target, const NAIDuplicable *source );
+static gboolean       iduplicable_are_equal( const NAIDuplicable *a, const NAIDuplicable *b );
+static gboolean       iduplicable_is_valid( const NAIDuplicable *object );
+
+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 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 );
 
 GType
 na_object_get_type( void )
@@ -114,7 +114,7 @@ register_type( void )
 		( GInstanceInitFunc ) instance_init
 	};
 
-	static const GInterfaceInfo idupicable_iface_info = {
+	static const GInterfaceInfo iduplicable_iface_info = {
 		( GInterfaceInitFunc ) iduplicable_iface_init,
 		NULL,
 		NULL
@@ -124,7 +124,7 @@ register_type( void )
 
 	type = g_type_register_static( G_TYPE_OBJECT, "NAObject", &info, 0 );
 
-	g_type_add_interface_static( type, NA_IDUPLICABLE_TYPE, &idupicable_iface_info );
+	g_type_add_interface_static( type, NA_IDUPLICABLE_TYPE, &iduplicable_iface_info );
 
 	return( type );
 }
@@ -163,12 +163,11 @@ class_init( NAObjectClass *klass )
 
 	klass->private = g_new0( NAObjectClassPrivate, 1 );
 
-	klass->dump = do_dump;
-	klass->check_edited_status = do_check_edited_status;
-	klass->duplicate = 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
@@ -178,7 +177,8 @@ iduplicable_iface_init( NAIDuplicableInterface *iface )
 
 	g_debug( "%s: iface=%p", thisfn, ( void * ) iface );
 
-	iface->duplicate = iduplicable_duplicate;
+	iface->copy = iduplicable_copy;
+	iface->new = iduplicable_new;
 	iface->are_equal = iduplicable_are_equal;
 	iface->is_valid = iduplicable_is_valid;
 }
@@ -186,10 +186,10 @@ iduplicable_iface_init( NAIDuplicableInterface *iface )
 static void
 instance_init( GTypeInstance *instance, gpointer klass )
 {
-	/*static const gchar *thisfn = "na_object_instance_init";
-	g_debug( "%s: instance=%p, klass=%p", thisfn, instance, klass );*/
+	/*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 ));
 	self = NA_OBJECT( instance );
 
@@ -201,10 +201,10 @@ instance_init( GTypeInstance *instance, gpointer klass )
 static void
 instance_constructed( GObject *object )
 {
-	na_iduplicable_init( NA_OBJECT( object ));
+	na_iduplicable_init( NA_IDUPLICABLE( object ));
 
 	/* chain call to parent class */
-	if( st_parent_class->constructed ){
+	if( G_OBJECT_CLASS( st_parent_class )->constructed ){
 		G_OBJECT_CLASS( st_parent_class )->constructed( object );
 	}
 }
@@ -270,7 +270,9 @@ instance_dispose( GObject *object )
 		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 );
+		}
 	}
 }
 
@@ -288,7 +290,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 );
 	}
 }
@@ -316,13 +318,31 @@ na_object_dump( const NAObject *object )
  * Exactly duplicates a #NAObject-derived object.
  *
  * Returns: the new #NAObject.
+ *
+ *     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
+ *      |   |
+ *      |   +- set_origin( dup, origin )
+ *      |   +- set_modified( dup, FALSE )
+ *      |   +- set_valid( dup, FALSE )
+ *      |
+ *      +- na_object_check_edited_status
  */
 NAObject *
 na_object_duplicate( const NAObject *object )
 {
+	NAIDuplicable *duplicate;
+
 	g_assert( NA_IS_OBJECT( object ));
 
-	return( na_iduplicable_duplicate( object ));
+	duplicate = na_iduplicable_duplicate( NA_IDUPLICABLE( object ));
+
+	na_object_check_edited_status( NA_OBJECT( duplicate ));
+
+	return( NA_OBJECT( duplicate ));
 }
 
 /**
@@ -342,6 +362,23 @@ na_object_copy( NAObject *target, const NAObject *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 )
+{
+	g_assert( NA_IS_OBJECT( object ));
+
+	return( v_get_clipboard_id( object ));
+}
+
+/**
  * na_object_check_edited_status:
  * @object: the #NAObject object to be checked.
  *
@@ -349,13 +386,19 @@ na_object_copy( NAObject *target, const NAObject *source )
  *
  * 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 )
 {
 	g_assert( NA_IS_OBJECT( object ));
 
-	v_check_edited_status( object );
+	na_iduplicable_check_edited_status( NA_IDUPLICABLE( object ));
 }
 
 /**
@@ -397,22 +440,6 @@ na_object_is_valid( const NAObject *object )
 }
 
 /**
- * na_object_get_origin:
- * @object: the #NAObject object whose status is requested.
- *
- * Returns the original object which was at the origin of @object.
- *
- * Returns: a #NAObject, or NULL.
- */
-NAObject *
-na_object_get_origin( const NAObject *object )
-{
-	g_assert( NA_IS_OBJECT( object ));
-
-	return( na_iduplicable_get_origin( object ));
-}
-
-/**
  * na_object_get_modified_status:
  * @object: the #NAObject object whose status is requested.
  *
@@ -432,7 +459,7 @@ na_object_get_modified_status( const NAObject *object )
 {
 	g_assert( NA_IS_OBJECT( object ));
 
-	return( na_iduplicable_is_modified( object ));
+	return( na_iduplicable_is_modified( NA_IDUPLICABLE( object )));
 }
 
 /**
@@ -454,23 +481,23 @@ na_object_get_valid_status( const NAObject *object )
 {
 	g_assert( NA_IS_OBJECT( object ));
 
-	return( na_iduplicable_is_valid( object ));
+	return( na_iduplicable_is_valid( NA_IDUPLICABLE( object )));
 }
 
 /**
- * na_object_set_origin:
+ * na_object_get_origin:
  * @object: the #NAObject object whose status is requested.
- * @origin: a #NAObject which will be set as the new origin of @object.
  *
- * Sets the new origin of @object.
+ * Returns the original object which was at the origin of @object.
+ *
+ * Returns: a #NAObject, or NULL.
  */
-void
-na_object_set_origin( NAObject *object, const NAObject *origin )
+NAObject *
+na_object_get_origin( const NAObject *object )
 {
 	g_assert( NA_IS_OBJECT( object ));
-	g_assert( NA_IS_OBJECT( origin ) || !origin );
 
-	na_iduplicable_set_origin( object, origin );
+	return( NA_OBJECT( na_iduplicable_get_origin( NA_IDUPLICABLE( object ))));
 }
 
 /**
@@ -518,6 +545,22 @@ na_object_get_label( const NAObject *object )
 }
 
 /**
+ * na_object_set_origin:
+ * @object: the #NAObject object whose status is requested.
+ * @origin: a #NAObject which will be set as the new origin of @object.
+ *
+ * Sets the new origin of @object.
+ */
+void
+na_object_set_origin( NAObject *object, const NAObject *origin )
+{
+	g_assert( NA_IS_OBJECT( object ));
+	g_assert( NA_IS_OBJECT( origin ) || !origin );
+
+	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.
@@ -530,6 +573,7 @@ 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 );
 }
 
@@ -544,25 +588,39 @@ 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
-v_check_edited_status( const NAObject *object )
+iduplicable_copy( NAIDuplicable *target, const NAIDuplicable *source )
 {
-	if( NA_OBJECT_GET_CLASS( object )->check_edited_status ){
-		NA_OBJECT_GET_CLASS( object )->check_edited_status( object );
+	v_copy( NA_OBJECT( target ), NA_OBJECT( source ));
+}
 
-	} else {
-		do_check_edited_status( object );
-	}
+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_duplicate( const NAObject *object )
+v_new( const NAObject *object )
 {
-	if( NA_OBJECT_GET_CLASS( object )->duplicate ){
-		return( NA_OBJECT_GET_CLASS( object )->duplicate( object ));
+	if( NA_OBJECT_GET_CLASS( object )->new ){
+		return( NA_OBJECT_GET_CLASS( object )->new( object ));
 	}
 
 	return( NULL );
@@ -576,6 +634,16 @@ v_copy( NAObject *target, const NAObject *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 )
 {
@@ -597,26 +665,6 @@ v_is_valid( const NAObject *object )
 }
 
 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( object );
-}
-
-static void
-do_check_edited_status( const NAObject *object )
-{
-	na_iduplicable_check_edited_status( object );
-}
-
-static void
 do_copy( NAObject *target, const NAObject *source )
 {
 	gchar *id, *label;
@@ -642,26 +690,26 @@ do_are_equal( const NAObject *a, const NAObject *b )
 	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 NAObject *
-iduplicable_duplicate( const NAObject *object )
+static void
+do_dump( const NAObject *object )
 {
-	return( v_duplicate( object ));
-}
+	static const char *thisfn = "na_object_do_dump";
 
-static gboolean
-iduplicable_are_equal( const NAObject *a, const NAObject *b )
-{
-	return( v_are_equal( a, b ));
-}
+	g_assert( NA_IS_OBJECT( object ));
 
-static gboolean
-iduplicable_is_valid( const NAObject *object )
-{
-	return( v_is_valid( 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 ));
 }
diff --git a/src/common/na-object.h b/src/common/na-object.h
index 047f302..af63318 100644
--- a/src/common/na-object.h
+++ b/src/common/na-object.h
@@ -74,42 +74,12 @@ typedef struct {
 	NAObjectClassPrivate *private;
 
 	/**
-	 * dump:
-	 * @object: the #NAObject-derived object to be dumped.
-	 *
-	 * Dumps via g_debug the content of the object.
-	 *
-	 * In order to get a down-to-top display, the derived class
-	 * implementation should call its parent class before actually
-	 * dumping its own data and properties.
-	 */
-	void       ( *dump )               ( const NAObject *object );
-
-	/**
-	 * check_edited_status:
-	 * @object: the #NAObject-derived object to be checked.
+	 * new:
+	 * @object: a #NAObject-derived object.
 	 *
-	 * Checks a #NAObject-derived object for modification and validity
-	 * status.
+	 * Returns: a newly allocated object of the same class that @object.
 	 */
-	void       ( *check_edited_status )( const NAObject *object );
-
-	/**
-	 * duplicate:
-	 * @object: the #NAObject-derived object to be dumped.
-	 *
-	 * Duplicates a #NAObject-derived object.
-	 *
-	 * As the most-derived class will actually allocate the new object
-	 * with the right class, it shouldn't call its parent class.
-	 *
-	 * Copying data and properties should then be done via the
-	 * na_object_copy() function.
-	 *
-	 * Returns: a newly allocated object, which is an exact copy of
-	 * @object.
-	 */
-	NAObject * ( *duplicate )          ( const NAObject *object );
+	NAObject * ( *new )                ( const NAObject *object );
 
 	/**
 	 * copy:
@@ -153,11 +123,31 @@ typedef struct {
 	 * 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.
+	 *
+	 * In order to get a down-to-top display, the derived class
+	 * implementation should call its parent class before actually
+	 * dumping its own data and properties.
+	 */
+	void       ( *dump )               ( const NAObject *object );
+
+	/**
+	 * 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 to the properties
+ * used in derived classes to access the properties
  */
 enum {
 	PROP_NAOBJECT_ID = 1,
@@ -170,19 +160,19 @@ 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 );
-
-NAObject *na_object_get_origin( const NAObject *object );
 gboolean  na_object_get_modified_status( const NAObject *object );
 gboolean  na_object_get_valid_status( const NAObject *object );
 
-void      na_object_set_origin( NAObject *object, const NAObject *origin );
-
+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 );
 
diff --git a/src/common/na-pivot.c b/src/common/na-pivot.c
index 2f308fb..223f226 100644
--- a/src/common/na-pivot.c
+++ b/src/common/na-pivot.c
@@ -73,6 +73,8 @@ struct NAPivotPrivate {
 
 enum {
 	ACTION_CHANGED,
+	DISPLAY_ORDER_CHANGE,
+	DISPLAY_ABOUT_CHANGE,
 	LAST_SIGNAL
 };
 
@@ -95,6 +97,9 @@ 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 );
 
+static void     on_display_order_change( NAPivot *pivot, gpointer user_data );
+static void     on_display_about_change( NAPivot *pivot, gpointer user_data );
+
 GType
 na_pivot_get_type( void )
 {
@@ -164,6 +169,30 @@ class_init( NAPivotClass *klass )
 				1,
 				G_TYPE_POINTER
 	);
+	st_signals[ DISPLAY_ORDER_CHANGE ] = 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,
+				( GCallback ) on_display_order_change,
+				NULL,
+				NULL,
+				g_cclosure_marshal_VOID__POINTER,
+				G_TYPE_NONE,
+				1,
+				G_TYPE_POINTER
+	);
+	st_signals[ DISPLAY_ABOUT_CHANGE ] = 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,
+				( GCallback ) on_display_about_change,
+				NULL,
+				NULL,
+				g_cclosure_marshal_VOID__POINTER,
+				G_TYPE_NONE,
+				1,
+				G_TYPE_POINTER
+	);
 }
 
 static void
@@ -399,7 +428,7 @@ na_pivot_get_duplicate_actions( const NAPivot *pivot )
 		list = g_slist_prepend( list, na_object_duplicate( NA_OBJECT( ia->data )));
 	}
 
-	return( list );
+	return( g_slist_reverse( list ));
 }
 
 /**
@@ -715,3 +744,36 @@ na_pivot_free_notify( NAPivotNotify *npn )
 		g_free( npn );
 	}
 }
+
+static void
+on_display_order_change( NAPivot *self, gpointer user_data  )
+{
+	static const gchar *thisfn = "na_pivot_on_display_order_change";
+	GSList *ic;
+
+	g_debug( "%s: self=%p, data=%p", thisfn, ( void * ) self, ( void * ) user_data );
+	g_assert( NA_IS_PIVOT( self ));
+	g_assert( user_data );
+
+	if( self->private->dispose_has_run ){
+		return;
+	}
+
+	for( ic = self->private->notified ; ic ; ic = ic->next ){
+		na_ipivot_consumer_notify( NA_IPIVOT_CONSUMER( ic->data ));
+	}
+}
+
+static void
+on_display_about_change( NAPivot *self, gpointer user_data  )
+{
+	static const gchar *thisfn = "na_pivot_on_display_order_change";
+
+	g_debug( "%s: self=%p, data=%p", thisfn, ( void * ) self, ( void * ) user_data );
+	g_assert( NA_IS_PIVOT( self ));
+	g_assert( user_data );
+
+	if( self->private->dispose_has_run ){
+		return;
+	}
+}
diff --git a/src/common/na-utils.c b/src/common/na-utils.c
index 0362ff3..e3723cc 100644
--- a/src/common/na-utils.c
+++ b/src/common/na-utils.c
@@ -32,6 +32,7 @@
 #include <config.h>
 #endif
 
+#include <gio/gio.h>
 #include <glib-object.h>
 #include <string.h>
 
@@ -363,3 +364,87 @@ na_utils_gstring_joinv( const gchar *start, const gchar *separator, gchar **list
 
 	return( g_string_free( tmp_string, FALSE ));
 }
+
+gchar *
+na_utils_remove_last_level_from_path( const gchar *path )
+{
+	int p;
+	const char *ptr = path;
+	char *new_path;
+
+	if( path == NULL ){
+		return( NULL );
+	}
+
+	p = strlen( path ) - 1;
+	if( p < 0 ){
+		return( NULL );
+	}
+
+	while(( p > 0 ) && ( ptr[p] != '/' )){
+		p--;
+	}
+
+	if(( p == 0 ) && ( ptr[p] == '/' )){
+		p++;
+	}
+
+	new_path = g_strndup( path, ( guint ) p );
+
+	return( new_path );
+}
+
+gboolean
+na_utils_is_writable_dir( const gchar *uri )
+{
+	static const gchar *thisfn = "na_utils_is_writable_dir";
+	GFile *file;
+	GError *error = NULL;
+	GFileInfo *info;
+	GFileType type;
+	gboolean writable;
+
+	if( !uri || !strlen( uri )){
+		return( FALSE );
+	}
+
+	file = g_file_new_for_uri( uri );
+	info = g_file_query_info( file,
+			G_FILE_ATTRIBUTE_ACCESS_CAN_WRITE "," G_FILE_ATTRIBUTE_STANDARD_TYPE,
+			G_FILE_QUERY_INFO_NONE, NULL, &error );
+
+	if( error ){
+		g_warning( "%s: g_file_query_info error: %s", thisfn, error->message );
+		g_error_free( error );
+		g_object_unref( file );
+		return( FALSE );
+	}
+
+	type = g_file_info_get_file_type( info );
+	if( type != G_FILE_TYPE_DIRECTORY ){
+		g_warning( "%s: %s is not a directory", thisfn, uri );
+		g_object_unref( info );
+		return( FALSE );
+	}
+
+	writable = g_file_info_get_attribute_boolean( info, G_FILE_ATTRIBUTE_ACCESS_CAN_WRITE );
+	if( !writable ){
+		g_warning( "%s: %s is not writable", thisfn, uri );
+	}
+	g_object_unref( info );
+
+	return( writable );
+}
+
+gboolean
+na_utils_exist_file( const gchar *uri )
+{
+	GFile *file;
+	gboolean exists;
+
+	file = g_file_new_for_uri( uri );
+	exists = g_file_query_exists( file, NULL );
+	g_object_unref( file );
+
+	return( exists );
+}
diff --git a/src/common/na-utils.h b/src/common/na-utils.h
index 7c57cf3..5902a0d 100644
--- a/src/common/na-utils.h
+++ b/src/common/na-utils.h
@@ -59,6 +59,13 @@ gchar   *na_utils_path_to_key( const gchar *path );
  */
 gchar *  na_utils_gstring_joinv( const gchar *start, const gchar *separator, gchar **list );
 
+/*
+ * path manipulations
+ */
+gchar   *na_utils_remove_last_level_from_path( const gchar *path );
+gboolean na_utils_is_writable_dir( const gchar *uri );
+gboolean na_utils_exist_file( const gchar *uri );
+
 G_END_DECLS
 
 #endif /* __NA_UTILS_H__ */
diff --git a/src/common/na-xml-writer.c b/src/common/na-xml-writer.c
index 5d1043c..cc2f83d 100644
--- a/src/common/na-xml-writer.c
+++ b/src/common/na-xml-writer.c
@@ -32,6 +32,7 @@
 #include <config.h>
 #endif
 
+#include <gio/gio.h>
 #include <libxml/tree.h>
 
 #include "na-action-profile.h"
@@ -72,7 +73,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, NAAction *action );
+static xmlDocPtr    create_xml_schema( NAXMLWriter *writer, gint format, const NAAction *action );
 static void         create_schema_entry(
 								NAXMLWriter *writer,
 								gint format,
@@ -85,7 +86,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, NAAction *action );
+static xmlDocPtr    create_xml_dump( NAXMLWriter *writer, gint format, const NAAction *action );
 static void         create_dump_entry(
 								NAXMLWriter *writer,
 								gint format,
@@ -268,46 +269,35 @@ xml_writer_new( const gchar *uuid )
 
 /**
  * na_xml_writer_export:
- * @action:
+ * @action: the #NAAction to be exported.
  * @folder: the directoy where to write the output XML file.
  * If NULL, the output will be directed to stdout.
+ * @format: the export format.
+ * @msg: pointer to a buffer which will receive error messages.
  *
  * Export the specified action as an XML file.
  *
  * Returns: the written filename, or NULL if written to stdout.
  */
 gchar *
-na_xml_writer_export( NAAction *action, const gchar *folder, gint format, gchar **msg )
+na_xml_writer_export( const NAAction *action, const gchar *folder, gint format, gchar **msg )
 {
-	gchar *uuid;
-	NAXMLWriter *writer;
-	xmlDocPtr doc = NULL;
 	gchar *filename = NULL;
 	gboolean free_filename = FALSE;
-
-
-	uuid = action ? na_action_get_uuid( action ) : NULL;
-	writer = xml_writer_new( uuid );
-	g_free( uuid );
+	gchar *xml_buffer;
 
 	switch( format ){
 		case FORMAT_GCONFSCHEMAFILE_V1:
-			doc = create_xml_schema( writer, format, action );
-			filename = g_strdup_printf( "%s/config_%s.schemas", folder, writer->private->uuid );
-			break;
-
 		case FORMAT_GCONFSCHEMAFILE_V2:
-			doc = create_xml_schema( writer, format, action );
-			filename = g_strdup_printf( "%s/config-%s.schema", folder, writer->private->uuid );
+			filename = na_xml_writer_get_output_fname( action, folder, format );
 			break;
 
 		/* this is the format used by nautilus-actions-new utility,
 		 * and that's why this option takes care of a NULL folder
 		 */
 		case FORMAT_GCONFENTRY:
-			doc = create_xml_dump( writer, format, action );
 			if( folder ){
-				filename = g_strdup_printf( "%s/action-%s.xml", folder, writer->private->uuid );
+				filename = na_xml_writer_get_output_fname( action, folder, format );
 			} else {
 				filename = g_strdup( "-" );
 				free_filename = TRUE;
@@ -319,7 +309,6 @@ na_xml_writer_export( NAAction *action, const gchar *folder, gint format, gchar
 		 * folder, or an output filename
 		 */
 		case FORMAT_GCONFSCHEMA:
-			doc = create_gconf_schema( writer );
 			if( folder ){
 				filename = g_strdup( folder );
 			} else {
@@ -329,28 +318,201 @@ na_xml_writer_export( NAAction *action, const gchar *folder, gint format, gchar
 			break;
 	}
 
-	g_assert( doc );
 	g_assert( filename );
 
-	if( xmlSaveFormatFileEnc( filename, doc, "UTF-8", 1 ) == -1 ){
-		g_free( filename );
-		filename = NULL;
-	}
+	xml_buffer = na_xml_writer_get_xml_buffer( action, format );
+
+	na_xml_writer_output_xml( xml_buffer, filename );
+
+	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.
+ * @folder: the uri of the directoy where to write the output XML file.
+ * @format: the export format.
+ *
+ * Returns: a filename suitable for writing the output XML.
+ *
+ * As we don't want overwrite already existing files, the candidate
+ * filename is incremented until we find an available filename.
+ *
+ * The returned string should be g_free() by the caller.
+ *
+ * Note that this function is always subject to race condition, as it
+ * is possible, though very unlikely, that the given file be created
+ * between our test of inexistance and the actual write.
+ */
+gchar *
+na_xml_writer_get_output_fname( const NAAction *action, const gchar *folder, gint format )
+{
+	gchar *uuid;
+	gchar *canonical_fname = NULL;
+	gchar *canonical_ext = NULL;
+	gchar *candidate_fname;
+	gint counter;
+
+	g_return_val_if_fail( action, NULL );
+	g_return_val_if_fail( folder, NULL );
+	g_return_val_if_fail( strlen( folder ), NULL );
+
+	uuid = na_action_get_uuid( action );
+
+	switch( format ){
+		case FORMAT_GCONFSCHEMAFILE_V1:
+			canonical_fname = g_strdup_printf( "config_%s", uuid );
+			canonical_ext = g_strdup( "schemas" );
+			break;
+
+		case FORMAT_GCONFSCHEMAFILE_V2:
+			canonical_fname = g_strdup_printf( "config-%s", uuid );
+			canonical_ext = g_strdup( "schema" );
+			break;
+
+		case FORMAT_GCONFENTRY:
+			canonical_fname = g_strdup_printf( "action-%s", uuid );
+			canonical_ext = g_strdup( "xml" );
+			break;
+	}
+
+	g_free( uuid );
+	g_return_val_if_fail( canonical_fname, NULL );
+
+	candidate_fname = g_strdup_printf( "%s/%s.%s", folder, canonical_fname, canonical_ext );
+
+	if( !na_utils_exist_file( candidate_fname )){
+		g_free( canonical_fname );
+		g_free( canonical_ext );
+		return( candidate_fname );
+	}
+
+	for( counter = 0 ; ; ++counter ){
+		g_free( candidate_fname );
+		candidate_fname = g_strdup_printf( "%s/%s_%d.%s", folder, canonical_fname, counter, canonical_ext );
+		if( !na_utils_exist_file( candidate_fname )){
+			break;
+		}
+	}
+
+	g_free( canonical_fname );
+	g_free( canonical_ext );
+
+	return( candidate_fname );
+}
+
+/**
+ * na_xml_writer_get_xml_buffer:
+ * @action: the #NAAction to be exported.
+ * @format: the export format.
+ *
+ * Returns: a buffer which contains the XML output.
+ *
+ * The returned string should be g_free() by the caller.
+ */
+gchar *
+na_xml_writer_get_xml_buffer( const NAAction *action, gint format )
+{
+	gchar *uuid;
+	NAXMLWriter *writer;
+	xmlDocPtr doc = NULL;
+	xmlChar *text;
+	int textlen;
+	gchar *buffer;
+
+	g_return_val_if_fail( action, NULL );
+
+	uuid = na_action_get_uuid( action );
+	writer = xml_writer_new( uuid );
+	g_free( uuid );
+
+	switch( format ){
+		case FORMAT_GCONFSCHEMAFILE_V1:
+		case FORMAT_GCONFSCHEMAFILE_V2:
+			doc = create_xml_schema( writer, format, action );
+			break;
+
+		case FORMAT_GCONFENTRY:
+			doc = create_xml_dump( writer, format, action );
+			break;
+
+		case FORMAT_GCONFSCHEMA:
+			doc = create_gconf_schema( writer );
+			break;
+	}
+
+	g_assert( doc );
+
+	xmlDocDumpFormatMemoryEnc( doc, &text, &textlen, "UTF-8", 1 );
+	buffer = g_strdup(( const gchar * ) text );
+
+	xmlFree( text );
 	xmlFreeDoc (doc);
 	xmlCleanupParser();
 	g_object_unref( writer );
 
-	return( filename );
+	return( buffer );
+}
+
+/**
+ * na_xml_writer_output_xml:
+ * @action: the #NAAction to be exported.
+ * @filename: the uri of the output filename
+ *
+ * Exports an action to the given filename.
+ */
+void
+na_xml_writer_output_xml( const gchar *xml, const gchar *filename )
+{
+	static const gchar *thisfn = "na_xml_writer_output_xml";
+	GFile *file;
+	GFileOutputStream *stream;
+	GError *error = NULL;
+
+	g_assert( filename );
+
+	file = g_file_new_for_uri( filename );
+
+	stream = g_file_create( file, G_FILE_CREATE_REPLACE_DESTINATION, NULL, &error );
+	if( error ){
+		g_warning( "%s: %s", thisfn, error->message );
+		g_error_free( error );
+		g_object_unref( stream );
+		g_object_unref( file );
+		return;
+	}
+
+	g_output_stream_write( G_OUTPUT_STREAM( stream ), xml, g_utf8_strlen( xml, -1 ), NULL, &error );
+	if( error ){
+		g_warning( "%s: %s", thisfn, error->message );
+		g_error_free( error );
+		g_object_unref( stream );
+		g_object_unref( file );
+		return;
+	}
+
+	g_output_stream_close( G_OUTPUT_STREAM( stream ), NULL, &error );
+	if( error ){
+		g_warning( "%s: %s", thisfn, error->message );
+		g_error_free( error );
+		g_object_unref( stream );
+		g_object_unref( file );
+		return;
+	}
+
+	g_object_unref( stream );
+	g_object_unref( file );
 }
 
 static xmlDocPtr
-create_xml_schema( NAXMLWriter *writer, gint format, NAAction *action )
+create_xml_schema( NAXMLWriter *writer, gint format, const NAAction *action )
 {
 	xmlDocPtr doc;
 	xmlNodePtr root_node, list_node;
@@ -528,7 +690,7 @@ create_schema_entry( NAXMLWriter *writer,
 }
 
 static xmlDocPtr
-create_xml_dump( NAXMLWriter *writer, gint format, NAAction *action )
+create_xml_dump( NAXMLWriter *writer, gint format, const NAAction *action )
 {
 	xmlDocPtr doc;
 	xmlNodePtr root_node, list_node;
diff --git a/src/common/na-xml-writer.h b/src/common/na-xml-writer.h
index efbd22a..a7b9781 100644
--- a/src/common/na-xml-writer.h
+++ b/src/common/na-xml-writer.h
@@ -71,7 +71,13 @@ typedef struct {
 
 GType  na_xml_writer_get_type( void );
 
-gchar *na_xml_writer_export( NAAction *action, const gchar *folder, gint format, gchar **msg );
+gchar *na_xml_writer_export( const NAAction *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_xml_buffer( const NAAction *action, gint format );
+
+void   na_xml_writer_output_xml( const gchar *xml, const gchar *filename );
 
 G_END_DECLS
 
diff --git a/src/nact/Makefile.am b/src/nact/Makefile.am
index 7f75b9f..98f7d47 100644
--- a/src/nact/Makefile.am
+++ b/src/nact/Makefile.am
@@ -45,6 +45,8 @@ nautilus_actions_config_tool_SOURCES = \
 	base-window.c										\
 	base-window.h										\
 	base-window-class.h									\
+	egg-tree-multi-dnd.c								\
+	egg-tree-multi-dnd.h								\
 	nact-application.c									\
 	nact-application.h									\
 	nact-assistant.c									\
@@ -72,8 +74,12 @@ nautilus_actions_config_tool_SOURCES = \
 	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										\
 	nact-window.h										\
 	nact-xml-reader.c									\
diff --git a/src/nact/egg-tree-multi-dnd.c b/src/nact/egg-tree-multi-dnd.c
new file mode 100644
index 0000000..226d785
--- /dev/null
+++ b/src/nact/egg-tree-multi-dnd.c
@@ -0,0 +1,505 @@
+/*
+ * 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)
+ */
+
+/* eggtreemultidnd.c
+ * Copyright (C) 2001  Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+
+#include "egg-tree-multi-dnd.h"
+
+#define EGG_TREE_MULTI_DND_STRING		"EggTreeMultiDndString"
+
+/*static GtkTargetEntry target_table[] = {
+        { "XdndDirectSave0", 0, 0 },
+        { "XdndNautilusActions0", 0, 1 }
+};*/
+
+typedef struct
+{
+	guint    pressed_button;
+	gint     x;
+	gint     y;
+	guint    motion_notify_handler;
+	guint    button_release_handler;
+	guint    drag_data_get_handler;
+	GSList  *event_list;
+	gboolean pending_event;
+}
+	EggTreeMultiDndData;
+
+static GType          register_type( void );
+
+static GtkTargetList *v_get_target_list( EggTreeMultiDragSource *drag_source );
+static void           v_free_target_list( EggTreeMultiDragSource *drag_source, GtkTargetList *list );
+static GdkDragAction  v_get_drag_actions( EggTreeMultiDragSource *drag_source );
+
+static gboolean       on_button_press_event( GtkWidget *widget, GdkEventButton *event, EggTreeMultiDragSource *drag_source );
+static gboolean       on_button_release_event( GtkWidget *widget, GdkEventButton *event, EggTreeMultiDragSource *drag_source );
+static gboolean       on_motion_event( GtkWidget *widget, GdkEventMotion *event, EggTreeMultiDragSource *drag_source );
+static gboolean       on_drag_data_get( GtkWidget *widget, GdkDragContext *context, GtkSelectionData *selection_data, guint info, guint time );
+
+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 );
+
+GType
+egg_tree_multi_drag_source_get_type( void )
+{
+	static GType our_type = 0;
+
+	if( !our_type ){
+		our_type = register_type();
+	}
+
+	return( our_type );
+}
+
+static GType
+register_type( void )
+{
+	GType type;
+
+	static const GTypeInfo our_info = {
+			sizeof( EggTreeMultiDragSourceIface ),	/* class_size */
+			NULL,									/* base_init */
+			NULL,									/* base_finalize */
+			NULL,
+			NULL,									/* class_finalize */
+			NULL,									/* class_data */
+			0,
+			0,										/* n_preallocs */
+			NULL
+	};
+
+	type = g_type_register_static( G_TYPE_INTERFACE, "EggTreeMultiDragSource", &our_info, 0 );
+
+    return( type );
+}
+
+/**
+ * egg_tree_multi_drag_add_drag_support:
+ */
+void
+egg_tree_multi_drag_add_drag_support( EggTreeMultiDragSource *drag_source, GtkTreeView *tree_view )
+{
+	g_return_if_fail( GTK_IS_TREE_VIEW( tree_view ));
+
+	g_signal_connect( G_OBJECT( tree_view ),
+			"button_press_event",
+			G_CALLBACK( on_button_press_event),
+			drag_source );
+}
+
+/**
+ * egg_tree_multi_drag_source_row_draggable:
+ * @drag_source: a #EggTreeMultiDragSource
+ * @path: row on which user is initiating a drag
+ *
+ * Asks the #EggTreeMultiDragSource whether a particular row can be used as
+ * the source of a DND operation. If the source doesn't implement
+ * this interface, the row is assumed draggable.
+ *
+ * Return value: %TRUE if the row can be dragged
+ **/
+gboolean
+egg_tree_multi_drag_source_row_draggable( EggTreeMultiDragSource *drag_source, GList *path_list )
+{
+	EggTreeMultiDragSourceIface *iface = EGG_TREE_MULTI_DRAG_SOURCE_GET_IFACE( drag_source );
+
+	g_return_val_if_fail( EGG_IS_TREE_MULTI_DRAG_SOURCE( drag_source ), FALSE );
+	g_return_val_if_fail( iface->row_draggable != NULL, FALSE );
+	g_return_val_if_fail( path_list != NULL, FALSE );
+
+	return(( *iface->row_draggable )( drag_source, path_list ));
+}
+
+/**
+ * egg_tree_multi_drag_source_drag_data_get:
+ * @drag_source: a #EggTreeMultiDragSource
+ * @path: row that was dragged
+ * @selection_data: a #EggSelectionData to fill with data from the dragged row
+ *
+ * Asks the #EggTreeMultiDragSource to fill in @selection_data with a
+ * representation of the row at @path. @selection_data->target gives
+ * the required type of the data.  Should robustly handle a @path no
+ * longer found in the model!
+ *
+ * Return value: %TRUE if data of the required type was provided
+ **/
+gboolean
+egg_tree_multi_drag_source_drag_data_get( EggTreeMultiDragSource *drag_source,
+											GdkDragContext   *context,
+											GtkSelectionData *selection_data,
+											GList            *path_list,
+											guint             info )
+{
+	EggTreeMultiDragSourceIface *iface = EGG_TREE_MULTI_DRAG_SOURCE_GET_IFACE( drag_source );
+
+	g_return_val_if_fail( EGG_IS_TREE_MULTI_DRAG_SOURCE( drag_source ), FALSE );
+	g_return_val_if_fail( iface->drag_data_get != NULL, FALSE );
+	g_return_val_if_fail( path_list != NULL, FALSE );
+	g_return_val_if_fail( selection_data != NULL, FALSE );
+
+	return(( *iface->drag_data_get )( drag_source, context, selection_data, path_list, info ));
+}
+
+/**
+ * egg_tree_multi_drag_source_drag_data_delete:
+ * @drag_source: a #EggTreeMultiDragSource
+ * @path: row that was being dragged
+ *
+ * Asks the #EggTreeMultiDragSource to delete the row at @path, because
+ * it was moved somewhere else via drag-and-drop. Returns %FALSE
+ * if the deletion fails because @path no longer exists, or for
+ * some model-specific reason. Should robustly handle a @path no
+ * longer found in the model!
+ *
+ * Return value: %TRUE if the row was successfully deleted
+ **/
+gboolean
+egg_tree_multi_drag_source_drag_data_delete( EggTreeMultiDragSource *drag_source, GList *path_list )
+{
+	EggTreeMultiDragSourceIface *iface = EGG_TREE_MULTI_DRAG_SOURCE_GET_IFACE( drag_source );
+
+	g_return_val_if_fail( EGG_IS_TREE_MULTI_DRAG_SOURCE( drag_source ), FALSE );
+	g_return_val_if_fail( iface->drag_data_delete != NULL, FALSE );
+	g_return_val_if_fail( path_list != NULL, FALSE );
+
+  return(( *iface->drag_data_delete )( drag_source, path_list ));
+}
+
+static GtkTargetList *
+v_get_target_list( EggTreeMultiDragSource *drag_source )
+{
+	EggTreeMultiDragSourceIface *iface = EGG_TREE_MULTI_DRAG_SOURCE_GET_IFACE( drag_source );
+
+	if( iface->get_target_list ){
+		return( iface->get_target_list( drag_source ));
+	}
+
+	return( NULL );
+}
+
+static void
+v_free_target_list( EggTreeMultiDragSource *drag_source, GtkTargetList *list )
+{
+	EggTreeMultiDragSourceIface *iface = EGG_TREE_MULTI_DRAG_SOURCE_GET_IFACE( drag_source );
+
+	if( iface->free_target_list ){
+		iface->free_target_list( drag_source, list );
+
+	} else {
+		gtk_target_list_unref( list );
+	}
+}
+
+static GdkDragAction
+v_get_drag_actions( EggTreeMultiDragSource *drag_source )
+{
+	EggTreeMultiDragSourceIface *iface = EGG_TREE_MULTI_DRAG_SOURCE_GET_IFACE( drag_source );
+
+	if( iface->get_drag_actions ){
+		return( iface->get_drag_actions( drag_source ));
+	}
+
+	return( 0 );
+}
+
+static gboolean
+on_button_press_event( GtkWidget *widget, GdkEventButton *event, EggTreeMultiDragSource *drag_source )
+{
+	GtkTreeView         *tree_view;
+	GtkTreePath         *path = NULL;
+	GtkTreeViewColumn   *column = NULL;
+	gint                 cell_x, cell_y;
+	GtkTreeSelection    *selection;
+	EggTreeMultiDndData *priv_data;
+	gboolean             call_parent;
+
+	if( event->window != gtk_tree_view_get_bin_window( GTK_TREE_VIEW( widget ))){
+		return( FALSE );
+	}
+
+	if( event->button == 3 ){
+		return( FALSE );
+	}
+
+	tree_view = GTK_TREE_VIEW( widget );
+	priv_data = g_object_get_data( G_OBJECT( tree_view ), EGG_TREE_MULTI_DND_STRING );
+	if( priv_data == NULL ){
+		priv_data = g_new0( EggTreeMultiDndData, 1 );
+		priv_data->pending_event = FALSE;
+		g_object_set_data( G_OBJECT( tree_view ), EGG_TREE_MULTI_DND_STRING, priv_data );
+	}
+
+	if( g_slist_find( priv_data->event_list, event )){
+		return( FALSE );
+	}
+
+	if( priv_data->pending_event ){
+		/* save the event to be propagated in order */
+		priv_data->event_list = g_slist_append( priv_data->event_list, gdk_event_copy(( GdkEvent * ) event ));
+		return( TRUE );
+	}
+
+	if( event->type == GDK_2BUTTON_PRESS ){
+		return( FALSE );
+	}
+
+	gtk_tree_view_get_path_at_pos( tree_view, event->x, event->y, &path, &column, &cell_x, &cell_y );
+
+	if( path ){
+		selection = gtk_tree_view_get_selection( tree_view );
+
+		call_parent = ( event->state & ( GDK_CONTROL_MASK | GDK_SHIFT_MASK ) ||
+				!gtk_tree_selection_path_is_selected( selection, path) ||
+				event->button != 1 );
+
+		if( call_parent ){
+			( GTK_WIDGET_GET_CLASS( tree_view ))->button_press_event( widget, event );
+		}
+
+		if( gtk_tree_selection_path_is_selected( selection, path )){
+			priv_data->pressed_button = event->button;
+			priv_data->x = event->x;
+			priv_data->y = event->y;
+			priv_data->pending_event = TRUE;
+
+			if( !call_parent ){
+				priv_data->event_list = g_slist_append( priv_data->event_list, gdk_event_copy(( GdkEvent * ) event ));
+			}
+
+			priv_data->motion_notify_handler =
+				g_signal_connect( G_OBJECT( tree_view ),
+						"motion_notify_event",
+						G_CALLBACK( on_motion_event ),
+						drag_source );
+
+			priv_data->button_release_handler =
+				g_signal_connect( G_OBJECT( tree_view ),
+						"button_release_event",
+						G_CALLBACK( on_button_release_event ),
+						drag_source );
+
+			if( priv_data->drag_data_get_handler == 0 ){
+				priv_data->drag_data_get_handler =
+					g_signal_connect( G_OBJECT( tree_view ),
+						"drag_data_get",
+						G_CALLBACK( on_drag_data_get ),
+						NULL );
+			}
+		}
+
+		gtk_tree_path_free (path);
+
+		/* We called the default handler so we don't let the default handler run */
+		return( TRUE );
+	}
+
+	return( FALSE );
+}
+
+static gboolean
+on_button_release_event( GtkWidget *widget, GdkEventButton *event, EggTreeMultiDragSource *drag_source )
+{
+	EggTreeMultiDndData *priv_data;
+	GSList *l;
+
+	priv_data = g_object_get_data( G_OBJECT( widget ), EGG_TREE_MULTI_DND_STRING );
+
+	for( l = priv_data->event_list ; l != NULL ; l = l->next ){
+		gtk_propagate_event( widget, l->data );
+	}
+
+	stop_drag_check( widget );
+
+	return( FALSE );
+}
+
+static gboolean
+on_motion_event( GtkWidget *widget, GdkEventMotion *event, EggTreeMultiDragSource *drag_source )
+{
+	EggTreeMultiDndData *priv_data;
+
+	priv_data = g_object_get_data( G_OBJECT( widget ), EGG_TREE_MULTI_DND_STRING );
+
+	if( gtk_drag_check_threshold( widget, priv_data->x, priv_data->y, event->x, event->y )){
+
+		GList            *path_list = NULL;
+		GtkTreeSelection *selection;
+		GtkTreeModel     *model;
+		GdkDragContext   *context;
+
+		stop_drag_check( widget );
+
+		selection = gtk_tree_view_get_selection( GTK_TREE_VIEW( widget ));
+		gtk_tree_selection_selected_foreach( selection, ( GtkTreeSelectionForeachFunc ) selection_foreach, &path_list );
+		path_list = g_list_reverse( path_list );
+
+		model = gtk_tree_view_get_model( GTK_TREE_VIEW( widget ));
+
+		if( egg_tree_multi_drag_source_row_draggable( EGG_TREE_MULTI_DRAG_SOURCE( model ), path_list )){
+
+			GtkTargetList *target_list = v_get_target_list( drag_source );
+			GdkDragAction actions = v_get_drag_actions( drag_source );
+
+			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 );
+
+			gtk_drag_set_icon_default( context );
+
+			v_free_target_list( drag_source, target_list );
+
+		} else {
+			path_list_free( path_list );
+		}
+	}
+
+	return( TRUE );
+}
+
+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";
+	GtkTreeView  *tree_view;
+	GtkTreeModel *model;
+	GList        *path_list;
+
+	g_debug( "%s: widget=%p, context=%p, selection_data=%p, info=%d, time=%d",
+			thisfn, ( void * ) widget, ( void * ) context, ( void * ) selection_data, info, time );
+
+	tree_view = GTK_TREE_VIEW( widget );
+	model = gtk_tree_view_get_model( tree_view );
+	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 );
+	}
+
+	/* We can implement the GTK_TREE_MODEL_ROW target generically for
+	 * any model; for DragSource models there are some other targets
+	 * we also support.
+	 */
+  return( egg_tree_multi_drag_source_drag_data_get(
+		  EGG_TREE_MULTI_DRAG_SOURCE( model ), context, selection_data, path_list, info ));
+}
+
+static void
+stop_drag_check( GtkWidget *widget )
+{
+	EggTreeMultiDndData *priv_data;
+	GSList *l;
+
+	priv_data = g_object_get_data( G_OBJECT( widget ), EGG_TREE_MULTI_DND_STRING );
+
+	for( l = priv_data->event_list ; l != NULL ; l = l->next ){
+		gdk_event_free( l->data );
+	}
+
+	g_slist_free( priv_data->event_list );
+	priv_data->event_list = NULL;
+	priv_data->pending_event = FALSE;
+
+	g_signal_handler_disconnect( widget, priv_data->motion_notify_handler );
+	g_signal_handler_disconnect( widget, priv_data->button_release_handler );
+}
+
+static void
+selection_foreach( GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, GList **path_list )
+{
+	*path_list = g_list_prepend( *path_list, gtk_tree_row_reference_new( model, path ));
+}
+
+static void
+path_list_free( GList *path_list )
+{
+	g_list_foreach( path_list, ( GFunc ) gtk_tree_row_reference_free, NULL );
+	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 )
+{
+	g_object_set_data_full(
+			G_OBJECT( treeview ),
+			"egg-tree-view-multi-source-row", path_list, ( GDestroyNotify ) path_list_free );
+}
+
+static GList *
+get_treeview_data( GtkWidget *treeview )
+{
+	return( g_object_get_data( G_OBJECT( treeview ), "egg-tree-view-multi-source-row" ));
+}
diff --git a/src/nact/egg-tree-multi-dnd.h b/src/nact/egg-tree-multi-dnd.h
new file mode 100644
index 0000000..55f307b
--- /dev/null
+++ b/src/nact/egg-tree-multi-dnd.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)
+ */
+
+/* eggtreednd.h
+ * Copyright (C) 2001  Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Adapted by Pierre Wieser for the needs of Nautilus Actions
+ */
+
+#ifndef __EGG_TREE_MULTI_DND_H__
+#define __EGG_TREE_MULTI_DND_H__
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+#define EGG_TYPE_TREE_MULTI_DRAG_SOURCE					( egg_tree_multi_drag_source_get_type())
+#define EGG_TREE_MULTI_DRAG_SOURCE( object )			( G_TYPE_CHECK_INSTANCE_CAST(( object ), EGG_TYPE_TREE_MULTI_DRAG_SOURCE, EggTreeMultiDragSource ))
+#define EGG_IS_TREE_MULTI_DRAG_SOURCE( object )			( G_TYPE_CHECK_INSTANCE_TYPE(( object ), EGG_TYPE_TREE_MULTI_DRAG_SOURCE ))
+#define EGG_TREE_MULTI_DRAG_SOURCE_GET_IFACE( object )	( G_TYPE_INSTANCE_GET_INTERFACE(( object ), EGG_TYPE_TREE_MULTI_DRAG_SOURCE, EggTreeMultiDragSourceIface ))
+
+typedef struct EggTreeMultiDragSource      EggTreeMultiDragSource;
+typedef struct EggTreeMultiDragSourceIface EggTreeMultiDragSourceIface;
+
+struct EggTreeMultiDragSourceIface
+{
+	GTypeInterface g_iface;
+
+	/* vtable - not signals */
+	gboolean        ( *row_draggable )   ( EggTreeMultiDragSource *drag_source, GList *path_list );
+	gboolean        ( *drag_data_get )   ( EggTreeMultiDragSource *drag_source, GdkDragContext *context, GtkSelectionData *selection_data, GList *path_list, guint info );
+	gboolean        ( *drag_data_delete )( EggTreeMultiDragSource *drag_source, GList *path_list );
+	GtkTargetList * ( *get_target_list ) ( EggTreeMultiDragSource *drag_source );
+	void            ( *free_target_list )( EggTreeMultiDragSource *drag_source, GtkTargetList *list );
+	GdkDragAction   ( *get_drag_actions )( EggTreeMultiDragSource *drag_source );
+};
+
+GType    egg_tree_multi_drag_source_get_type( void ) G_GNUC_CONST;
+
+/* initialize drag support on the treeview */
+void     egg_tree_multi_drag_add_drag_support( EggTreeMultiDragSource *drag_source, GtkTreeView *tree_view );
+
+/* returns whether the given row can be dragged */
+gboolean egg_tree_multi_drag_source_row_draggable( EggTreeMultiDragSource *drag_source, GList *path_list );
+
+/* Fills in selection_data with type selection_data->target based on the row
+ * denoted by path, returns TRUE if it does anything
+ */
+gboolean egg_tree_multi_drag_source_drag_data_get( EggTreeMultiDragSource *drag_source, GdkDragContext *context, GtkSelectionData *selection_data, GList *path_list, guint info );
+
+/* deletes the given row, or returns FALSE if it can't */
+gboolean egg_tree_multi_drag_source_drag_data_delete( EggTreeMultiDragSource *drag_source, GList *path_list );
+
+G_END_DECLS
+
+#endif /* __EGG_TREE_MULTI_DND_H__ */
diff --git a/src/nact/nact-application.c b/src/nact/nact-application.c
index 0835b42..58d762a 100644
--- a/src/nact/nact-application.c
+++ b/src/nact/nact-application.c
@@ -332,9 +332,9 @@ appli_initialize_application( BaseApplication *application )
 static gchar *
 appli_get_application_name( BaseApplication *application )
 {
-	static const gchar *thisfn = "nact_application_appli_get_application_name";
+	/*static const gchar *thisfn = "nact_application_appli_get_application_name";*/
 
-	g_debug( "%s: application=%p", thisfn, ( void * ) application );
+	/*g_debug( "%s: application=%p", thisfn, ( void * ) application );*/
 
 	/* i18n: this is the application name, used in window title */
 	return( g_strdup( _( "Nautilus Actions Configuration Tool" )));
diff --git a/src/nact/nact-assistant-export.c b/src/nact/nact-assistant-export.c
index ddc6a74..499dbb0 100644
--- a/src/nact/nact-assistant-export.c
+++ b/src/nact/nact-assistant-export.c
@@ -110,13 +110,12 @@ static void            assist_runtime_init_intro( NactAssistantExport *window, G
 
 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( GtkTreeSelection *selection, gpointer user_data );
+static void            on_actions_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 );
 static GtkFileChooser *get_folder_chooser( NactAssistantExport *window );
 static void            on_folder_selection_changed( GtkFileChooser *chooser, gpointer user_data );
-static gboolean        is_writable_dir( const gchar *uri );
 
 static void            assist_initial_load_format( NactAssistantExport *window, GtkAssistant *assistant );
 static void            assist_runtime_init_format( NactAssistantExport *window, GtkAssistant *assistant );
@@ -506,7 +505,7 @@ assist_runtime_init_actions_list( NactAssistantExport *window, GtkAssistant *ass
 }
 
 static void
-on_actions_list_selection_changed( GtkTreeSelection *selection, gpointer user_data )
+on_actions_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,12 +515,12 @@ on_actions_list_selection_changed( GtkTreeSelection *selection, gpointer user_da
 	gboolean enabled;
 	GtkWidget *content;
 
-	g_assert( NACT_IS_ASSISTANT_EXPORT( user_data ));
-	assistant = GTK_ASSISTANT( base_window_get_toplevel_dialog( BASE_WINDOW( user_data )));
+	g_assert( NACT_IS_ASSISTANT_EXPORT( instance ));
+	assistant = GTK_ASSISTANT( base_window_get_toplevel_dialog( BASE_WINDOW( instance )));
 	pos = gtk_assistant_get_current_page( assistant );
 	if( pos == ASSIST_PAGE_ACTIONS_SELECTION ){
 
-		enabled = ( gtk_tree_selection_count_selected_rows( selection ) > 0 );
+		enabled = ( g_slist_length( selected_items ) > 0 );
 
 		content = gtk_assistant_get_nth_page( assistant, pos );
 		gtk_assistant_set_page_complete( assistant, content, enabled );
@@ -590,7 +589,7 @@ on_folder_selection_changed( GtkFileChooser *chooser, gpointer user_data )
 
 		uri = gtk_file_chooser_get_uri( chooser );
 		g_debug( "%s: uri=%s", thisfn, uri );
-		enabled = ( uri && strlen( uri ) && is_writable_dir( uri ));
+		enabled = ( uri && strlen( uri ) && na_utils_is_writable_dir( uri ));
 
 		if( enabled ){
 			assist = NACT_ASSISTANT_EXPORT( user_data );
@@ -607,48 +606,6 @@ on_folder_selection_changed( GtkFileChooser *chooser, gpointer user_data )
 	}
 }
 
-static gboolean
-is_writable_dir( const gchar *uri )
-{
-	static const gchar *thisfn = "nact_assistant_export_is_writable_dir";
-	GFile *file;
-	GError *error = NULL;
-	GFileInfo *info;
-	GFileType type;
-	gboolean writable;
-
-	if( !uri || !strlen( uri )){
-		return( FALSE );
-	}
-
-	file = g_file_new_for_uri( uri );
-	info = g_file_query_info( file,
-			G_FILE_ATTRIBUTE_ACCESS_CAN_WRITE "," G_FILE_ATTRIBUTE_STANDARD_TYPE,
-			G_FILE_QUERY_INFO_NONE, NULL, &error );
-
-	if( error ){
-		g_warning( "%s: g_file_query_info error: %s", thisfn, error->message );
-		g_error_free( error );
-		g_object_unref( file );
-		return( FALSE );
-	}
-
-	type = g_file_info_get_file_type( info );
-	if( type != G_FILE_TYPE_DIRECTORY ){
-		g_warning( "%s: %s is not a directory", thisfn, uri );
-		g_object_unref( info );
-		return( FALSE );
-	}
-
-	writable = g_file_info_get_attribute_boolean( info, G_FILE_ATTRIBUTE_ACCESS_CAN_WRITE );
-	if( !writable ){
-		g_warning( "%s: %s is not writable", thisfn, uri );
-	}
-	g_object_unref( info );
-
-	return( writable );
-}
-
 static void
 assist_initial_load_format( NactAssistantExport *window, GtkAssistant *assistant )
 {
diff --git a/src/nact/nact-iaction-tab.c b/src/nact/nact-iaction-tab.c
index 1f2237c..06a8308 100644
--- a/src/nact/nact-iaction-tab.c
+++ b/src/nact/nact-iaction-tab.c
@@ -61,7 +61,6 @@ static GType         register_type( void );
 static void          interface_base_init( NactIActionTabInterface *klass );
 static void          interface_base_finalize( NactIActionTabInterface *klass );
 
-static NAObject     *v_get_selected( NactWindow *window );
 static NAAction     *v_get_edited_action( NactWindow *window );
 static void          v_field_modified( NactWindow *window );
 
@@ -214,11 +213,9 @@ nact_iaction_tab_dispose( NactWindow *dialog )
  * than one profile
  */
 void
-nact_iaction_tab_set_action( NactWindow *dialog, const NAAction *action )
+nact_iaction_tab_set_action( NactWindow *dialog, const NAAction *action, GSList *selected_items )
 {
-	/*static const gchar *thisfn = "nact_iaction_tab_set_action";
-	g_debug( "%s: dialog=%p, action=%p", thisfn, dialog, action );*/
-
+	static const gchar *thisfn = "nact_iaction_tab_set_action";
 	NAObject *current;
 	gboolean enabled;
 	GtkWidget *label_widget, *tooltip_widget, *icon_widget, *button;
@@ -226,11 +223,16 @@ nact_iaction_tab_set_action( NactWindow *dialog, const NAAction *action )
 	GtkButton *enabled_button;
 	gboolean enabled_action;
 
-	current = v_get_selected( dialog );
-	enabled = ( action != NULL );
-	if( NA_IS_ACTION_PROFILE( current)){
-		if( na_action_get_profiles_count( action ) > 1 ){
-			enabled = FALSE;
+	g_debug( "%s: dialog=%p, action=%p, selected_items=%p",
+			thisfn, ( void * ) dialog, ( void * ) action, ( void * ) selected_items );
+
+	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;
+			}
 		}
 	}
 
@@ -279,18 +281,6 @@ nact_iaction_tab_has_label( NactWindow *window )
 	return( g_utf8_strlen( label, -1 ) > 0 );
 }
 
-static NAObject *
-v_get_selected( NactWindow *window )
-{
-	g_assert( NACT_IS_IACTION_TAB( window ));
-
-	if( NACT_IACTION_TAB_GET_INTERFACE( window )->get_selected ){
-		return( NACT_IACTION_TAB_GET_INTERFACE( window )->get_selected( window ));
-	}
-
-	return( NULL );
-}
-
 static NAAction *
 v_get_edited_action( NactWindow *window )
 {
diff --git a/src/nact/nact-iaction-tab.h b/src/nact/nact-iaction-tab.h
index 9c27655..9d4d72a 100644
--- a/src/nact/nact-iaction-tab.h
+++ b/src/nact/nact-iaction-tab.h
@@ -68,7 +68,7 @@ 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_set_action( NactWindow *dialog, const NAAction *action );
+void     nact_iaction_tab_set_action( NactWindow *dialog, const NAAction *action, GSList *selected_items );
 gboolean nact_iaction_tab_has_label( NactWindow *window );
 
 G_END_DECLS
diff --git a/src/nact/nact-iactions-list.c b/src/nact/nact-iactions-list.c
index 28191f7..2693319 100644
--- a/src/nact/nact-iactions-list.c
+++ b/src/nact/nact-iactions-list.c
@@ -35,8 +35,11 @@
 #include <gdk/gdkkeysyms.h>
 #include <string.h>
 
+#include <common/na-iprefs.h>
+
 #include "nact-application.h"
 #include "nact-iactions-list.h"
+#include "nact-tree-model.h"
 
 /* private interface data
  */
@@ -44,28 +47,19 @@ struct NactIActionsListInterfacePrivate {
 	void *empty;						/* so that gcc -pedantic is happy */
 };
 
-/* column ordering
- */
-enum {
-	IACTIONS_LIST_ICON_COLUMN = 0,
-	IACTIONS_LIST_LABEL_COLUMN,
-	IACTIONS_LIST_NAOBJECT_COLUMN,
-	IACTIONS_LIST_N_COLUMN
-};
-
 /* 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 void       v_on_selection_changed( GtkTreeSelection *selection, gpointer user_data );
 static gboolean   v_on_button_press_event( GtkWidget *widget, GdkEventButton *event, gpointer data );
 static gboolean   v_on_key_pressed_event( GtkWidget *widget, GdkEventKey *event, gpointer data );
 static gboolean   v_is_modified_action( NactWindow *window, const NAAction *action );
@@ -73,11 +67,10 @@ 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 gint       sort_actions_list( GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b, NactWindow *window );
-static gboolean   filter_visible( GtkTreeModel *model, GtkTreeIter *iter, gpointer data );
 static GtkWidget *get_actions_list_widget( NactWindow *window );
 static GSList    *get_expanded_rows( NactWindow *window );
 static void       expand_rows( NactWindow *window, GSList *expanded );
@@ -155,14 +148,19 @@ interface_base_finalize( NactIActionsListInterface *klass )
 
 /**
  * Allocates and initializes the ActionsList widget.
+ *
+ * GtkTreeView is created with NactTreeModel model
+ * NactTreeModel
+ *   implements EggTreeMultiDragSourceIface
+ *   is derived from GtkTreeModelFilter
+ *     GtkTreeModelFilter is built on top of GtkTreeStore
  */
 void
 nact_iactions_list_initial_load( NactWindow *window )
 {
 	static const gchar *thisfn = "nact_iactions_list_initial_load";
 	GtkWidget *widget, *label;
-	GtkTreeStore *ts_model;
-	GtkTreeModel *tmf_model;
+	NactTreeModel *model;
 	GtkTreeViewColumn *column;
 	GtkCellRenderer *renderer;
 
@@ -179,28 +177,10 @@ nact_iactions_list_initial_load( NactWindow *window )
 	nact_iactions_list_set_send_selection_changed_on_fill_list( window, FALSE );
 	nact_iactions_list_set_is_filling_list( window, FALSE );
 
-	/* create the model */
-	ts_model = gtk_tree_store_new(
-			IACTIONS_LIST_N_COLUMN, GDK_TYPE_PIXBUF, G_TYPE_STRING, NA_OBJECT_TYPE );
-
-	gtk_tree_sortable_set_default_sort_func(
-			GTK_TREE_SORTABLE( ts_model ),
-	        ( GtkTreeIterCompareFunc ) sort_actions_list, window, NULL );
-
-	gtk_tree_sortable_set_sort_column_id(
-			GTK_TREE_SORTABLE( ts_model ),
-			IACTIONS_LIST_LABEL_COLUMN, GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID );
-
-	tmf_model = gtk_tree_model_filter_new( GTK_TREE_MODEL( ts_model ), NULL );
-
-	gtk_tree_model_filter_set_visible_func(
-			GTK_TREE_MODEL_FILTER( tmf_model ), ( GtkTreeModelFilterVisibleFunc ) filter_visible, window, NULL );
-
-	gtk_tree_view_set_model( GTK_TREE_VIEW( widget ), tmf_model );
+	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( tmf_model );
-	g_object_unref( ts_model );
+	g_object_unref( model );
 
 	/* create visible columns on the tree view */
 	column = gtk_tree_view_column_new_with_attributes(
@@ -237,13 +217,14 @@ nact_iactions_list_runtime_init( NactWindow *window )
 	g_assert( GTK_IS_WIDGET( widget ));
 
 	nact_iactions_list_fill( window, TRUE );
+	nact_tree_model_runtime_init_dnd( NACT_MAIN_WINDOW( window ), GTK_TREE_VIEW( widget ));
 
-	/* set up selection */
+	/* set up selection control */
 	nact_window_signal_connect(
 			window,
 			G_OBJECT( gtk_tree_view_get_selection( GTK_TREE_VIEW( widget ))),
 			"changed",
-			G_CALLBACK( v_on_selection_changed ));
+			G_CALLBACK( on_selection_changed ));
 
 	/* catch press 'Enter' */
 	nact_window_signal_connect(
@@ -344,6 +325,9 @@ nact_iactions_list_fill( NactWindow *window, gboolean keep_expanded )
  * - 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
@@ -385,7 +369,7 @@ nact_iactions_list_set_selection( NactWindow *window, GType type, const gchar *u
 	if( !uuid || !strlen( uuid )){
 		g_debug( "%s: null or empty uuid: unselect all", thisfn );
 		gtk_tree_selection_unselect_all( selection );
-		v_on_selection_changed( selection, window );
+		on_selection_changed( selection, NACT_IACTIONS_LIST( window ));
 		return;
 	}
 
@@ -394,7 +378,7 @@ nact_iactions_list_set_selection( NactWindow *window, GType type, const gchar *u
 	if( !iterok ){
 		g_debug( "%s: empty actions list: unselect all", thisfn );
 		gtk_tree_selection_unselect_all( selection );
-		v_on_selection_changed( selection, window );
+		on_selection_changed( selection, NACT_IACTIONS_LIST( window ));
 		return;
 	}
 
@@ -407,7 +391,7 @@ nact_iactions_list_set_selection( NactWindow *window, GType type, const gchar *u
 		nb_profiles = na_action_get_profiles_count( NA_ACTION( iter_object ));
 
 		if( type == NA_ACTION_TYPE || ( ret_uuid == 0 && nb_profiles == 1 )){
-			ret_label = g_utf8_collate( iter_label, label );
+			ret_label = label ? g_utf8_collate( iter_label, label ) : -1;
 
 			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 );
@@ -469,7 +453,7 @@ nact_iactions_list_select_first( NactWindow *window )
 	if( !iterok ){
 		g_debug( "%s: empty actions list: unselect all", thisfn );
 		gtk_tree_selection_unselect_all( selection );
-		v_on_selection_changed( selection, window );
+		on_selection_changed( selection, NACT_IACTIONS_LIST( window ));
 		return;
 	}
 
@@ -488,6 +472,7 @@ nact_iactions_list_set_focus( NactWindow *window )
 
 /**
  * Returns the currently selected action or profile.
+ * TODO: remove this function
  */
 NAObject *
 nact_iactions_list_get_selected_object( NactWindow *window )
@@ -517,34 +502,47 @@ nact_iactions_list_get_selected_object( NactWindow *window )
  *
  * 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
  */
 GSList *
 nact_iactions_list_get_selected_actions( NactWindow *window )
 {
-	GSList *actions = NULL;
+	return( nact_iactions_list_get_selected_items( NACT_IACTIONS_LIST( window )));
+}
+
+/**
+ * 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.
+ */
+GSList *
+nact_iactions_list_get_selected_items( NactIActionsList *instance )
+{
+	GSList *items = NULL;
 	GtkWidget *treeview;
 	GtkTreeSelection *selection;
 	GtkTreeModel *model;
 	GtkTreeIter iter;
 	GList *it, *listrows;
-	NAAction *action;
+	NAObject *object;
 	GtkTreePath *path;
 
-	treeview = get_actions_list_widget( window );
+	treeview = get_actions_list_widget( NACT_WINDOW( instance ));
 	selection = gtk_tree_view_get_selection( GTK_TREE_VIEW( treeview ));
 	listrows = gtk_tree_selection_get_selected_rows( selection, &model );
 
 	for( it = listrows ; it ; it = it->next ){
 		path = ( GtkTreePath * ) it->data;
 		gtk_tree_model_get_iter( model, &iter, path );
-		gtk_tree_model_get( model, &iter, IACTIONS_LIST_NAOBJECT_COLUMN, &action, -1 );
-		actions = g_slist_prepend( actions, action );
+		gtk_tree_model_get( model, &iter, IACTIONS_LIST_NAOBJECT_COLUMN, &object, -1 );
+		items = g_slist_prepend( items, object );
 	}
 
 	g_list_foreach( listrows, ( GFunc ) gtk_tree_path_free, NULL );
 	g_list_free( listrows );
 
-	return( g_slist_reverse( actions ));
+	return( g_slist_reverse( items ));
 }
 
 /*void
@@ -635,24 +633,29 @@ nact_iactions_list_toggle_collapse( NactWindow *window, const NAAction *action )
 void
 nact_iactions_list_update_selected( NactWindow *window, NAAction *action )
 {
-	GtkWidget *treeview = get_actions_list_widget( window );
-	GtkTreeSelection *selection = gtk_tree_view_get_selection( GTK_TREE_VIEW( treeview ));
-
+	GtkWidget *treeview;
+	GtkTreeSelection *selection;
+	GList *listrows, *irow;
 	GtkTreeModel *tm_model;
+	GtkTreePath *path;
 	GtkTreeIter iter;
 	NAObject *object;
-	GtkTreePath *path;
 	GtkTreeModelFilter *tmf_model;
 	GtkTreeStore *ts_model;
 	GtkTreeIter ts_iter;
 	GSList *profiles, *ip;
 
-	if( gtk_tree_selection_get_selected( selection, &tm_model, &iter )){
+	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 );
-
-		path = gtk_tree_model_get_path( tm_model, &iter );
+		g_assert( NA_IS_OBJECT( 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 ));
@@ -730,6 +733,16 @@ nact_iactions_list_set_is_filling_list( NactWindow *window, gboolean is_filling
 	g_object_set_data( G_OBJECT( window ), IS_FILLING_LIST, GINT_TO_POINTER( is_filling ));
 }
 
+/**
+ * Does the TreeView implements Drag&Drop ?
+ */
+void
+nact_iactions_list_set_dnd_mode( NactWindow *window, gboolean have_dnd )
+{
+	g_assert( NACT_IS_IACTIONS_LIST( window ));
+	g_object_set_data( G_OBJECT( window ), HAVE_DND_MODE, GINT_TO_POINTER( have_dnd ));
+}
+
 static GSList *
 v_get_actions( NactWindow *window )
 {
@@ -756,28 +769,6 @@ v_set_sorted_actions( NactWindow *window, GSList *actions )
 	}
 }*/
 
-static void
-v_on_selection_changed( GtkTreeSelection *selection, gpointer user_data )
-{
-	NactIActionsList *instance;
-	gboolean send_message, is_filling;
-
-	g_assert( NACT_IS_IACTIONS_LIST( user_data ));
-	g_assert( BASE_IS_WINDOW( user_data ));
-
-	instance = NACT_IACTIONS_LIST( user_data );
-
-	g_assert( NACT_IS_WINDOW( user_data ));
-	send_message = GPOINTER_TO_INT( g_object_get_data( G_OBJECT( user_data ), SEND_SELECTION_CHANGED_MESSAGE ));
-	is_filling = GPOINTER_TO_INT( g_object_get_data( G_OBJECT( user_data ), IS_FILLING_LIST ));
-
-	if( send_message || !is_filling ){
-		if( NACT_IACTIONS_LIST_GET_INTERFACE( instance )->on_selection_changed ){
-			NACT_IACTIONS_LIST_GET_INTERFACE( instance )->on_selection_changed( selection, user_data );
-		}
-	}
-}
-
 static gboolean
 v_on_button_press_event( GtkWidget *widget, GdkEventButton *event, gpointer user_data )
 {
@@ -879,6 +870,24 @@ v_is_valid_profile( NactWindow *window, const NAActionProfile *profile )
 	return( FALSE );
 }
 
+static void
+on_selection_changed( GtkTreeSelection *selection, NactIActionsList *instance )
+{
+	gboolean send_message, is_filling;
+	GSList *selected_items;
+
+	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 ));
+
+	selected_items = nact_iactions_list_get_selected_items( instance );
+
+	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 );
+		}
+	}
+}
+
 /*
  * action modified: italic
  * action not saveable: red
@@ -974,44 +983,6 @@ setup_profile( GtkWidget *treeview, GtkTreeStore *model, GtkTreeIter *iter, NAAc
 	g_free( label );
 }
 
-static gint
-sort_actions_list( GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b, NactWindow *window )
-{
-	gchar *labela, *labelb;
-	gint ret;
-
-	gtk_tree_model_get( model, a, IACTIONS_LIST_LABEL_COLUMN, &labela, -1 );
-	gtk_tree_model_get( model, b, IACTIONS_LIST_LABEL_COLUMN, &labelb, -1 );
-
-	ret = g_utf8_collate( labela, labelb );
-
-	g_free( labela );
-	g_free( labelb );
-
-	return( ret );
-}
-
-static gboolean
-filter_visible( GtkTreeModel *model, GtkTreeIter *iter, gpointer data )
-{
-	NAObject *object;
-	NAAction *action;
-
-	gtk_tree_model_get( model, iter, IACTIONS_LIST_NAOBJECT_COLUMN, &object, -1 );
-
-	if( object ){
-		if( NA_IS_ACTION( 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 );
-	}
-
-	return( FALSE );
-}
-
 static GtkWidget *
 get_actions_list_widget( NactWindow *window )
 {
diff --git a/src/nact/nact-iactions-list.h b/src/nact/nact-iactions-list.h
index f591a0f..17cf327 100644
--- a/src/nact/nact-iactions-list.h
+++ b/src/nact/nact-iactions-list.h
@@ -60,7 +60,7 @@ typedef struct {
 
 	/* api */
 	GSList * ( *get_actions )          ( NactWindow *window );
-	void     ( *on_selection_changed ) ( GtkTreeSelection *selection, gpointer user_data );
+	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 );
@@ -80,6 +80,7 @@ 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 );
+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 );*/
@@ -92,6 +93,7 @@ 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 );
 
 G_END_DECLS
 
diff --git a/src/nact/nact-imenubar.c b/src/nact/nact-imenubar.c
index ba58a22..867ac04 100644
--- a/src/nact/nact-imenubar.c
+++ b/src/nact/nact-imenubar.c
@@ -59,9 +59,9 @@ static void       interface_base_finalize( NactIMenubarInterface *klass );
 static void       on_file_menu_selected( GtkMenuItem *item, NactWindow *window );
 static void       on_new_action_activated( GtkMenuItem *item, NactWindow *window );
 static void       on_new_profile_activated( GtkMenuItem *item, NactWindow *window );
+static void       on_new_menu_activated( GtkMenuItem *item, NactWindow *window );
 static void       on_save_activated( GtkMenuItem *item, NactWindow *window );
 static void       on_quit_activated( GtkMenuItem *item, NactWindow *window );
-static void       add_action( NactWindow *window, NAAction *action );
 static void       add_profile( NactWindow *window, NAAction *action, NAActionProfile *profile );
 
 static void       on_edit_menu_selected( GtkMenuItem *item, NactWindow *window );
@@ -81,7 +81,7 @@ static void       on_about_activated( GtkMenuItem *item, NactWindow *window );
 static void       on_menu_item_selected( GtkItem *item, NactWindow *window );
 static void       on_menu_item_deselected( GtkItem *item, NactWindow *window );
 
-static void       v_add_action( NactWindow *window, NAAction *action );
+static void       v_insert_item( NactWindow *window, NAAction *action );
 static void       v_add_profile( NactWindow *window, NAActionProfile *profile );
 static void       v_remove_action( NactWindow *window, NAAction *action );
 static GSList    *v_get_deleted_actions( NactWindow *window );
@@ -111,6 +111,10 @@ static const GtkActionEntry entries[] = {
 				/* 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 ) },
+		{ "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 ) },
 		{ "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." ),
@@ -169,6 +173,9 @@ static const MenuOnSelectedStruct menu_callback[] = {
 };
 
 /* associates action with menu to be able to build their path
+ * should also be done by parsing the XML definition file (beurk !)
+ * or if Gtk+ would give the path of a given action (maybe in the
+ * future ??)
  */
 typedef struct {
 	char *menu;
@@ -179,6 +186,7 @@ typedef struct {
 static const MenuActionStruct menu_actions[] = {
 		{ "FileMenu", "NewActionItem" },
 		{ "FileMenu", "NewProfileItem" },
+		{ "FileMenu", "NewMenuItem" },
 		{ "FileMenu", "SaveItem" },
 		{ "FileMenu", "QuitItem" },
 		{ "EditMenu", "DuplicateItem" },
@@ -384,7 +392,7 @@ static void
 on_new_action_activated( GtkMenuItem *item, NactWindow *window )
 {
 	NAAction *action = na_action_new_with_profile();
-	add_action( window, action );
+	v_insert_item( window, action );
 }
 
 static void
@@ -412,6 +420,13 @@ on_new_profile_activated( GtkMenuItem *item, NactWindow *window )
 }
 
 static void
+on_new_menu_activated( GtkMenuItem *item, NactWindow *window )
+{
+	NAActionMenu *menu = na_action_menu_new();
+	v_insert_item( window, NA_ACTION( menu ));
+}
+
+static void
 on_save_activated( GtkMenuItem *item, NactWindow *window )
 {
 	static const gchar *thisfn = "nact_imenubar_on_save_activated";
@@ -523,25 +538,6 @@ on_quit_activated( GtkMenuItem *item, NactWindow *window )
 }
 
 static void
-add_action( NactWindow *window, NAAction *action )
-{
-	gchar *uuid, *label;
-
-	na_object_check_edited_status( NA_OBJECT( action ));
-	v_add_action( window, action );
-
-	v_update_actions_list( window );
-
-	uuid = na_action_get_uuid( action );
-	label = na_action_get_label( action );
-	v_select_actions_list( window, NA_ACTION_TYPE, uuid, label );
-	g_free( label );
-	g_free( uuid );
-
-	v_setup_dialog_title( window );
-}
-
-static void
 add_profile( NactWindow *window, NAAction *action, NAActionProfile *profile )
 {
 	gchar *uuid, *label;
@@ -617,7 +613,7 @@ on_duplicate_activated( GtkMenuItem *item, NactWindow *window )
 		g_free( dup_label );
 		g_free( label );
 
-		add_action( window, NA_ACTION( dup ));
+		v_insert_item( window, NA_ACTION( dup ));
 
 	} else {
 		g_assert( NA_IS_ACTION_PROFILE( object ));
@@ -643,14 +639,13 @@ on_delete_activated( GtkMenuItem *item, NactWindow *window )
 	GType type;
 	NAAction *action;
 
-	g_debug( "%s: item=%p, window=%p", thisfn, ( void * ) item, ( void * ) window );
-
 	object = v_get_selected( window );
-	g_debug( "%s: object=%p", thisfn, ( void * ) object );
 	if( !object ){
 		return;
 	}
 
+	g_debug( "%s: item=%p, window=%p", thisfn, ( void * ) item, ( void * ) window );
+
 	if( NA_IS_ACTION( object )){
 		uuid = na_action_get_uuid( NA_ACTION( object ));
 		label = na_action_get_label( NA_ACTION( object ));
@@ -727,7 +722,7 @@ on_import_activated( GtkMenuItem *item, NactWindow *window )
 	GSList *list = nact_assistant_import_run( window );
 	GSList *ia;
 	for( ia = list ; ia ; ia = ia->next ){
-		add_action( window, NA_ACTION( ia->data ));
+		v_insert_item( window, NA_ACTION( ia->data ));
 	}
 }
 
@@ -786,10 +781,12 @@ on_menu_item_deselected( GtkItem *item, NactWindow *window )
 }
 
 static void
-v_add_action( NactWindow *window, NAAction *action )
+v_insert_item( NactWindow *window, NAAction *action )
 {
-	if( NACT_IMENUBAR_GET_INTERFACE( window )->add_action ){
-		NACT_IMENUBAR_GET_INTERFACE( window )->add_action( window, action );
+	na_object_check_edited_status( NA_OBJECT( action ));
+
+	if( NACT_IMENUBAR_GET_INTERFACE( window )->insert_item ){
+		NACT_IMENUBAR_GET_INTERFACE( window )->insert_item( window, action );
 	}
 }
 
diff --git a/src/nact/nact-imenubar.h b/src/nact/nact-imenubar.h
index 55c4f4b..bbff770 100644
--- a/src/nact/nact-imenubar.h
+++ b/src/nact/nact-imenubar.h
@@ -55,7 +55,7 @@ typedef struct {
 	NactIMenubarInterfacePrivate *private;
 
 	/* api */
-	void        ( *add_action )            ( NactWindow *window, NAAction* action );
+	void        ( *insert_item )           ( NactWindow *window, NAAction* action );
 	void        ( *add_profile )           ( NactWindow *window, NAActionProfile *profile );
 	void        ( *remove_action )         ( NactWindow *window, NAAction *action );
 	GSList *    ( *get_deleted_actions )   ( NactWindow *window );
diff --git a/src/nact/nact-main-window.c b/src/nact/nact-main-window.c
index d937f05..bf524e5 100644
--- a/src/nact/nact-main-window.c
+++ b/src/nact/nact-main-window.c
@@ -40,6 +40,7 @@
 #include <common/na-pivot.h>
 #include <common/na-iio-provider.h>
 #include <common/na-ipivot-consumer.h>
+#include <common/na-iprefs.h>
 
 #include "nact-application.h"
 #include "nact-iactions-list.h"
@@ -83,6 +84,7 @@ static void             iconditions_tab_iface_init( NactIConditionsTabInterface
 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 );
@@ -95,11 +97,11 @@ 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( GtkTreeSelection *selection, gpointer user_data );
+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 );
-static void             set_current_profile( NactMainWindow *window, gboolean set_action );
+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 );
@@ -112,7 +114,7 @@ static void             get_isfiledir( NactWindow *window, gboolean *isfile, gbo
 static gboolean         get_multiple( NactWindow *window );
 static GSList          *get_schemes( NactWindow *window );
 
-static void             add_action( NactWindow *window, NAAction *action );
+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 );
@@ -126,6 +128,8 @@ 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 );
 
 GType
 nact_main_window_get_type( void )
@@ -193,12 +197,18 @@ register_type( void )
 		NULL
 	};
 
-	static const GInterfaceInfo pivot_consumer_iface_info = {
+	static const GInterfaceInfo ipivot_consumer_iface_info = {
 		( GInterfaceInitFunc ) ipivot_consumer_iface_init,
 		NULL,
 		NULL
 	};
 
+	static const GInterfaceInfo iprefs_iface_info = {
+		( GInterfaceInitFunc ) iprefs_iface_init,
+		NULL,
+		NULL
+	};
+
 	g_debug( "%s", thisfn );
 
 	type = g_type_register_static( NACT_WINDOW_TYPE, "NactMainWindow", &info, 0 );
@@ -215,7 +225,9 @@ register_type( void )
 
 	g_type_add_interface_static( type, NACT_IMENUBAR_TYPE, &imenubar_iface_info );
 
-	g_type_add_interface_static( type, NA_IPIVOT_CONSUMER_TYPE, &pivot_consumer_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 );
 
 	return( type );
 }
@@ -273,7 +285,6 @@ iaction_tab_iface_init( NactIActionTabInterface *iface )
 
 	g_debug( "%s: iface=%p", thisfn, ( void * ) iface );
 
-	iface->get_selected = nact_iactions_list_get_selected_object;
 	iface->get_edited_action = get_edited_action;
 	iface->field_modified = on_modified_field;
 }
@@ -321,7 +332,7 @@ imenubar_iface_init( NactIMenubarInterface *iface )
 
 	g_debug( "%s: iface=%p", thisfn, ( void * ) iface );
 
-	iface->add_action = add_action;
+	iface->insert_item = insert_item;
 	iface->add_profile = add_profile;
 	iface->remove_action = remove_action;
 	iface->get_deleted_actions = get_deleted_actions;
@@ -345,6 +356,15 @@ 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;
+}
+
+static void
+iprefs_iface_init( NAIPrefsInterface *iface )
+{
+	static const gchar *thisfn = "nact_main_window_iprefs_iface_init";
+
+	g_debug( "%s: iface=%p", thisfn, ( void * ) iface );
 }
 
 static void
@@ -503,6 +523,7 @@ on_initial_load_toplevel( BaseWindow *window )
 	NactMainWindow *wnd;
 	gint pos;
 	GtkWidget *pane;
+	/*gboolean alpha_order;*/
 
 	/* call parent class at the very beginning */
 	if( BASE_WINDOW_CLASS( st_parent_class )->initial_load_toplevel ){
@@ -518,8 +539,12 @@ on_initial_load_toplevel( BaseWindow *window )
 	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_multiple_selection( NACT_WINDOW( window ), FALSE );
 	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 ));
@@ -589,7 +614,9 @@ on_runtime_init_toplevel( BaseWindow *window )
 	/* forces a no-selection when the list is initially empty
 	 */
 	if( !wnd->private->initial_count ){
-		set_current_action( NACT_MAIN_WINDOW( window ));
+		set_current_action( NACT_MAIN_WINDOW( window ), NULL );
+	} else {
+		nact_iactions_list_select_first( NACT_WINDOW( window ));
 	}
 }
 
@@ -620,38 +647,36 @@ setup_dialog_title( NactWindow *window )
 	g_free( title );
 }
 
-/*
- * note that the IActionsList tree store may return an action or a profile
- */
 static void
-on_actions_list_selection_changed( GtkTreeSelection *selection, gpointer user_data )
+on_actions_list_selection_changed( NactIActionsList *instance, GSList *selected_items )
 {
 	static const gchar *thisfn = "nact_main_window_on_actions_list_selection_changed";
 	NactMainWindow *window;
 	NAObject *object;
+	gint count;
 
-	g_debug( "%s: selection=%p, user_data=%p", thisfn, ( void * ) selection, ( void * ) user_data );
+	g_debug( "%s: instance=%p, selected_items=%p", thisfn, ( void * ) instance, ( void * ) selected_items );
 
-	g_assert( NACT_IS_MAIN_WINDOW( user_data ));
-	window = NACT_MAIN_WINDOW( user_data );
+	g_assert( NACT_IS_MAIN_WINDOW( instance ));
+	window = NACT_MAIN_WINDOW( instance );
 
-	object = nact_iactions_list_get_selected_object( NACT_WINDOW( window ));
-	g_debug( "%s: object=%p", thisfn, ( void * ) object );
+	count = g_slist_length( selected_items );
 
-	if( object ){
+	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 );
+			set_current_action( window, selected_items );
 
 		} else {
 			g_assert( NA_IS_ACTION_PROFILE( object ));
 			window->private->edited_profile = NA_ACTION_PROFILE( object );
-			set_current_profile( window, TRUE );
+			set_current_profile( window, TRUE, selected_items );
 		}
 
 	} else {
 		window->private->edited_action = NULL;
-		set_current_action( window );
+		set_current_action( window, selected_items );
 	}
 }
 
@@ -680,11 +705,14 @@ on_actions_list_enter_key_pressed( GtkWidget *widget, GdkEventKey *event, gpoint
  * if there is only one profile, we also setup the profile
  */
 static void
-set_current_action( NactMainWindow *window )
+set_current_action( NactMainWindow *window, GSList *selected_items )
 {
-	g_debug( "set_current_action: current=%p", ( void * ) window->private->edited_action );
+	static const gchar *thisfn = "nact_main_window_set_current_action";
 
-	nact_iaction_tab_set_action( NACT_WINDOW( window ), window->private->edited_action );
+	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 );
 
 	window->private->edited_profile = NULL;
 
@@ -694,16 +722,21 @@ set_current_action( NactMainWindow *window )
 		}
 	}
 
-	set_current_profile( window, FALSE );
+	set_current_profile( window, FALSE, selected_items );
 }
 
 static void
-set_current_profile( NactMainWindow *window, gboolean set_action )
+set_current_profile( NactMainWindow *window, gboolean set_action, GSList *selected_items )
 {
+	static const gchar *thisfn = "nact_main_window_set_current_profile";
+
+	g_debug( "%s: window=%p, set_action=%s, selected_items=%p",
+			thisfn, ( void * ) window, set_action ? "True":"False", ( void * ) selected_items );
+
 	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 );
+		nact_iaction_tab_set_action( NACT_WINDOW( window ), window->private->edited_action, selected_items );
 	}
 
 	nact_icommand_tab_set_profile( NACT_WINDOW( window ), window->private->edited_profile );
@@ -789,11 +822,44 @@ 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
-add_action( NactWindow *window, NAAction *action )
+insert_item( NactWindow *window, NAAction *item )
 {
 	NactMainWindow *wnd = NACT_MAIN_WINDOW( window );
-	wnd->private->actions = g_slist_prepend( wnd->private->actions, ( gpointer ) action );
+	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 );
+
+	} 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 );
+		}
+	}
+
+	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
@@ -984,3 +1050,35 @@ on_actions_changed( NAIPivotConsumer *instance, gpointer user_data )
 		nact_iactions_list_fill( NACT_WINDOW( instance ), TRUE );
 	}
 }
+
+/*
+ * called by NAPivot via NAIPivotConsumer whenever the
+ * "sort in alphabetical order" preference is modified.
+ */
+static void
+on_display_order_changed( NAIPivotConsumer *instance, gpointer user_data )
+{
+	static const gchar *thisfn = "nact_main_window_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-preferences-editor.c b/src/nact/nact-preferences-editor.c
index 5b04776..0a1ca58 100644
--- a/src/nact/nact-preferences-editor.c
+++ b/src/nact/nact-preferences-editor.c
@@ -71,7 +71,8 @@ static void     on_runtime_init_dialog( BaseWindow *dialog );
 static void     on_all_widgets_showed( BaseWindow *dialog );
 /*static void     setup_buttons( NactPreferencesEditor *dialog, gboolean is_modified );
 static void     on_modified_field( NactWindow *dialog );*/
-static void     on_submenu_toggled( GtkToggleButton *button, NactWindow *window );
+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     save_preferences( NactPreferencesEditor *editor );
@@ -290,7 +291,7 @@ on_runtime_init_dialog( BaseWindow *dialog )
 {
 	static const gchar *thisfn = "nact_preferences_editor_on_runtime_init_dialog";
 	NactPreferencesEditor *editor;
-	gboolean as_submenu;
+	gboolean sort_alpha, add_about_item;
 	GtkWidget *button;
 
 	/* call parent class at the very beginning */
@@ -302,11 +303,15 @@ on_runtime_init_dialog( BaseWindow *dialog )
 	g_assert( NACT_IS_PREFERENCES_EDITOR( dialog ));
 	editor = NACT_PREFERENCES_EDITOR( dialog );
 
-	as_submenu = na_iprefs_get_bool( NA_IPREFS( editor ), PREFS_DISPLAY_AS_SUBMENU );
-	button = base_window_get_widget( dialog, "AsSubmenuButton" );
-	gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( button ), as_submenu );
+	sort_alpha = na_iprefs_get_alphabetical_order( NA_IPREFS( editor ));
+	button = base_window_get_widget( dialog, "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 ));
 
-	nact_window_signal_connect_by_name( NACT_WINDOW( editor ), "AsSubmenuButton", "toggled", G_CALLBACK( on_submenu_toggled ));
+	add_about_item = na_iprefs_get_add_about_item( NA_IPREFS( editor ));
+	button = base_window_get_widget( dialog, "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 ));
@@ -371,7 +376,14 @@ on_modified_field( NactWindow *window )
 }*/
 
 static void
-on_submenu_toggled( GtkToggleButton *button, NactWindow *window )
+on_sort_alpha_toggled( GtkToggleButton *button, NactWindow *window )
+{
+	g_assert( NACT_IS_PREFERENCES_EDITOR( window ));
+	/*NactPreferencesEditor *editor = NACT_PREFERENCES_EDITOR( window );*/
+}
+
+static void
+on_add_about_toggled( GtkToggleButton *button, NactWindow *window )
 {
 	g_assert( NACT_IS_PREFERENCES_EDITOR( window ));
 	/*NactPreferencesEditor *editor = NACT_PREFERENCES_EDITOR( window );*/
@@ -394,9 +406,16 @@ on_ok_clicked( GtkButton *button, NactWindow *window )
 static void
 save_preferences( NactPreferencesEditor *editor )
 {
-	GtkWidget *button = base_window_get_widget( BASE_WINDOW( editor ), "AsSubmenuButton" );
-	gboolean as_submenu = gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON( button ));
-	na_iprefs_set_bool( NA_IPREFS( editor ), PREFS_DISPLAY_AS_SUBMENU, as_submenu );
+	GtkWidget *button;
+	gboolean enabled;
+
+	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 );
+
+	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 );
 }
 
 static gboolean
diff --git a/src/nact/nact-selection.c b/src/nact/nact-selection.c
new file mode 100644
index 0000000..70edc85
--- /dev/null
+++ b/src/nact/nact-selection.c
@@ -0,0 +1,180 @@
+/*
+ * 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 <common/na-action.h>
+#include <common/na-action-profile.h>
+#include <common/na-xml-names.h>
+#include <common/na-xml-writer.h>
+
+#include "nact-selection.h"
+
+static void   export_action( const gchar *uri, const NAAction *action, GSList **exported );
+static gchar *get_action_xml_buffer( const NAAction *action, GSList **exported );
+
+/**
+ *
+ */
+char *
+nact_selection_get_data_for_intern_use( GSList *selected_items )
+{
+	GString *data;
+	GSList *item;
+
+	data = g_string_new( "" );
+
+	for( item = selected_items ; item ; item = item->next ){
+		gchar *chunk = na_object_get_clipboard_id( NA_OBJECT( item->data ));
+		if( chunk && strlen( chunk )){
+			data = g_string_append( data, chunk );
+			data = g_string_append( data, "\n" );
+		}
+		g_free( chunk );
+	}
+
+	return( g_string_free( data, FALSE ));
+}
+
+/**
+ * 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_selection_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_ACTION( item_object )){
+			chunk = get_action_xml_buffer( NA_ACTION( item_object ), &exported );
+
+		} else if( NA_IS_ACTION_PROFILE( item_object )){
+			NAAction *action = na_action_profile_get_action( NA_ACTION_PROFILE( item_object ));
+			chunk = get_action_xml_buffer( 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_selection_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_ACTION( item_object )){
+			export_action( uri, NA_ACTION( item_object ), &exported );
+
+		} else if( NA_IS_ACTION_PROFILE( item_object )){
+			NAAction *action = na_action_profile_get_action( NA_ACTION_PROFILE( item_object ));
+			export_action( uri, action, &exported );
+		}
+	}
+
+	g_slist_free( exported );
+}
+
+static void
+export_action( const gchar *uri, const NAAction *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( action, uri, FORMAT_GCONFENTRY );
+	buffer = na_xml_writer_get_xml_buffer( 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 NAAction *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( action, FORMAT_GCONFENTRY );
+
+	*exported = g_slist_prepend( *exported, ( gpointer ) action );
+
+	return( buffer );
+}
diff --git a/src/nact/nact-selection.h b/src/nact/nact-selection.h
new file mode 100644
index 0000000..0ac54c6
--- /dev/null
+++ b/src/nact/nact-selection.h
@@ -0,0 +1,45 @@
+/*
+ * Nautilus Actions
+ * A Nautilus extension which offers configurable context menu actions.
+ *
+ * Copyright (C) 2005 The GNOME Foundation
+ * Copyright (C) 2006, 2007, 2008 Frederic Ruaudel and others (see AUTHORS)
+ * Copyright (C) 2009 Pierre Wieser and others (see AUTHORS)
+ *
+ * This Program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this Library; see the file COPYING.  If not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place,
+ * Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Authors:
+ *   Frederic Ruaudel <grumz grumz net>
+ *   Rodrigo Moya <rodrigo gnome-db org>
+ *   Pierre Wieser <pwieser trychlos org>
+ *   ... and many others (see AUTHORS)
+ */
+
+#ifndef __NACT_DND_H__
+#define __NACT_DND_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_selection_export_items( const gchar *uri, GSList *items );
+
+G_END_DECLS
+
+#endif /* __NACT_DND_H__ */
diff --git a/src/nact/nact-tree-model.c b/src/nact/nact-tree-model.c
new file mode 100644
index 0000000..a35d8da
--- /dev/null
+++ b/src/nact/nact-tree-model.c
@@ -0,0 +1,694 @@
+/*
+ * 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)
+ */
+
+/*
+ * Adapted from File-Roller:fr-list-model.c
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+
+#include <common/na-action.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-tree-model.h"
+
+/*
+ * call once egg_tree_multi_drag_add_drag_support( treeview ) at init time (before gtk_main)
+ *
+ * when we start with drag
+ * 	 call once egg_tree_multi_dnd_on_button_press_event( treeview, event, drag_source )
+ *   call many egg_tree_multi_dnd_on_motion_event( treeview, event, drag_source )
+ *     until mouse quits the selected area
+ *
+ * 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 )
+ *
+ * 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 )
+ */
+
+/* private class data
+ */
+struct NactTreeModelClassPrivate {
+	void *empty;						/* so that gcc -pedantic is happy */
+};
+
+/* private instance data
+ */
+struct NactTreeModelPrivate {
+	gboolean        dispose_has_run;
+	NactMainWindow *window;
+	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
+
+};
+
+/* as a dnd source, we provide
+ * - 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 dnd_source_formats[] = {
+	{ "XdndNautilusActions", GTK_TARGET_SAME_WIDGET, NACT_XCHANGE_FORMAT_NACT },
+	{ "XdndDirectSave0",     GTK_TARGET_OTHER_APP,   NACT_XCHANGE_FORMAT_XDS },
+	{ "application/xml",     GTK_TARGET_OTHER_APP,   NACT_XCHANGE_FORMAT_APPLICATION_XML },
+	{ "text/plain",          GTK_TARGET_OTHER_APP,   NACT_XCHANGE_FORMAT_TEXT_PLAIN },
+};
+
+/*static GtkTargetEntry dnd_dest_targets[] = {
+	{ "XdndNautilusActions0", 0, 0 },
+	{ "XdndDirectSave0", 0, 2 }
+};*/
+
+static GtkTreeModelFilterClass *st_parent_class = NULL;
+
+static GType          register_type( void );
+static void           class_init( NactTreeModelClass *klass );
+static void           imulti_drag_source_init( EggTreeMultiDragSourceIface *iface );
+static void           idrag_dest_init( GtkTreeDragDestIface *iface );
+static void           instance_init( GTypeInstance *instance, gpointer klass );
+static void           instance_dispose( GObject *application );
+static void           instance_finalize( GObject *application );
+
+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 );
+static GtkTargetList *imulti_drag_source_get_target_list( EggTreeMultiDragSource *drag_source );
+static GdkDragAction  imulti_drag_source_get_drag_actions( EggTreeMultiDragSource *drag_source );
+
+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 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 char          *get_xds_atom_value( GdkDragContext *context );
+
+GType
+nact_tree_model_get_type( void )
+{
+	static GType model_type = 0;
+
+	if( !model_type ){
+		model_type = register_type();
+	}
+
+	return( model_type );
+}
+
+static GType
+register_type (void)
+{
+	static const gchar *thisfn = "nact_tree_model_register_type";
+	GType type;
+
+	static const GTypeInfo info = {
+		sizeof( NactTreeModelClass ),
+		NULL,		/* base_init */
+		NULL,		/* base_finalize */
+		( GClassInitFunc ) class_init,
+		NULL,		/* class_finalize */
+		NULL,		/* class_data */
+		sizeof( NactTreeModel ),
+		0,
+		( GInstanceInitFunc ) instance_init
+	};
+
+	static const GInterfaceInfo imulti_drag_source_info = {
+		( GInterfaceInitFunc ) imulti_drag_source_init,
+		NULL,
+		NULL
+	};
+
+	static const GInterfaceInfo idrag_dest_info = {
+		( GInterfaceInitFunc ) idrag_dest_init,
+		NULL,
+		NULL
+	};
+
+	g_debug( "%s", thisfn );
+
+	type = g_type_register_static( GTK_TYPE_TREE_MODEL_FILTER, "NactTreeModel", &info, 0 );
+
+	g_type_add_interface_static( type, EGG_TYPE_TREE_MULTI_DRAG_SOURCE, &imulti_drag_source_info );
+
+	g_type_add_interface_static( type, GTK_TYPE_TREE_DRAG_DEST, &idrag_dest_info );
+
+	return( type );
+}
+
+static void
+class_init( NactTreeModelClass *klass )
+{
+	static const gchar *thisfn = "nact_tree_model_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( NactTreeModelClassPrivate, 1 );
+}
+
+static void
+imulti_drag_source_init( EggTreeMultiDragSourceIface *iface )
+{
+	static const gchar *thisfn = "nact_tree_model_imulti_drag_source_init";
+
+	g_debug( "%s: iface=%p", thisfn, ( void * ) iface );
+
+	iface->row_draggable = imulti_drag_source_row_draggable;
+	iface->drag_data_get = imulti_drag_source_drag_data_get;
+	iface->drag_data_delete = imulti_drag_source_drag_data_delete;
+	iface->get_target_list = imulti_drag_source_get_target_list;
+	iface->free_target_list = NULL;
+	iface->get_drag_actions = imulti_drag_source_get_drag_actions;
+}
+
+static void
+idrag_dest_init( GtkTreeDragDestIface *iface )
+{
+	static const gchar *thisfn = "nact_tree_model_idrag_dest_init";
+
+	g_debug( "%s: iface=%p", thisfn, ( void * ) iface );
+
+	iface->drag_data_received = idrag_dest_drag_data_received;
+	iface->row_drop_possible = idrag_dest_row_drop_possible;
+}
+
+static void
+instance_init( GTypeInstance *instance, gpointer klass )
+{
+	/*static const gchar *thisfn = "nact_tree_model_instance_init";*/
+	NactTreeModel *self;
+
+	/*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;
+}
+
+static void
+instance_dispose( GObject *object )
+{
+	/*static const gchar *thisfn = "nact_tree_model_instance_dispose";*/
+	NactTreeModel *self;
+
+	/*g_debug( "%s: object=%p", thisfn, ( void * ) object );*/
+	g_assert( NACT_IS_TREE_MODEL( object ));
+	self = NACT_TREE_MODEL( 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 = "nact_tree_model_instance_finalize";*/
+	NactTreeModel *self;
+
+	/*g_debug( "%s: object=%p", thisfn, ( void * ) object );*/
+	g_assert( NACT_IS_TREE_MODEL( object ));
+	self = NACT_TREE_MODEL( object );
+
+	g_free( self->private->drag_dest_uri );
+	g_slist_free( self->private->drag_items );
+
+	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 );
+	}
+}
+
+NactTreeModel *
+nact_tree_model_new( NactMainWindow *window )
+{
+	GtkTreeStore  *ts_model;
+	NactTreeModel *model;
+	gboolean       alpha_order;
+
+	ts_model = gtk_tree_store_new(
+			IACTIONS_LIST_N_COLUMN, GDK_TYPE_PIXBUF, G_TYPE_STRING, NA_OBJECT_TYPE );
+
+	gtk_tree_sortable_set_default_sort_func(
+			GTK_TREE_SORTABLE( ts_model ),
+	        ( GtkTreeIterCompareFunc ) sort_actions_list, window, NULL );
+
+	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 */
+
+	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;
+
+	return( model );
+}
+
+/**
+ * nact_tree_model_runtime_init_dnd:
+ * @window: the #NactMainWindow window.
+ * @widget: the #GtkTreeView which implements this #NactTreeModel.
+ *
+ * Initializes the drag & drop features.
+ *
+ * We use drag and drop:
+ * - inside of treeview, for duplicating items, or moving items between
+ *   menus
+ * - from treeview to the outside world (e.g. Nautilus) to export actions
+ * - from outside world (e.g. Nautilus) to import actions
+ */
+void
+nact_tree_model_runtime_init_dnd( NactMainWindow *window, GtkTreeView *widget )
+{
+	NactTreeModel *model;
+
+	model = NACT_TREE_MODEL( gtk_tree_view_get_model( widget ));
+	g_assert( NACT_IS_TREE_MODEL( model ));
+
+	nact_window_signal_connect(
+			NACT_WINDOW( window ),
+			G_OBJECT( widget ),
+			"drag_begin",
+			G_CALLBACK( on_drag_begin ));
+
+	nact_window_signal_connect(
+			NACT_WINDOW( window ),
+			G_OBJECT( widget ),
+			"drag_end",
+			G_CALLBACK( on_drag_end ));
+
+	egg_tree_multi_drag_add_drag_support( EGG_TREE_MULTI_DRAG_SOURCE( model ), GTK_TREE_VIEW( widget ));
+
+	/*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
+	);*/
+
+	/*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 );*/
+}
+
+/*
+ * all rows are draggable
+ */
+static gboolean
+imulti_drag_source_row_draggable( EggTreeMultiDragSource *drag_source, GList *path_list )
+{
+	static const gchar *thisfn = "nact_tree_model_imulti_drag_source_row_draggable";
+	/*FrWindow     *window;
+	GtkTreeModel *model;
+	GList        *scan;*/
+
+	g_debug( "%s: drag_source=%p, path_list=%p", thisfn, ( void * ) drag_source, ( void * ) path_list );
+
+	/*window = g_object_get_data (G_OBJECT (drag_source), "FrWindow");
+	g_return_val_if_fail (window != NULL, FALSE);
+
+	model = fr_window_get_list_store (window);
+
+	for (scan = path_list; scan; scan = scan->next) {
+		GtkTreeRowReference *reference = scan->data;
+		GtkTreePath         *path;
+		GtkTreeIter          iter;
+		FileData            *fdata;
+
+		path = gtk_tree_row_reference_get_path (reference);
+		if (path == NULL)
+			continue;
+
+		if (! gtk_tree_model_get_iter (model, &iter, path))
+			continue;
+
+		gtk_tree_model_get (model, &iter,
+				    COLUMN_FILE_DATA, &fdata,
+				    -1);
+
+		if (fdata != NULL)
+			return TRUE;
+	}*/
+
+	return( TRUE );
+}
+
+/*
+ * drag_data_get is called when we release the selected items onto the
+ * destination
+ *
+ * if some rows are selected
+ * here, we only provide id. of dragged rows :
+ * 		M:uuid
+ * 		A:uuid
+ * 		P:uuid/name
+ * this is suitable and sufficient for the internal clipboard
+ *
+ * when exporting to the outside, we should prepare to export the items
+ */
+static gboolean
+imulti_drag_source_drag_data_get( EggTreeMultiDragSource *drag_source,
+				   GdkDragContext         *context,
+				   GtkSelectionData       *selection_data,
+				   GList                  *path_list,
+				   guint                   info )
+{
+	static const gchar *thisfn = "nact_tree_model_imulti_drag_source_drag_data_get";
+	gchar *atom_name;
+	NactTreeModel *model;
+	GSList *selected_items;
+	gchar *data;
+	gboolean ret = FALSE;
+	gchar *dest_folder, *folder;
+	gboolean is_writable;
+
+	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,
+			atom_name );
+	g_free( atom_name );
+
+	model = NACT_TREE_MODEL( drag_source );
+	g_assert( model->private->window );
+
+	selected_items = nact_iactions_list_get_selected_items( NACT_IACTIONS_LIST( model->private->window ));
+	if( !selected_items ){
+		return( FALSE );
+	}
+	if( !g_slist_length( selected_items )){
+		g_slist_free( selected_items );
+		return( FALSE );
+	}
+
+	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 );
+			ret = TRUE;
+			break;
+
+		case NACT_XCHANGE_FORMAT_XDS:
+			folder = get_xds_atom_value( context );
+			dest_folder = na_utils_remove_last_level_from_path( folder );
+			g_free( folder );
+			is_writable = na_utils_is_writable_dir( dest_folder );
+			gtk_selection_data_set( selection_data, selection_data->target, 8, ( guchar * )( is_writable ? "S" : "F" ), 1 );
+			if( is_writable ){
+				model->private->drag_dest_uri = g_strdup( dest_folder );
+				model->private->drag_items = g_slist_copy( selected_items );
+			}
+			g_free( dest_folder );
+			ret = TRUE;
+			break;
+
+		case NACT_XCHANGE_FORMAT_APPLICATION_XML:
+		case NACT_XCHANGE_FORMAT_TEXT_PLAIN:
+			data = nact_selection_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;
+			break;
+
+		default:
+			break;
+	}
+
+	g_slist_free( selected_items );
+	return( ret );
+}
+
+static gboolean
+imulti_drag_source_drag_data_delete( EggTreeMultiDragSource *drag_source, GList *path_list )
+{
+	static const gchar *thisfn = "nact_tree_model_imulti_drag_source_drag_data_delete";
+
+	g_debug( "%s: drag_source=%p, path_list=%p", thisfn, ( void * ) drag_source, ( void * ) path_list );
+
+	return( TRUE );
+}
+
+static GtkTargetList *
+imulti_drag_source_get_target_list( EggTreeMultiDragSource *drag_source )
+{
+	GtkTargetList *target_list;
+
+	target_list = gtk_target_list_new( dnd_source_formats, G_N_ELEMENTS( dnd_source_formats ));
+
+	return( target_list );
+}
+
+static GdkDragAction
+imulti_drag_source_get_drag_actions( EggTreeMultiDragSource *drag_source )
+{
+	return( GDK_ACTION_COPY | GDK_ACTION_MOVE );
+}
+
+static gboolean
+idrag_dest_drag_data_received( GtkTreeDragDest *drag_dest, GtkTreePath *dest, GtkSelectionData  *selection_data )
+{
+	static const gchar *thisfn = "nact_tree_model_idrag_dest_drag_data_received";
+
+	g_debug( "%s: drag_dest=%p, dest=%p, selection_data=%p", thisfn, ( void * ) drag_dest, ( void * ) dest, ( void * ) selection_data );
+
+	return( FALSE );
+}
+
+static gboolean
+idrag_dest_row_drop_possible( GtkTreeDragDest *drag_dest, GtkTreePath *dest_path, GtkSelectionData *selection_data )
+{
+	static const gchar *thisfn = "nact_tree_model_idrag_dest_row_drop_possible";
+
+	g_debug( "%s: drag_dest=%p, dest_path=%p, selection_data=%p", thisfn, ( void * ) drag_dest, ( void * ) dest_path, ( void * ) selection_data );
+
+	return( TRUE );
+}
+
+static gboolean
+on_drag_begin( GtkWidget *widget, GdkDragContext *context, NactWindow *window )
+{
+	static const gchar *thisfn = "nact_selection_on_drag_begin";
+	NactTreeModel *model;
+
+	g_debug( "%s: widget=%p, context=%p, window=%p",
+			thisfn, ( void * ) widget, ( void * ) context, ( void * ) window );
+
+	model = NACT_TREE_MODEL( gtk_tree_view_get_model( GTK_TREE_VIEW( widget )));
+
+	g_free( model->private->drag_dest_uri );
+	model->private->drag_dest_uri = NULL;
+
+	g_slist_free( model->private->drag_items );
+	model->private->drag_items = NULL;
+
+	gdk_property_change(
+			context->source_window,
+			XDS_ATOM, TEXT_ATOM, 8, GDK_PROP_MODE_REPLACE, ( guchar * ) XDS_FILENAME, strlen( XDS_FILENAME ));
+
+	return( FALSE );
+}
+
+static void
+on_drag_end( GtkWidget *widget, GdkDragContext *context, NactWindow *window )
+{
+	static const gchar *thisfn = "nact_selection_on_drag_end";
+	NactTreeModel *model;
+
+	g_debug( "%s: widget=%p, context=%p, window=%p",
+			thisfn, ( void * ) widget, ( void * ) context, ( void * ) 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 );
+	}
+
+	g_free( model->private->drag_dest_uri );
+	model->private->drag_dest_uri = NULL;
+
+	g_slist_free( model->private->drag_items );
+	model->private->drag_items = NULL;
+
+	gdk_property_delete( context->source_window, XDS_ATOM );
+}
+
+static gint
+sort_actions_list( GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b, NactWindow *window )
+{
+	static const gchar *thisfn = "nact_tree_model_sort_actions_list";
+	gchar *labela, *labelb;
+	gint ret;
+
+	g_debug( "%s: model=%p, a=%p, b=%p, window=%p", thisfn, ( void * ) model, ( void * ) a, ( void * ) b, ( void * ) window );
+
+	gtk_tree_model_get( model, a, IACTIONS_LIST_LABEL_COLUMN, &labela, -1 );
+	gtk_tree_model_get( model, b, IACTIONS_LIST_LABEL_COLUMN, &labelb, -1 );
+
+	ret = g_utf8_collate( labela, labelb );
+
+	g_free( labela );
+	g_free( labelb );
+
+	return( ret );
+}
+
+static gboolean
+filter_visible( GtkTreeModel *model, GtkTreeIter *iter, gpointer data )
+{
+	/*static const gchar *thisfn = "nact_tree_model_filter_visible";*/
+	NAObject *object;
+	NAAction *action;
+
+	/*g_debug( "%s: model=%p, iter=%p, data=%p", thisfn, ( void * ) model, ( void * ) iter, ( void * ) data );*/
+
+	gtk_tree_model_get( model, iter, IACTIONS_LIST_NAOBJECT_COLUMN, &object, -1 );
+
+	if( object ){
+		if( NA_IS_ACTION( 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 );
+	}
+
+	return( FALSE );
+}
+
+/*
+ * from FileRoller
+ */
+/* The following three functions 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)
+{
+	char *ret;
+
+	g_return_val_if_fail (context != NULL, NULL);
+	g_return_val_if_fail (context->source_window != NULL, NULL);
+
+	gdk_property_get (context->source_window,
+						XDS_ATOM, TEXT_ATOM,
+						0, MAX_XDS_ATOM_VAL_LEN,
+						FALSE, NULL, NULL, NULL,
+						(unsigned char **) &ret);
+
+	return ret;
+}
diff --git a/src/nact/nact-tree-model.h b/src/nact/nact-tree-model.h
new file mode 100644
index 0000000..a2b773c
--- /dev/null
+++ b/src/nact/nact-tree-model.h
@@ -0,0 +1,95 @@
+/*
+ * 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)
+ */
+
+/*
+ * Adapted from File-Roller:fr-list-model.h
+ */
+
+/**
+ * SECTION: nact_tree_model
+ *
+ * NactTreeModel is derived from GtkTreeModelFilter in order to be able
+ * to selectively display profiles, whether an action has one or more
+ * profiles.
+ *
+ * NactTreeModel implements EggTreeMultiDragSource and GtkTreeDragDest
+ * interfaces.
+ *
+ * The GtkTreeModelFilter base class embeds a GtkTreeStore.
+ */
+#ifndef __NACT_TREE_MODEL_H__
+#define __NACT_TREE_MODEL_H__
+
+#include <gtk/gtk.h>
+
+#include "nact-main-window.h"
+
+G_BEGIN_DECLS
+
+#define NACT_TREE_MODEL_TYPE				( nact_tree_model_get_type())
+#define NACT_TREE_MODEL( object )			( G_TYPE_CHECK_INSTANCE_CAST(( object ), NACT_TREE_MODEL_TYPE, NactTreeModel ))
+#define NACT_TREE_MODEL_CLASS( klass )		( G_TYPE_CHECK_CLASS_CAST(( klass ), NACT_TREE_MODEL_TYPE, NactTreeModelClass ))
+#define NACT_IS_TREE_MODEL( object )		( G_TYPE_CHECK_INSTANCE_TYPE(( object ), NACT_TREE_MODEL_TYPE ))
+#define NACT_IS_TREE_MODEL_CLASS( klass )	( G_TYPE_CHECK_CLASS_TYPE(( klass ), NACT_TREE_MODEL_TYPE ))
+#define NACT_TREE_MODEL_GET_CLASS( object )	( G_TYPE_INSTANCE_GET_CLASS(( object ), NACT_TREE_MODEL_TYPE, NactTreeModelClass ))
+
+typedef struct NactTreeModelPrivate NactTreeModelPrivate;
+
+typedef struct {
+	GtkTreeModelFilter    parent;
+	NactTreeModelPrivate *private;
+}
+	NactTreeModel;
+
+typedef struct NactTreeModelClassPrivate NactTreeModelClassPrivate;
+
+typedef struct {
+	GtkTreeModelFilterClass    parent;
+	NactTreeModelClassPrivate *private;
+}
+	NactTreeModelClass;
+
+/* column ordering of the tree view
+ */
+enum {
+	IACTIONS_LIST_ICON_COLUMN = 0,
+	IACTIONS_LIST_LABEL_COLUMN,
+	IACTIONS_LIST_NAOBJECT_COLUMN,
+	IACTIONS_LIST_N_COLUMN
+};
+
+GType          nact_tree_model_get_type( void );
+
+NactTreeModel *nact_tree_model_new( NactMainWindow *window );
+void           nact_tree_model_runtime_init_dnd( NactMainWindow *window, GtkTreeView *widget );
+
+G_END_DECLS
+
+#endif /* __NACT_TREE_MODEL_H__ */
diff --git a/src/nact/nact-window.h b/src/nact/nact-window.h
index c92a1c0..67279a2 100644
--- a/src/nact/nact-window.h
+++ b/src/nact/nact-window.h
@@ -39,6 +39,7 @@
  */
 
 #include <common/na-action.h>
+#include <common/na-action-menu.h>
 #include <common/na-action-profile.h>
 #include <common/na-pivot.h>
 
diff --git a/src/nact/nautilus-actions-config-tool.actions b/src/nact/nautilus-actions-config-tool.actions
index 459b654..61ac0d8 100644
--- a/src/nact/nautilus-actions-config-tool.actions
+++ b/src/nact/nautilus-actions-config-tool.actions
@@ -4,6 +4,7 @@
         <menu action="FileMenu">
             <menuitem action="NewActionItem" />
             <menuitem action="NewProfileItem" />
+            <menuitem action="NewMenuItem" />
             <menuitem action="SaveItem" />
             <separator />
             <menuitem action="QuitItem" />
diff --git a/src/nact/nautilus-actions-config-tool.ui b/src/nact/nautilus-actions-config-tool.ui
index 637f706..3857952 100644
--- a/src/nact/nautilus-actions-config-tool.ui
+++ b/src/nact/nautilus-actions-config-tool.ui
@@ -1009,10 +1009,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="preview_widget_active">False</property>
         <property name="use_preview_label">False</property>
-        <property name="select_multiple">True</property>
+        <property name="preview_widget_active">False</property>
       </object>
     </child>
     <child>
@@ -1116,9 +1116,9 @@ to extend a selection.</property>
           <object class="GtkFileChooserWidget" id="ExportFolderChooser">
             <property name="visible">True</property>
             <property name="local_only">False</property>
-            <property name="action">select-folder</property>
-            <property name="preview_widget_active">False</property>
             <property name="use_preview_label">False</property>
+            <property name="preview_widget_active">False</property>
+            <property name="action">select-folder</property>
           </object>
           <packing>
             <property name="position">0</property>
@@ -1743,15 +1743,16 @@ The exported file may later be imported via :
                 <child>
                   <object class="GtkVBox" id="vbox2">
                     <property name="visible">True</property>
-                    <property name="border_width">5</property>
+                    <property name="border_width">10</property>
                     <property name="orientation">vertical</property>
                     <property name="spacing">10</property>
                     <child>
-                      <object class="GtkCheckButton" id="AsSubmenuButton">
-                        <property name="label" translatable="yes">Display available actions as a Nautilus _submenu</property>
+                      <object class="GtkCheckButton" id="SortAlphabeticalButton">
+                        <property name="label" translatable="yes">_Sort actions in alphabetical order</property>
                         <property name="visible">True</property>
                         <property name="can_focus">True</property>
                         <property name="receives_default">False</property>
+                        <property name="tooltip_text" translatable="yes">When checked, actions appear in Nautilus context menu in alphabetical order of their label. Unchecked, this option lets you reorder yourself the actions.</property>
                         <property name="use_underline">True</property>
                         <property name="draw_indicator">True</property>
                       </object>
@@ -1759,6 +1760,20 @@ The exported file may later be imported via :
                         <property name="position">0</property>
                       </packing>
                     </child>
+                    <child>
+                      <object class="GtkCheckButton" id="AddAboutButton">
+                        <property name="label" translatable="yes">Add an '_About Nautilus Actions' item in the Nautilus context menu</property>
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="receives_default">False</property>
+                        <property name="tooltip_text" translatable="yes">When checked, and if only a single entry is defined as a root menu in the Nautilus context menu, then add an "About Nautilus Actions" at the end of the first level of your submenu.</property>
+                        <property name="use_underline">True</property>
+                        <property name="draw_indicator">True</property>
+                      </object>
+                      <packing>
+                        <property name="position">1</property>
+                      </packing>
+                    </child>
                   </object>
                 </child>
               </object>
@@ -1824,16 +1839,16 @@ The exported file may later be imported via :
   </object>
   <object class="GtkSizeGroup" id="CommandLabelSizeGroup">
     <widgets>
-      <widget name="ProfileLabelLabel"/>
-      <widget name="CommandPathLabel"/>
-      <widget name="CommandParametersLabel"/>
       <widget name="CommandExamplePreLabel"/>
+      <widget name="CommandParametersLabel"/>
+      <widget name="CommandPathLabel"/>
+      <widget name="ProfileLabelLabel"/>
     </widgets>
   </object>
   <object class="GtkSizeGroup" id="CommandButtonSizeGroup">
     <widgets>
-      <widget name="CommandPathButton"/>
       <widget name="CommandLegendButton"/>
+      <widget name="CommandPathButton"/>
     </widgets>
   </object>
 </interface>
diff --git a/src/plugin/nautilus-actions.c b/src/plugin/nautilus-actions.c
index 0fcdaa4..711b8a9 100644
--- a/src/plugin/nautilus-actions.c
+++ b/src/plugin/nautilus-actions.c
@@ -74,8 +74,8 @@ 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_sub_menu( NautilusMenu **menu );
-static void              add_post_submenu( NautilusMenu *menu );
+/*static NautilusMenuItem *create_sub_menu( NautilusMenu **menu );*/
+static void              add_about_item( NautilusMenu *menu );
 static void              execute_action( NautilusMenuItem *item, NAActionProfile *profile );
 static void              actions_changed_handler( NAIPivotConsumer *instance, gpointer user_data );
 
@@ -281,7 +281,8 @@ get_file_items( NautilusMenuProvider *provider, GtkWidget *window, GList *files
 	NautilusMenuItem *item;
 	GSList *actions = NULL;
 	gchar *label, *uuid;
-	gboolean have_submenu;
+	gint submenus = 0;
+	gboolean add_about;
 
 	g_debug( "%s: provider=%p, window=%p, files=%p, count=%d",
 			thisfn, ( void * ) provider, ( void * ) window, ( void * ) files, g_list_length( files ));
@@ -294,8 +295,6 @@ get_file_items( NautilusMenuProvider *provider, GtkWidget *window, GList *files
 		return(( GList * ) NULL );
 	}
 
-	have_submenu = na_iprefs_get_bool( NA_IPREFS( self ), PREFS_DISPLAY_AS_SUBMENU );
-
 	if( !self->private->dispose_has_run ){
 		actions = na_pivot_get_actions( self->private->pivot );
 
@@ -333,22 +332,24 @@ get_file_items( NautilusMenuProvider *provider, GtkWidget *window, GList *files
 
 				if( na_action_profile_is_candidate( profile, files )){
 					item = create_menu_item( action, profile, files );
+					items = g_list_append( items, item );
 
-					if( have_submenu ){
+					/*if( have_submenu ){
 						if( !menu ){
 							items = g_list_append( items, create_sub_menu( &menu ));
 						}
 						nautilus_menu_append_item( menu, item );
 
 					} else {
-						items = g_list_append( items, item );
-					}
+					}*/
 					break;
 				}
 			}
 		}
-		if( have_submenu ){
-			add_post_submenu( menu );
+
+		add_about = na_iprefs_get_add_about_item( NA_IPREFS( self ));
+		if( submenus == 1 && add_about ){
+			add_about_item( menu );
 		}
 	}
 
@@ -398,7 +399,7 @@ create_menu_item( NAAction *action, NAActionProfile *profile, GList *files )
 	return( item );
 }
 
-static NautilusMenuItem *
+/*static NautilusMenuItem *
 create_sub_menu( NautilusMenu **menu )
 {
 	NautilusMenuItem *item;
@@ -418,10 +419,10 @@ create_sub_menu( NautilusMenu **menu )
 	g_free( icon_name );
 
 	return( item );
-}
+}*/
 
 static void
-add_post_submenu( NautilusMenu *menu )
+add_about_item( NautilusMenu *menu )
 {
 	gchar *icon_name = na_about_get_icon_name();
 



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