[nautilus-actions] Export actions and menus to buffer



commit 5ffab9bed3ef362730d92905a924db14502615ec
Author: Pierre Wieser <pwieser trychlos org>
Date:   Wed Mar 3 01:22:46 2010 +0100

    Export actions and menus to buffer

 ChangeLog                                      |   59 +++
 TODO                                           |    2 +
 po/POTFILES.in                                 |    6 +-
 src/api/na-data-types.h                        |    2 +
 src/api/na-ifactory-object-data.h              |    1 +
 src/api/na-ifactory-object.h                   |    9 +-
 src/core/Makefile.am                           |    1 +
 src/core/na-core-utils.c                       |    6 +-
 src/core/na-data-types.c                       |   76 +++
 src/core/na-exporter.c                         |   96 +++--
 src/core/na-exporter.h                         |    2 +-
 src/core/na-factory-object.c                   |   43 +--
 src/core/na-factory-object.h                   |    2 +
 src/core/na-ifactory-object.c                  |   36 ++
 src/core/na-object-action-factory.c            |   27 +-
 src/core/na-object-action.c                    |   11 +-
 src/core/na-object-item-factory.c              |   64 ++-
 src/core/na-object-menu.c                      |   11 +-
 src/core/na-object-profile-factory.c           |  123 ++++--
 src/io-gconf/nagp-keys.h                       |    2 +-
 src/io-xml/Makefile.am                         |    7 +-
 src/io-xml/naxml-formats.c                     |   77 +++
 src/io-xml/naxml-formats.h                     |   42 ++
 src/io-xml/naxml-keys.h                        |  112 -----
 src/io-xml/naxml-provider.c                    |   55 +--
 src/io-xml/{na-xml-writer.c => naxml-writer.c} |  634 ++++++++++++++++++++----
 src/io-xml/{na-xml-writer.h => naxml-writer.h} |   43 +-
 src/nact/nact-clipboard.c                      |   35 +-
 src/nact/nact-tree-model-dnd.c                 |   63 ++-
 29 files changed, 1194 insertions(+), 453 deletions(-)
---
diff --git a/ChangeLog b/ChangeLog
index 5dc277b..e929b50 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,62 @@
+2009-03-03 Pierre Wieser <pwieser trychlos org>
+
+	* po/POTFILES.in: Updated.
+
+	* src/api/na-data-types.h
+	(na_data_types_get_gconf_dump_key): New function.
+
+	* src/core/na-data-types.c: New file.
+
+	* src/core/Makefile.am: Updated accordingly.
+
+	* src/api/na-ifactory-object-data.h:
+	* src/core/na-object-item-factory.c:
+	(NAFO_DATA_TYPE): New elementary data.
+
+	* src/core/na-ifactory-object.c:
+	* src/api/na-ifactory-object.h
+	(na_ifactory_object_get_data_boxed): New function.
+
+	* src/core/na-core-utils.c (na_core_utils_dir_is_writable_uri):
+	Give a better name to the parameter.
+
+	* src/core/na-exporter.c:
+	* src/core/na-exporter.h (na_exporter_to_buffer, na_exporter_to_file):
+	Reorder of functions in the files.
+
+	* src/core/na-factory-object.c:
+	* src/core/na-factory-object.h:
+	Now use the new na_ifactory_object_get_data_boxed() function.
+
+	* src/core/na-object-action-factory.c:
+	* src/core/na-object-profile-factory.c:
+	* src/io-xml/naxml-keys.h:
+	Move the schema descriptions to data factory.
+
+	* src/core/na-object-action.c:
+	* src/core/na-object-menu.c:
+	(ifactory_object_read_start): Allocate the 'type' data boxed.
+
+	* src/io-gconf/nagp-keys.h: Fix the path of the schemas.
+
+	* src/io-xml/naxml-formats.c:
+	* src/io-xml/naxml-formats.h: New files.
+
+	* src/io-xml/Makefile.am: Updated accordingly.
+
+	* src/io-xml/naxml-provider.c: Implement NAXMLWriter calls.
+
+	* src/io-xml/naxml-writer.c:
+	* src/io-xml/naxml-writer.h: Export to buffer.
+
+	* src/nact/nact-clipboard.c
+	(nact_clipboard_dnd_drag_end): Fix gtk_selection_data_free() call.
+	(export_row_object): Also exports menus.
+
+	* src/nact/nact-tree-model-dnd.c
+	(nact_tree_model_dnd_imulti_drag_source_drag_data_get):
+	Fix and parse the returned URI to get the path of the target folder.
+
 2009-03-01 Pierre Wieser <pwieser trychlos org>
 
 	* po/POTFILES.in: Add src/core/na-exporter.c file.
diff --git a/TODO b/TODO
index 468116c..38fcb01 100644
--- a/TODO
+++ b/TODO
@@ -161,3 +161,5 @@
 - icon: is defined as localestring in desktop entry spec
   but path is defined as string in this same spec
   and icon may be a path -> so what to do with this ?
+
+- get_xds_atom_value: test on 64bit platform, then remove debug stuff
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 452258a..b3133b0 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -5,14 +5,16 @@ src/core/na-importer-ask.c
 src/core/na-importer-ask.ui
 src/core/na-io-provider.c
 src/core/na-object-action.c
+src/core/na-object-action-factory.c
 src/core/na-object-id.c
+src/core/na-object-item-factory.c
 src/core/na-object-menu.c
+src/core/na-object-profile.c
 src/core/na-object-profile-factory.c
 src/io-desktop/nadp-desktop-provider.c
 src/io-gconf/nagp-gconf-provider.c
-src/io-xml/naxml-keys.h
 src/io-xml/naxml-reader.c
-src/io-xml/naxml-provider.c
+src/io-xml/naxml-formats.c
 src/nact/base-application.c
 src/nact/base-assistant.c
 src/nact/base-window.c
diff --git a/src/api/na-data-types.h b/src/api/na-data-types.h
index 4138ed8..679bba2 100644
--- a/src/api/na-data-types.h
+++ b/src/api/na-data-types.h
@@ -71,6 +71,8 @@ enum {
 	NAFD_TYPE_UINT,						/* an unsigned integer */
 };
 
+const gchar *na_data_types_get_gconf_dump_key( guint type );
+
 G_END_DECLS
 
 #endif /* __NAUTILUS_ACTIONS_API_NA_FACTORY_DATA_TYPES_H__ */
diff --git a/src/api/na-ifactory-object-data.h b/src/api/na-ifactory-object-data.h
index 944625b..3ec16f7 100644
--- a/src/api/na-ifactory-object-data.h
+++ b/src/api/na-ifactory-object-data.h
@@ -46,6 +46,7 @@ G_BEGIN_DECLS
 #define NAFO_DATA_PARENT					"na-factory-data-parent"
 
 #define NA_FACTORY_OBJECT_ITEM_GROUP		"na-factory-group-item"
+#define NAFO_DATA_TYPE						"na-factory-data-type"
 #define NAFO_DATA_LABEL						"na-factory-data-label"
 #define NAFO_DATA_TOOLTIP					"na-factory-data-tooltip"
 #define NAFO_DATA_ICON						"na-factory-data-icon"
diff --git a/src/api/na-ifactory-object.h b/src/api/na-ifactory-object.h
index 0527400..7f9a7d0 100644
--- a/src/api/na-ifactory-object.h
+++ b/src/api/na-ifactory-object.h
@@ -49,6 +49,7 @@
  */
 
 #include "na-data-def.h"
+#include "na-data-boxed.h"
 #include "na-ifactory-provider-provider.h"
 
 G_BEGIN_DECLS
@@ -172,11 +173,13 @@ typedef struct {
 }
 	NAIFactoryObjectInterface;
 
-GType      na_ifactory_object_get_type( void );
+GType        na_ifactory_object_get_type( void );
 
-void      *na_ifactory_object_get_as_void  ( const NAIFactoryObject *object, const gchar *name );
+NADataBoxed *na_ifactory_object_get_data_boxed( const NAIFactoryObject *object, const gchar *name );
 
-void       na_ifactory_object_set_from_void( NAIFactoryObject *object, const gchar *name, const void *data );
+void        *na_ifactory_object_get_as_void   ( const NAIFactoryObject *object, const gchar *name );
+
+void         na_ifactory_object_set_from_void ( NAIFactoryObject *object, const gchar *name, const void *data );
 
 #if 0
 void        na_ifactory_object_set_from_string( NAIFactoryObject *object, guint data_id, const gchar *data );
diff --git a/src/core/Makefile.am b/src/core/Makefile.am
index 3130d43..fd235c4 100644
--- a/src/core/Makefile.am
+++ b/src/core/Makefile.am
@@ -41,6 +41,7 @@ AM_CPPFLAGS += \
 libna_core_la_SOURCES = \
 	na-core-utils.c										\
 	na-data-boxed.c										\
+	na-data-types.c										\
 	na-dbus-tracker.h									\
 	na-exporter.c										\
 	na-exporter.h										\
diff --git a/src/core/na-core-utils.c b/src/core/na-core-utils.c
index 3829f61..5770d0f 100644
--- a/src/core/na-core-utils.c
+++ b/src/core/na-core-utils.c
@@ -522,7 +522,7 @@ na_core_utils_dir_is_writable_uri( const gchar *uri )
 }
 
 static gboolean
-info_dir_is_writable( GFile *file, const gchar *path )
+info_dir_is_writable( GFile *file, const gchar *path_or_uri )
 {
 	static const gchar *thisfn = "na_core_utils_info_dir_is_writable";
 	GError *error = NULL;
@@ -542,14 +542,14 @@ info_dir_is_writable( GFile *file, const gchar *path )
 
 	type = g_file_info_get_file_type( info );
 	if( type != G_FILE_TYPE_DIRECTORY ){
-		g_debug( "%s: %s is not a directory", thisfn, path );
+		g_debug( "%s: %s is not a directory", thisfn, path_or_uri );
 		g_object_unref( info );
 		return( FALSE );
 	}
 
 	writable = g_file_info_get_attribute_boolean( info, G_FILE_ATTRIBUTE_ACCESS_CAN_WRITE );
 	if( !writable ){
-		g_debug( "%s: %s is not writable", thisfn, path );
+		g_debug( "%s: %s is not writable", thisfn, path_or_uri );
 	}
 
 	g_object_unref( info );
diff --git a/src/core/na-data-types.c b/src/core/na-data-types.c
new file mode 100644
index 0000000..d878855
--- /dev/null
+++ b/src/core/na-data-types.c
@@ -0,0 +1,76 @@
+/*
+ * Nautilus Actions
+ * A Nautilus extension which offers configurable context menu actions.
+ *
+ * Copyright (C) 2005 The GNOME Foundation
+ * Copyright (C) 2006, 2007, 2008 Frederic Ruaudel and others (see AUTHORS)
+ * Copyright (C) 2009, 2010 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 <api/na-data-types.h>
+
+typedef struct {
+	guint  type;
+	gchar *gconf_dump_key;
+}
+	FactoryType;
+
+static FactoryType st_factory_type[] = {
+		{ NAFD_TYPE_STRING,        "string" },
+		{ NAFD_TYPE_LOCALE_STRING, "string" },
+		{ NAFD_TYPE_BOOLEAN,       "bool" },
+		{ NAFD_TYPE_STRING_LIST,   "list" },
+		{ NAFD_TYPE_POINTER,        NULL },
+		{ NAFD_TYPE_UINT,          "int" },
+		{ 0 }
+};
+
+/**
+ * na_data_types_get_gconf_dump_key:
+ * @type: the FactoryData type.
+ *
+ * Returns: the GConf key suitable for this type.
+ *
+ * The returned key is owned by FactoryData, and should not be released
+ * by the caller.
+ */
+const gchar *
+na_data_types_get_gconf_dump_key( guint type )
+{
+	FactoryType *str;
+
+	str = st_factory_type;
+	while( str->type ){
+		if( str->type == type ){
+			return( str->gconf_dump_key );
+		}
+		str++;
+	}
+
+	return( NULL );
+}
diff --git a/src/core/na-exporter.c b/src/core/na-exporter.c
index 611171d..99598f8 100644
--- a/src/core/na-exporter.c
+++ b/src/core/na-exporter.c
@@ -99,52 +99,62 @@ na_exporter_free_formats( GList *formats )
 }
 
 /**
- * na_exporter_to_file:
+ * na_exporter_to_buffer:
  * @pivot: the #NAPivot pivot for the running application.
  * @item: a #NAObjectItem-derived object.
- * @folder: the URI of the target folder.
  * @format: the #GQuark target format.
  * @messages: a pointer to a #GSList list of strings; the provider
  *  may append messages to this list, but shouldn't reinitialize it.
  *
- * Exports the specified @item to the target @uri in the required @format.
+ * Exports the specified @item in the required @format.
  *
- * Returns: the URI of the exported file, as a newly allocated string which
- * should be g_free() by the caller, or %NULL if an error has been detected.
+ * Returns: the output buffer, as a newly allocated string which should
+ * be g_free() by the caller, or %NULL if an error has been detected.
  */
 gchar *
-na_exporter_to_file( const NAPivot *pivot, const NAObjectItem *item, const gchar *folder, GQuark format, GSList **messages )
+na_exporter_to_buffer( const NAPivot *pivot, const NAObjectItem *item, GQuark format, GSList **messages )
 {
-	gchar *export_uri;
-	NAIExporterFileParms parms;
+	static const gchar *thisfn = "na_exporter_to_buffer";
+	gchar *buffer;
+	NAIExporterBufferParms parms;
 	NAIExporter *exporter;
-	gchar *msg;
 	gchar *name;
+	gchar *msg;
 
-	export_uri = NULL;
+	g_return_val_if_fail( NA_IS_PIVOT( pivot ), NULL );
+	g_return_val_if_fail( NA_IS_OBJECT_ITEM( item ), NULL );
+
+	g_debug( "%s: pivot=%p, item=%p (%s), format=%u (%s), messages=%p",
+			thisfn,
+			( void * ) pivot,
+			( void * ) item, G_OBJECT_TYPE_NAME( item ),
+			( guint ) format, g_quark_to_string( format ),
+			( void * ) messages );
+
+	buffer = NULL;
 
 	if( iexporter_initialized && !iexporter_finalized ){
 
 		exporter = find_exporter_for_format( pivot, format );
+		g_debug( "%s: exporter=%p (%s)", thisfn, ( void * ) exporter, G_OBJECT_TYPE_NAME( exporter ));
 
 		if( exporter ){
 			parms.version = 1;
 			parms.exported = ( NAObjectItem * ) item;
-			parms.folder = ( gchar * ) folder;
 			parms.format = format;
-			parms.basename = NULL;
-			parms.messages = *messages;
+			parms.buffer = NULL;
+			parms.messages = messages ? *messages : NULL;
 
-			if( NA_IEXPORTER_GET_INTERFACE( exporter )->to_file ){
-				NA_IEXPORTER_GET_INTERFACE( exporter )->to_file( exporter, &parms );
+			if( NA_IEXPORTER_GET_INTERFACE( exporter )->to_buffer ){
+				NA_IEXPORTER_GET_INTERFACE( exporter )->to_buffer( exporter, &parms );
 
-				if( parms.basename ){
-					export_uri = g_strdup_printf( "%s%s%s", folder, G_DIR_SEPARATOR_S, parms.basename );
+				if( parms.buffer ){
+					buffer = parms.buffer;
 				}
 
 			} else {
 				name = exporter_get_name( exporter );
-				msg = g_strdup_printf( _( "NAIExporter %s doesn't implement 'to_file' interface." ), name );
+				msg = g_strdup_printf( _( "NAIExporter %s doesn't implement 'to_buffer' interface." ), name );
 				*messages = g_slist_append( *messages, msg );
 				g_free( name );
 			}
@@ -156,32 +166,45 @@ na_exporter_to_file( const NAPivot *pivot, const NAObjectItem *item, const gchar
 		}
 	}
 
-	return( export_uri );
+	return( buffer );
 }
 
 /**
- * na_exporter_to_buffer:
+ * na_exporter_to_file:
  * @pivot: the #NAPivot pivot for the running application.
  * @item: a #NAObjectItem-derived object.
+ * @folder: the URI of the target folder.
  * @format: the #GQuark target format.
  * @messages: a pointer to a #GSList list of strings; the provider
  *  may append messages to this list, but shouldn't reinitialize it.
  *
- * Exports the specified @item in the required @format.
+ * Exports the specified @item to the target @uri in the required @format.
  *
- * Returns: the output buffer, as a newly allocated string which should
- * be g_free() by the caller, or %NULL if an error has been detected.
+ * Returns: the URI of the exported file, as a newly allocated string which
+ * should be g_free() by the caller, or %NULL if an error has been detected.
  */
 gchar *
-na_exporter_to_buffer( const NAPivot *pivot, const NAObjectItem *item, GQuark format, GSList **messages )
+na_exporter_to_file( const NAPivot *pivot, const NAObjectItem *item, const gchar *folder, GQuark format, GSList **messages )
 {
-	gchar *buffer;
-	NAIExporterBufferParms parms;
+	static const gchar *thisfn = "na_exporter_to_file";
+	gchar *export_uri;
+	NAIExporterFileParms parms;
 	NAIExporter *exporter;
-	gchar *name;
 	gchar *msg;
+	gchar *name;
 
-	buffer = NULL;
+	g_return_val_if_fail( NA_IS_PIVOT( pivot ), NULL );
+	g_return_val_if_fail( NA_IS_OBJECT_ITEM( item ), NULL );
+
+	g_debug( "%s: pivot=%p, item=%p (%s), folder=%s, format=%u (%s), messages=%p",
+			thisfn,
+			( void * ) pivot,
+			( void * ) item, G_OBJECT_TYPE_NAME( item ),
+			folder,
+			( guint ) format, g_quark_to_string( format ),
+			( void * ) messages );
+
+	export_uri = NULL;
 
 	if( iexporter_initialized && !iexporter_finalized ){
 
@@ -190,20 +213,21 @@ na_exporter_to_buffer( const NAPivot *pivot, const NAObjectItem *item, GQuark fo
 		if( exporter ){
 			parms.version = 1;
 			parms.exported = ( NAObjectItem * ) item;
+			parms.folder = ( gchar * ) folder;
 			parms.format = format;
-			parms.buffer = NULL;
-			parms.messages = *messages;
+			parms.basename = NULL;
+			parms.messages = messages ? *messages : NULL;
 
-			if( NA_IEXPORTER_GET_INTERFACE( exporter )->to_buffer ){
-				NA_IEXPORTER_GET_INTERFACE( exporter )->to_buffer( exporter, &parms );
+			if( NA_IEXPORTER_GET_INTERFACE( exporter )->to_file ){
+				NA_IEXPORTER_GET_INTERFACE( exporter )->to_file( exporter, &parms );
 
-				if( parms.buffer ){
-					buffer = parms.buffer;
+				if( parms.basename ){
+					export_uri = g_strdup_printf( "%s%s%s", folder, G_DIR_SEPARATOR_S, parms.basename );
 				}
 
 			} else {
 				name = exporter_get_name( exporter );
-				msg = g_strdup_printf( _( "NAIExporter %s doesn't implement 'to_buffer' interface." ), name );
+				msg = g_strdup_printf( _( "NAIExporter %s doesn't implement 'to_file' interface." ), name );
 				*messages = g_slist_append( *messages, msg );
 				g_free( name );
 			}
@@ -215,7 +239,7 @@ na_exporter_to_buffer( const NAPivot *pivot, const NAObjectItem *item, GQuark fo
 		}
 	}
 
-	return( buffer );
+	return( export_uri );
 }
 
 static const NAIExporterFormat *
diff --git a/src/core/na-exporter.h b/src/core/na-exporter.h
index 2254a18..89ebf42 100644
--- a/src/core/na-exporter.h
+++ b/src/core/na-exporter.h
@@ -46,8 +46,8 @@ G_BEGIN_DECLS
 GList *na_exporter_get_formats ( const NAPivot *pivot );
 void   na_exporter_free_formats( GList *formats );
 
-gchar *na_exporter_to_file  ( const NAPivot *pivot, const NAObjectItem *item, const gchar *uri, GQuark format, GSList **messages );
 gchar *na_exporter_to_buffer( const NAPivot *pivot, const NAObjectItem *item, GQuark format, GSList **messages );
+gchar *na_exporter_to_file  ( const NAPivot *pivot, const NAObjectItem *item, const gchar *uri, GQuark format, GSList **messages );
 
 G_END_DECLS
 
diff --git a/src/core/na-factory-object.c b/src/core/na-factory-object.c
index 6b71572..1fdf15d 100644
--- a/src/core/na-factory-object.c
+++ b/src/core/na-factory-object.c
@@ -82,8 +82,6 @@ typedef struct {
 }
 	NafoDefaultIter;
 
-#define NA_IFACTORY_OBJECT_PROP_DATA				"na-ifactory-object-prop-data"
-
 extern gboolean                   ifactory_object_initialized;
 extern gboolean                   ifactory_object_finalized;
 
@@ -103,7 +101,6 @@ static guint        v_write_start( NAIFactoryObject *serializable, const NAIFact
 static guint        v_write_done( NAIFactoryObject *serializable, const NAIFactoryProvider *reader, void *reader_data, GSList **messages );
 
 static void         attach_boxed_to_object( NAIFactoryObject *object, NADataBoxed *boxed );
-static NADataBoxed *data_boxed_from_name( const NAIFactoryObject *object, const gchar *name );
 static void         free_data_boxed_list( NAIFactoryObject *object );
 static void         iter_on_data_defs( const NADataGroup *idgroups, gboolean serializable_only, NADataDefIterFunc pfn, void *user_data );
 
@@ -291,7 +288,7 @@ set_defaults_iter( NADataDef *def, NafoDefaultIter *data )
 	if( !def->obsoleted ){
 		if( def->default_value ){
 			is_null = TRUE;
-			boxed = data_boxed_from_name( data->object, def->name );
+			boxed = na_ifactory_object_get_data_boxed( data->object, def->name );
 			if( boxed ){
 				is_null = ( na_data_boxed_get_as_void( boxed ) == NULL );
 			}
@@ -370,7 +367,7 @@ na_factory_object_copy( NAIFactoryObject *target, const NAIFactoryObject *source
 		NADataDef *def = na_data_boxed_get_data_def( src_boxed );
 
 		if( def->copyable ){
-			NADataBoxed *tgt_boxed = data_boxed_from_name( target, def->name );
+			NADataBoxed *tgt_boxed = na_ifactory_object_get_data_boxed( target, def->name );
 			if( !tgt_boxed ){
 				tgt_boxed = na_data_boxed_new( def );
 				attach_boxed_to_object( target, tgt_boxed );
@@ -408,7 +405,7 @@ na_factory_object_are_equal( const NAIFactoryObject *a, const NAIFactoryObject *
 		NADataDef *a_def = na_data_boxed_get_data_def( a_boxed );
 		if( a_def->comparable ){
 
-			NADataBoxed *b_boxed = data_boxed_from_name( b, a_def->name );
+			NADataBoxed *b_boxed = na_ifactory_object_get_data_boxed( b, a_def->name );
 			if( b_boxed ){
 				are_equal = na_data_boxed_are_equal( a_boxed, b_boxed );
 				if( !are_equal ){
@@ -428,7 +425,7 @@ na_factory_object_are_equal( const NAIFactoryObject *a, const NAIFactoryObject *
 		NADataDef *b_def = na_data_boxed_get_data_def( b_boxed );
 		if( b_def->comparable ){
 
-			NADataBoxed *a_boxed = data_boxed_from_name( a, b_def->name );
+			NADataBoxed *a_boxed = na_ifactory_object_get_data_boxed( a, b_def->name );
 			if( a_boxed ){
 				are_equal = na_data_boxed_are_equal( a_boxed, b_boxed );
 				if( !are_equal ){
@@ -496,7 +493,7 @@ is_valid_mandatory_iter( const NADataDef *def, NafoValidIter *data )
 	NADataBoxed *boxed;
 
 	if( def->mandatory && !def->obsoleted ){
-		boxed = data_boxed_from_name( data->object, def->name );
+		boxed = na_ifactory_object_get_data_boxed( data->object, def->name );
 		if( !boxed ){
 			g_debug( "na_factory_object_is_valid_mandatory_iter: invalid %s: mandatory but not set", def->name );
 			data->is_valid = FALSE;
@@ -611,7 +608,7 @@ read_data_iter( NADataDef *def, NafoReadIter *iter )
 	NADataBoxed *boxed = na_factory_provider_read_data( iter->reader, iter->reader_data, iter->object, def, iter->messages );
 
 	if( boxed ){
-		NADataBoxed *exist = data_boxed_from_name( iter->object, def->name );
+		NADataBoxed *exist = na_ifactory_object_get_data_boxed( iter->object, def->name );
 
 		if( exist ){
 			na_data_boxed_set_from_boxed( exist, boxed );
@@ -717,7 +714,7 @@ na_factory_object_get_as_value( const NAIFactoryObject *object, const gchar *nam
 
 	g_value_unset( value );
 
-	boxed = data_boxed_from_name( object, name );
+	boxed = na_ifactory_object_get_data_boxed( object, name );
 	if( boxed ){
 		na_data_boxed_get_as_value( boxed, value );
 	}
@@ -745,7 +742,7 @@ na_factory_object_get_as_void( const NAIFactoryObject *object, const gchar *name
 
 	value = NULL;
 
-	boxed = data_boxed_from_name( object, name );
+	boxed = na_ifactory_object_get_data_boxed( object, name );
 	if( boxed ){
 		value = na_data_boxed_get_as_void( boxed );
 	}
@@ -769,7 +766,7 @@ na_factory_object_set_from_value( NAIFactoryObject *object, const gchar *name, c
 
 	g_return_if_fail( NA_IS_IFACTORY_OBJECT( object ));
 
-	NADataBoxed *boxed = data_boxed_from_name( object, name );
+	NADataBoxed *boxed = na_ifactory_object_get_data_boxed( object, name );
 	if( boxed ){
 		na_data_boxed_set_from_value( boxed, value );
 
@@ -801,7 +798,7 @@ na_factory_object_set_from_void( NAIFactoryObject *object, const gchar *name, co
 
 	g_return_if_fail( NA_IS_IFACTORY_OBJECT( object ));
 
-	NADataBoxed *boxed = data_boxed_from_name( object, name );
+	NADataBoxed *boxed = na_ifactory_object_get_data_boxed( object, name );
 	if( boxed ){
 		na_data_boxed_set_from_void( boxed, data );
 
@@ -916,26 +913,6 @@ attach_boxed_to_object( NAIFactoryObject *object, NADataBoxed *boxed )
 	g_object_set_data( G_OBJECT( object ), NA_IFACTORY_OBJECT_PROP_DATA, list );
 }
 
-static NADataBoxed *
-data_boxed_from_name( const NAIFactoryObject *object, const gchar *name )
-{
-	GList *list, *ip;
-
-	list = g_object_get_data( G_OBJECT( object ), NA_IFACTORY_OBJECT_PROP_DATA );
-	/*g_debug( "list=%p (count=%u)", ( void * ) list, g_list_length( list ));*/
-
-	for( ip = list ; ip ; ip = ip->next ){
-		NADataBoxed *boxed = NA_DATA_BOXED( ip->data );
-		NADataDef *def = na_data_boxed_get_data_def( boxed );
-
-		if( !strcmp( def->name, name )){
-			return( boxed );
-		}
-	}
-
-	return( NULL );
-}
-
 static void
 free_data_boxed_list( NAIFactoryObject *object )
 {
diff --git a/src/core/na-factory-object.h b/src/core/na-factory-object.h
index 20bd2e6..119cd59 100644
--- a/src/core/na-factory-object.h
+++ b/src/core/na-factory-object.h
@@ -46,6 +46,8 @@ G_BEGIN_DECLS
 
 typedef gboolean ( *NAFactoryObjectIterBoxedFn )( const NAIFactoryObject *object, NADataBoxed *boxed, void *data );
 
+#define NA_IFACTORY_OBJECT_PROP_DATA			"na-ifactory-object-prop-data"
+
 void         na_factory_object_define_properties( GObjectClass *class, const NADataGroup *groups );
 NADataDef   *na_factory_object_get_data_def     ( const NAIFactoryObject *object, const gchar *name );
 NADataGroup *na_factory_object_get_data_groups  ( const NAIFactoryObject *object );
diff --git a/src/core/na-ifactory-object.c b/src/core/na-ifactory-object.c
index 90b406a..9345065 100644
--- a/src/core/na-ifactory-object.c
+++ b/src/core/na-ifactory-object.c
@@ -236,6 +236,42 @@ na_ifactory_object_get_data_def_from_gconf_key( const NAIFactoryObject *object,
 #endif
 
 /**
+ * na_ifactory_object_get_data_boxed:
+ * @object: a #NAIFactoryObject object.
+ * @name: the name of the elementary data we are searching for.
+ *
+ * Returns: The #NADataBoxed object which contains the specified data,
+ * or %NULL.
+ *
+ * The returned #NADataBoxed is owned by #NAIFactoryObject @object, and
+ * should not be released by the caller.
+ */
+NADataBoxed *
+na_ifactory_object_get_data_boxed( const NAIFactoryObject *object, const gchar *name )
+{
+	GList *list, *ip;
+
+	g_return_val_if_fail( NA_IS_IFACTORY_OBJECT( object ), NULL );
+
+	if( ifactory_object_initialized && !ifactory_object_finalized ){
+
+		list = g_object_get_data( G_OBJECT( object ), NA_IFACTORY_OBJECT_PROP_DATA );
+		/*g_debug( "list=%p (count=%u)", ( void * ) list, g_list_length( list ));*/
+
+		for( ip = list ; ip ; ip = ip->next ){
+			NADataBoxed *boxed = NA_DATA_BOXED( ip->data );
+			NADataDef *def = na_data_boxed_get_data_def( boxed );
+
+			if( !strcmp( def->name, name )){
+				return( boxed );
+			}
+		}
+	}
+
+	return( NULL );
+}
+
+/**
  * na_ifactory_object_get_as_void:
  * @object: this #NAIFactoryObject instance.
  * @name: the elementary data whose value is to be got.
diff --git a/src/core/na-object-action-factory.c b/src/core/na-object-action-factory.c
index a2e1e13..72493c2 100644
--- a/src/core/na-object-action-factory.c
+++ b/src/core/na-object-action-factory.c
@@ -32,6 +32,8 @@
 #include <config.h>
 #endif
 
+#include <glib/gi18n.h>
+
 #include <api/na-ifactory-object-data.h>
 #include <api/na-data-def.h>
 #include <api/na-data-types.h>
@@ -43,8 +45,9 @@ static NADataDef data_def_action [] = {
 
 	{ NAFO_DATA_VERSION,
 				TRUE,
-				"Action version",
-				"Version of the action",
+				N_( "Version of the format" ),
+				N_( "The version of the configuration format that will be used to manage " \
+					"backward compatibility." ),
 				NAFD_TYPE_STRING,
 				"2.0",
 				TRUE,
@@ -56,8 +59,10 @@ static NADataDef data_def_action [] = {
 
 	{ NAFO_DATA_TARGET_SELECTION,
 				TRUE,
-				"Target a selection context menu",
-				"Does the action target the context menu when there is some selection ?",
+				N_( "Targets the context menu" ),
+				N_( "Whether the action of the menu targets the selection file manager " \
+					"context menus.\n" \
+					"This used to be the historical behavior."),
 				NAFD_TYPE_BOOLEAN,
 				"true",
 				TRUE,
@@ -82,10 +87,9 @@ static NADataDef data_def_action [] = {
 
 	{ NAFO_DATA_TARGET_TOOLBAR,
 				TRUE,
-				"Target the toolbar",
-				"Does the action target the toolbar ? " \
-				"Only an action may target the toolbar as Nautilus, as of 2.28, " \
-				"doesn't support menus in toolbar.",
+				N_( "Targets the toolbar" ),
+				N_( "Whether the action is candidate to be displayed in file manager toolbar.\n" \
+					"Note, that as of Nautilus 2.26, menus can not be candidate to toolbar display." ),
 				NAFD_TYPE_BOOLEAN,
 				"false",
 				TRUE,
@@ -97,9 +101,10 @@ static NADataDef data_def_action [] = {
 
 	{ NAFO_DATA_TOOLBAR_LABEL,
 				TRUE,
-				"Toolbar label",
-				"Label of the action in the toolbar. " \
-				"Defaults to main label if empty or not set.",
+				N_( "Label of the toolbar item" ),
+				N_( "The label displayed besides of the icon in the file manager toolbar.\n" \
+					"Note that actual display may depend of your own Desktop Environment preferences.\n" \
+					"Defaults to label of the context menu when not set or empty."),
 				NAFD_TYPE_LOCALE_STRING,
 				"",
 				TRUE,
diff --git a/src/core/na-object-action.c b/src/core/na-object-action.c
index 86aa3b7..9dfabb9 100644
--- a/src/core/na-object-action.c
+++ b/src/core/na-object-action.c
@@ -84,6 +84,7 @@ static guint        ifactory_object_get_version( const NAIFactoryObject *instanc
 static NADataGroup *ifactory_object_get_groups( const NAIFactoryObject *instance );
 static gboolean     ifactory_object_are_equal( const NAIFactoryObject *a, const NAIFactoryObject *b );
 static gboolean     ifactory_object_is_valid( const NAIFactoryObject *object );
+static void         ifactory_object_read_start( NAIFactoryObject *instance, const NAIFactoryProvider *reader, void *reader_data, GSList **messages );
 static void         ifactory_object_read_done( NAIFactoryObject *instance, const NAIFactoryProvider *reader, void *reader_data, GSList **messages );
 static guint        ifactory_object_write_start( NAIFactoryObject *instance, const NAIFactoryProvider *writer, void *writer_data, GSList **messages );
 static guint        ifactory_object_write_done( NAIFactoryObject *instance, const NAIFactoryProvider *writer, void *writer_data, GSList **messages );
@@ -284,7 +285,7 @@ ifactory_object_iface_init( NAIFactoryObjectInterface *iface )
 	iface->copy = NULL;
 	iface->are_equal = ifactory_object_are_equal;
 	iface->is_valid = ifactory_object_is_valid;
-	iface->read_start = NULL;
+	iface->read_start = ifactory_object_read_start;
 	iface->read_done = ifactory_object_read_done;
 	iface->write_start = ifactory_object_write_start;
 	iface->write_done = ifactory_object_write_done;
@@ -317,6 +318,14 @@ ifactory_object_is_valid( const NAIFactoryObject *object )
 }
 
 static void
+ifactory_object_read_start( NAIFactoryObject *instance, const NAIFactoryProvider *reader, void *reader_data, GSList **messages )
+{
+	/* create the 'type' data box to be available later when writing/exporting
+	 */
+	na_ifactory_object_set_from_void( instance, NAFO_DATA_TYPE, ( void * ) "Action" );
+}
+
+static void
 ifactory_object_read_done( NAIFactoryObject *instance, const NAIFactoryProvider *reader, void *reader_data, GSList **messages )
 {
 	IterForObsoletedParms parms;
diff --git a/src/core/na-object-item-factory.c b/src/core/na-object-item-factory.c
index 0f7deb3..8cdd5ed 100644
--- a/src/core/na-object-item-factory.c
+++ b/src/core/na-object-item-factory.c
@@ -32,17 +32,40 @@
 #include <config.h>
 #endif
 
+#include <glib/gi18n.h>
+
 #include <api/na-ifactory-object-data.h>
 #include <api/na-data-def.h>
 #include <api/na-data-types.h>
 
 NADataDef data_def_item [] = {
 
+	/* this data is marked as 'non-serializable'
+	 * this means it will not be automatically readen/written or imported/exported
+	 * the corresponding NADataBoxed is created at read_start() time
+	 */
+	{ NAFO_DATA_TYPE,
+				FALSE,
+				N_( "Type of the item" ),
+				N_( "Defines if the item is an action or a menu. Possible values are :\n" \
+					"- 'Action',\n" \
+					"- 'Menu'.\n" \
+					"The value is case sensitive and must not be localized." ),
+				NAFD_TYPE_LOCALE_STRING,
+				NULL,
+				TRUE,
+				FALSE,
+				FALSE,
+				FALSE,
+				"type",
+				FALSE },
+
 	{ NAFO_DATA_LABEL,
 				TRUE,
-				"NAObjectItem label",
-				"Main label of the NAObjectItem object. " \
-				"Serves as a default for the toolbar label of an action.",
+				N_( "Label of the context menu item" ),
+				N_( "The label of the menu item that will appear in the file manager context " \
+					"menu when the selection matches the appearance condition settings.\n" \
+					"It is also used as a default for the toolbar label of an action." ),
 				NAFD_TYPE_LOCALE_STRING,
 				"",
 				TRUE,
@@ -54,8 +77,10 @@ NADataDef data_def_item [] = {
 
 	{ NAFO_DATA_TOOLTIP,
 				TRUE,
-				"Item tooltip",
-				"Tooltip associated to the item in the context menu or in the toolbar.",
+				N_( "Tooltip of the context menu item" ),
+				N_( "The tooltip of the menu item that will appear in the file manager " \
+					"statusbar when the user points to the file manager context menu item " \
+					"with his/her mouse." ),
 				NAFD_TYPE_LOCALE_STRING,
 				"",
 				TRUE,
@@ -67,9 +92,11 @@ NADataDef data_def_item [] = {
 
 	{ NAFO_DATA_ICON,
 				TRUE,
-				"Icon name",
-				"Icon displayed in the context menu and in the toolbar. " \
-				"May be the name of a themed icon, or the full path to any appropriate image.",
+				N_( "Icon of the context menu item" ),
+				N_( "The icon of the menu item that will appear next to the label " \
+					"in the file manager context menu when the selection matches the appearance " \
+					"conditions settings.\n" \
+					"May be the localized name of a themed icon, or a full path to any appropriate image." ),
 				NAFD_TYPE_LOCALE_STRING,
 				"",
 				TRUE,
@@ -81,9 +108,9 @@ NADataDef data_def_item [] = {
 
 	{ NAFO_DATA_DESCRIPTION,
 				TRUE,
-				"Description",
-				"Some text which explains the goal of the menu or the action. " \
-				"Will be used, e.g. when displaying available items on a web site.",
+				N_( "Description relative to the item" ),
+				N_( "Some text which explains the goal of the menu or the action.\n" \
+					"May be used, e.g. when displaying available items on a web site." ),
 				NAFD_TYPE_LOCALE_STRING,
 				"",
 				TRUE,
@@ -108,9 +135,11 @@ NADataDef data_def_item [] = {
 
 	{ NAFO_DATA_SUBITEMS_SLIST,
 				TRUE,
-				"Subitems",
-				"List of subitems ids, " \
-				"as readen from corresponding entry from the storage subsystem.",
+				N_( "List of subitem ids" ),
+				N_( "Ordered list of the IDs of the subitems. This may be actions or menus " \
+					"if the item is a menu, or profiles if the item is an action.\n" \
+					"If this list doesn't exist or is empty for an action or a menu, " \
+					"subitems are attached in the order of the read operations." ),
 				NAFD_TYPE_STRING_LIST,
 				NULL,
 				FALSE,
@@ -122,10 +151,9 @@ NADataDef data_def_item [] = {
 
 	{ NAFO_DATA_ENABLED,
 				TRUE,
-				"Enabled",
-				"Is the item enabled ? " \
-				"When FALSE, the item will never be candidate to the context menu," \
-				"nor to the toolbar.",
+				N_( "Whether the action or the menu is enabled" ),
+				N_( "If the or the menu action is disabled, it will never appear in the " \
+					"file manager context menu." ),
 				NAFD_TYPE_BOOLEAN,
 				"true",
 				TRUE,
diff --git a/src/core/na-object-menu.c b/src/core/na-object-menu.c
index 2f8f689..cea372e 100644
--- a/src/core/na-object-menu.c
+++ b/src/core/na-object-menu.c
@@ -77,6 +77,7 @@ static guint        ifactory_object_get_version( const NAIFactoryObject *instanc
 static NADataGroup *ifactory_object_get_groups( const NAIFactoryObject *instance );
 static gboolean     ifactory_object_are_equal( const NAIFactoryObject *a, const NAIFactoryObject *b );
 static gboolean     ifactory_object_is_valid( const NAIFactoryObject *object );
+static void         ifactory_object_read_start( NAIFactoryObject *instance, const NAIFactoryProvider *reader, void *reader_data, GSList **messages );
 static void         ifactory_object_read_done( NAIFactoryObject *instance, const NAIFactoryProvider *reader, void *reader_data, GSList **messages );
 static guint        ifactory_object_write_start( NAIFactoryObject *instance, const NAIFactoryProvider *writer, void *writer_data, GSList **messages );
 static guint        ifactory_object_write_done( NAIFactoryObject *instance, const NAIFactoryProvider *writer, void *writer_data, GSList **messages );
@@ -274,7 +275,7 @@ ifactory_object_iface_init( NAIFactoryObjectInterface *iface )
 	iface->copy = NULL;
 	iface->are_equal = ifactory_object_are_equal;
 	iface->is_valid = ifactory_object_is_valid;
-	iface->read_start = NULL;
+	iface->read_start = ifactory_object_read_start;
 	iface->read_done = ifactory_object_read_done;
 	iface->write_start = ifactory_object_write_start;
 	iface->write_done = ifactory_object_write_done;
@@ -307,6 +308,14 @@ ifactory_object_is_valid( const NAIFactoryObject *object )
 }
 
 static void
+ifactory_object_read_start( NAIFactoryObject *instance, const NAIFactoryProvider *reader, void *reader_data, GSList **messages )
+{
+	/* create the 'type' data box to be available later when writing/exporting
+	 */
+	na_ifactory_object_set_from_void( instance, NAFO_DATA_TYPE, ( void * ) "Menu" );
+}
+
+static void
 ifactory_object_read_done( NAIFactoryObject *instance, const NAIFactoryProvider *reader, void *reader_data, GSList **messages )
 {
 	na_factory_object_set_defaults( instance );
diff --git a/src/core/na-object-profile-factory.c b/src/core/na-object-profile-factory.c
index fc845f1..6183105 100644
--- a/src/core/na-object-profile-factory.c
+++ b/src/core/na-object-profile-factory.c
@@ -32,6 +32,8 @@
 #include <config.h>
 #endif
 
+#include <glib/gi18n.h>
+
 #include <api/na-ifactory-object-data.h>
 #include <api/na-data-def.h>
 #include <api/na-data-types.h>
@@ -42,9 +44,9 @@ static NADataDef data_def_profile [] = {
 
 	{ NAFO_DATA_DESCNAME,
 				TRUE,
-				"NAObjectProfile label",
-				"Main label of the NAObjectProfile profile. " \
-				"May be used as a description for the function of the profile.",
+				N_( "Name of the profile" ),
+				N_( "May be used as a description for the function of the profile.\n" \
+					"If not set, it defaults to an auto-generated name." ),
 				NAFD_TYPE_LOCALE_STRING,
 				"",
 				TRUE,
@@ -56,8 +58,9 @@ static NADataDef data_def_profile [] = {
 
 	{ NAFO_DATA_PATH,
 				TRUE,
-				"Command path",
-				"The path to the command.",
+				N_( "Path of the command" ),
+				N_( "The path of the command to be executed when the user select the menu item " \
+					"in the file manager context menu or in the toolbar." ),
 				NAFD_TYPE_STRING,
 				"",
 				TRUE,
@@ -69,8 +72,23 @@ static NADataDef data_def_profile [] = {
 
 	{ NAFO_DATA_PARAMETERS,
 				TRUE,
-				"Command parameters",
-				"The parameters of the command.",
+				N_( "Parameters of the command" ),
+										/* too long string for iso c: 665 (max=509) */
+				N_( "The parameters of the command to be executed when the user selects the menu " \
+					"item in the file manager context menu or in the toolbar.\n" \
+					"The parameters may contain some special tokens which are replaced by the " \
+					"informations provided by the file manager before starting the command:\n" \
+					"%d: base folder of the selected file(s)\n" \
+					"%f: the name of the selected file or the first one if several are selected\n" \
+					"%h: hostname of the URI\n" \
+					"%m: space-separated list of the basenames of the selected file(s)/folder(s)\n" \
+					"%M: space-separated list of the selected file(s)/folder(s), with their full paths\n" \
+					"%p: port number of the first URI\n" \
+					"%R: space-separated list of selected URIs\n" \
+					"%s: scheme of the URI\n" \
+					"%u: URI\n" \
+					"%U: username of the URI\n" \
+					"%%: a percent sign." ),
 				NAFD_TYPE_STRING,
 				"",
 				TRUE,
@@ -82,9 +100,13 @@ static NADataDef data_def_profile [] = {
 
 	{ NAFO_DATA_BASENAMES,
 				TRUE,
-				"Basenames",
-				"The basenames the selection must match. " \
-				"Defaults to '*'.",
+				N_( "List of pattern to match the selected file(s)/folder(s)" ),
+				N_( "A list of strings with joker '*' or '?' to be matched against the name(s) " \
+					"of the selected file(s)/folder(s). Each selected items must match at least " \
+					"one of the filename patterns for the action or the menu be candidate to " \
+					"display.\n" \
+					"This obviously only applies when there is a selection.\n" \
+					"Defaults to '*'." ),
 				NAFD_TYPE_STRING_LIST,
 				"*",
 				TRUE,
@@ -96,9 +118,13 @@ static NADataDef data_def_profile [] = {
 
 	{ NAFO_DATA_MATCHCASE,
 				TRUE,
-				"Case sensitive",
-				"Whether the specified basenames are case sensitive." \
-				"Defaults to 'true'.",
+				N_( "Whether the specified basenames are case sensitive" ),
+				N_( "Must be set to 'true' if the filename patterns are case sensitive, to 'false' " \
+					"otherwise. E.g., if you need to match a filename in a case-sensitive manner, " \
+					"set this key to 'true'. If you also want, for example '*.jpg' to match 'photo.JPG', " \
+					"then set 'false'.\n" \
+					"This obviously only applies when there is a selection.\n" \
+					"Defaults to 'true'." ),
 				NAFD_TYPE_BOOLEAN,
 				"true",
 				TRUE,
@@ -110,9 +136,12 @@ static NADataDef data_def_profile [] = {
 
 	{ NAFO_DATA_MIMETYPES,
 				TRUE,
-				"Mimetypes",
-				"The mimetypes the selection must match." \
-				"Defaults to '*'.",
+				N_( "List of patterns to match the mimetypes of the selected file(s)/folder(s)" ),
+				N_( "A list of strings with joker '*' to be matched against the mimetypes of the " \
+					"selected file(s)/folder(s). Each selected items must match at least one of " \
+					"the mimetype patterns for the action to appear.\n" \
+					"This obviously only applies when there is a selection.\n" \
+					"Defaults to '*/*'." ),
 				NAFD_TYPE_STRING_LIST,
 				"*",
 				TRUE,
@@ -124,9 +153,16 @@ static NADataDef data_def_profile [] = {
 
 	{ NAFO_DATA_ISFILE,
 				TRUE,
-				"Applies to files only",
-				"Whether the profile only applies to files." \
-				"Defaults to 'true'",
+				N_( "Whether the profile applies to files" ),
+				N_( "Set to 'true' if the selection can have files, to 'false' otherwise.\n" \
+					"This setting is tied in with the 'isdir' setting. The valid combinations are: \n" \
+					"isfile=TRUE and isdir=FALSE: the selection may hold only files\n" \
+					"isfile=FALSE and isdir=TRUE: the selection may hold only folders\n" \
+					"isfile=TRUE and isdir=TRUE: the selection may hold both files and folders\n" \
+					"isfile=FALSE and isdir=FALSE: this is an invalid combination " \
+					"(your configuration will never appear).\n" \
+					"This obviously only applies when there is a selection.\n" \
+					"Defaults to 'true'." ),
 				NAFD_TYPE_BOOLEAN,
 				"true",
 				TRUE,
@@ -138,9 +174,16 @@ static NADataDef data_def_profile [] = {
 
 	{ NAFO_DATA_ISDIR,
 				TRUE,
-				"Applies to directories only",
-				"Whether the profile applies to directories only." \
-				"Defaults to 'false'",
+				N_( "Whether the profile applies to folders" ),
+				N_( "Set to 'true' if the selection can have folders, to 'false' otherwise.\n" \
+					"This setting is tied in with the 'isfile' setting. The valid combinations are: \n" \
+					"isfile=TRUE and isdir=FALSE: the selection may hold only files\n" \
+					"isfile=FALSE and isdir=TRUE: the selection may hold only folders\n" \
+					"isfile=TRUE and isdir=TRUE: the selection may hold both files and folders\n" \
+					"isfile=FALSE and isdir=FALSE: this is an invalid combination " \
+					"(your configuration will never appear).\n" \
+					"This obviously only applies when there is a selection.\n" \
+					"Defaults to 'false'." ),
 				NAFD_TYPE_BOOLEAN,
 				"false",
 				TRUE,
@@ -152,9 +195,11 @@ static NADataDef data_def_profile [] = {
 
 	{ NAFO_DATA_MULTIPLE,
 				TRUE,
-				"Multiple selection",
-				"Whether the selection may be multiple." \
-				"Defaults to 'false'.",
+				N_( "Whether the selection may be multiple" ),
+				N_( "If you need more than one files or folders to be selected, set this " \
+					"key to 'true'. If you want just one file or folder, set it to 'false'.\n" \
+					"This obviously only applies when there is a selection.\n" \
+					"Defaults to 'false'." ),
 				NAFD_TYPE_BOOLEAN,
 				"false",
 				TRUE,
@@ -166,9 +211,23 @@ static NADataDef data_def_profile [] = {
 
 	{ NAFO_DATA_SCHEMES,
 				TRUE,
-				"Schemes",
-				"The list of schemes the selection must match." \
-				"Defaults to 'file'.",
+				N_( "List of schemes" ),
+										/* too long string for iso c: 510 (max=509) */
+				N_( "Defines the list of valid schemes to be matched against the selected " \
+					"items. The scheme is the protocol used to access the files. The " \
+					"keyword to use is the one used in the URI by the file manager.\n" \
+					"Examples of valid URI include:\n" \
+					"- file:///tmp/foo.txt\n" \
+					"- sftp:///root test example net/tmp/foo.txt\n" \
+					"The most common schemes are:\n" \
+					"'file': local files\n" \
+					"'sftp': files accessed via SSH\n" \
+					"'ftp': files accessed via FTP\n" \
+					"'smb': files accessed via Samba (Windows share)\n" \
+					"'dav': files accessed via WebDAV.\n" \
+					"All schemes used by your favorite file manager may be used here.\n" \
+					"This obviously only applies when there is a selection.\n" \
+					"Defaults to 'file'." ),
 				NAFD_TYPE_STRING_LIST,
 				"file",
 				TRUE,
@@ -180,9 +239,11 @@ static NADataDef data_def_profile [] = {
 
 	{ NAFO_DATA_FOLDERS,
 				TRUE,
-				"Folders",
-				"The list of folders which apply when there is no selection." \
-				"Defaults to '/'.",
+				N_( "List of folders" ),
+				N_( "Defines the list of valid paths to be matched against the current folder.\n " \
+					"All folders 'under' the specified path are considered valid.\n" \
+					"This is only used when there is no selection.\n" \
+					"Defaults to '/'." ),
 				NAFD_TYPE_STRING_LIST,
 				"/",
 				TRUE,
diff --git a/src/io-gconf/nagp-keys.h b/src/io-gconf/nagp-keys.h
index 4ff9ba5..6eafb0b 100644
--- a/src/io-gconf/nagp-keys.h
+++ b/src/io-gconf/nagp-keys.h
@@ -32,7 +32,7 @@
 #define __NAGP_GCONF_PROVIDER_KEYS_H__
 
 #define NAGP_CONFIGURATIONS_PATH		"/apps/nautilus-actions/configurations"
-#define NAGP_SCHEMAS_PATH				"/schemas/apps/nautilus-actions"
+#define NAGP_SCHEMAS_PATH				"/schemas/apps/nautilus-actions/configurations"
 
 #define NAGP_ENTRY_TYPE					"type"
 #define NAGP_VALUE_TYPE_MENU			"Menu"
diff --git a/src/io-xml/Makefile.am b/src/io-xml/Makefile.am
index fbeb150..d309a06 100644
--- a/src/io-xml/Makefile.am
+++ b/src/io-xml/Makefile.am
@@ -41,13 +41,14 @@ libna_io_xml_la_SOURCES = \
 	naxml-provider.h									\
 	naxml-keys.c										\
 	naxml-keys.h										\
+	naxml-formats.c										\
+	naxml-formats.h										\
 	naxml-reader.c										\
 	naxml-reader.h										\
+	naxml-writer.c										\
+	naxml-writer.h										\
 	$(NULL)
 
-#na-xml-writer.c										
-#na-xml-writer.h										
-
 libna_io_xml_la_LIBADD = \
 	$(top_builddir)/src/core/libna-core.la				\
 	$(NULL)
diff --git a/src/io-xml/naxml-formats.c b/src/io-xml/naxml-formats.c
new file mode 100644
index 0000000..493315b
--- /dev/null
+++ b/src/io-xml/naxml-formats.c
@@ -0,0 +1,77 @@
+/*
+ * Nautilus Actions
+ * A Nautilus extension which offers configurable context menu actions.
+ *
+ * Copyright (C) 2005 The GNOME Foundation
+ * Copyright (C) 2006, 2007, 2008 Frederic Ruaudel and others (see AUTHORS)
+ * Copyright (C) 2009, 2010 Pierre Wieser and others (see AUTHORS)
+ *
+ * This Program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this Library; see the file COPYING.  If not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place,
+ * Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Authors:
+ *   Frederic Ruaudel <grumz grumz net>
+ *   Rodrigo Moya <rodrigo gnome-db org>
+ *   Pierre Wieser <pwieser trychlos org>
+ *   ... and many others (see AUTHORS)
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <glib/gi18n.h>
+
+#include <api/na-iexporter.h>
+
+#include "naxml-formats.h"
+
+NAIExporterFormat naxml_formats[] = {
+
+	/* GCONF_SCHEMA_V1: a schema with owner, short and long descriptions;
+	 * each action has its own schema addressed by the id
+	 * (historical format up to v1.10.x serie)
+	 */
+	{ NAXML_FORMAT_GCONF_SCHEMA_V1,
+			N_( "Export as a full GConf schema (v_1) file" ),
+			N_( "Export as a GConf schema file with full key descriptions" ),
+			N_( "This used to be the historical export format. " \
+				"The exported file may later be imported via :\n" \
+				"- Import assistant of the Nautilus Actions Configuration Tool,\n" \
+				"- or via the gconftool-2 --import-schema-file command-line tool." ) },
+
+	/* GCONF_SCHEMA_V2: the lightest schema still compatible with gconftool-2 --install-schema-file
+	 * (no owner, no short nor long descriptions) - introduced in v 1.11
+	 */
+	{ NAXML_FORMAT_GCONF_SCHEMA_V2,
+			N_( "Export as a light GConf _schema (v2) file" ),
+			N_( "Export as a light GConf schema file" ),
+			N_( "The exported file may later be imported via :\n" \
+				"- Import assistant of the Nautilus Actions Configuration Tool,\n" \
+				"- or via the gconftool-2 --import-schema-file command-line tool." ) },
+
+	/* GCONF_ENTRY: not a schema, but a dump of the GConf entry
+	 * introduced in v 1.11
+	 */
+	{ NAXML_FORMAT_GCONF_ENTRY,
+			N_( "Export as a GConf _entry file" ),
+			N_( "Export as a GConf entry file" ),
+			N_( "This should be the preferred format for newly exported actions.\n" \
+				"The exported file may later be imported via :\n" \
+				"- Import assistant of the Nautilus Actions Configuration Tool,\n" \
+				"- or via the gconftool-2 --load command-line tool." ) },
+
+	{ NULL, NULL, NULL }
+};
diff --git a/src/io-xml/naxml-formats.h b/src/io-xml/naxml-formats.h
new file mode 100644
index 0000000..1bb1342
--- /dev/null
+++ b/src/io-xml/naxml-formats.h
@@ -0,0 +1,42 @@
+/*
+ * 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, 2010 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 __NAXML_FORMATS_H__
+#define __NAXML_FORMATS_H__
+
+G_BEGIN_DECLS
+
+#define NAXML_FORMAT_GCONF_SCHEMA_V1			"GConfSchemaV1"
+#define NAXML_FORMAT_GCONF_SCHEMA_V2			"GConfSchemaV2"
+#define NAXML_FORMAT_GCONF_ENTRY				"GConfEntry"
+
+G_END_DECLS
+
+#endif /* __NAXML_FORMATS_H__ */
diff --git a/src/io-xml/naxml-keys.h b/src/io-xml/naxml-keys.h
index 8fbffa8..e67fbcc 100644
--- a/src/io-xml/naxml-keys.h
+++ b/src/io-xml/naxml-keys.h
@@ -31,8 +31,6 @@
 #ifndef __NAXML_KEYS_H__
 #define __NAXML_KEYS_H__
 
-#include <glib/gi18n.h>
-
 #include <api/na-data-def.h>
 
 G_BEGIN_DECLS
@@ -91,116 +89,6 @@ typedef struct {
 #define NAXML_KEY_DUMP_NODE_VALUE_LIST				"list"
 #define NAXML_KEY_DUMP_NODE_VALUE_LIST_PARM_TYPE	"type"
 
-/* GConf schema descriptions
- */
-#define ACTION_LABEL_DESC_SHORT		_( "The label of the menu item" )
-#define ACTION_LABEL_DESC_LONG		_( "The label of the menu item that will appear in the Nautilus popup " \
-										"menu when the selection matches the appearance condition settings." )
-#define ACTION_TOOLTIP_DESC_SHORT	_( "The tooltip of the menu item" )
-#define ACTION_TOOLTIP_DESC_LONG	_( "The tooltip of the menu item that will appear in the Nautilus " \
-										"statusbar when the user points to the Nautilus popup menu item "\
-										"with his/her mouse." )
-#define ACTION_ICON_DESC_SHORT		_( "The icon of the menu item" )
-#define ACTION_ICON_DESC_LONG		_( "The icon of the menu item that will appear next to the label " \
-										"in the Nautilus popup menu when the selection matches the appearance " \
-										"conditions settings." )
-#define ACTION_ENABLED_DESC_SHORT	_( "Whether the action is enabled" )
-#define ACTION_ENABLED_DESC_LONG	_( "If the action is disabled, it will never appear in the Nautilus " \
-										"context menu." )
-#define ACTION_ITEMS_DESC_SHORT		_( "List of subitem ids" )
-#define ACTION_ITEMS_DESC_LONG		_( "Ordered list of the IDs of the subitems. This may be actions or menus " \
-										"if the item is a menu, or profiles if the item is an action.\nIf this " \
-										"list doesn't exist or is empty for an action, we load the found profiles " \
-										"in the order of the read operations." )
-#define ACTION_TYPE_DESC_SHORT		_( "Type of the item" )
-#define ACTION_TYPE_DESC_LONG		_( "Defines if the item is an action or a menu. Possible values are :\n" \
-										"- \"Action\",\n- \"Menu\".\nThe value is case sensitive and must " \
-										"not be localized." )
-#define ACTION_TARGET_SELECTION_DESC_SHORT		_( "Targets selection" )
-#define ACTION_TARGET_SELECTION_DESC_LONG		_( "Whether the action of menu targets the selection Nautilus " \
-													"menus. This is the historical behavior." )
-#define ACTION_TARGET_BACKGROUND_DESC_SHORT		_( "Targets background" )
-#define ACTION_TARGET_BACKGROUND_DESC_LONG		_( "Whether the action of menu targets the background Nautilus menus." )
-#define ACTION_TARGET_TOOLBAR_DESC_SHORT		_( "Targets toolbar" )
-#define ACTION_TARGET_TOOLBAR_DESC_LONG			_( "Whether the action is candidate to be displayed in Nautilus " \
-													"toolbar.\nNote, that as of Nautilus -2.26, menus can not be " \
-													"candidate to toolbar display." )
-#define ACTION_TOOLBAR_SAME_LABEL_DESC_SHORT	_( "Whether the labels are the sames" )
-#define ACTION_TOOLBAR_SAME_LABEL_DESC_LONG		_( "Whether the label displayed in the Nautilus toolbar " \
-													"besides of the icon is the same that the main item label." )
-#define ACTION_TOOLBAR_LABEL_DESC_SHORT			_( "Label of the item in the toolbar" )
-#define ACTION_TOOLBAR_LABEL_DESC_LONG			_( "The label displayed besides of the icon in the Nautilus " \
-													"toolbar.\nNote that actual display may depend of your " \
-													"own Gnome preferences." )
-#define ACTION_PROFILE_NAME_DESC_SHORT _( "A description name of the profile" )
-#define ACTION_PROFILE_NAME_DESC_LONG  _( "The field is here to give the user a human readable name for a " \
-										"profile in the NACT interface. If not set there will be a default " \
-										"auto generated string set." )
-#define ACTION_PATH_DESC_SHORT		_( "The path of the command" )
-#define ACTION_PATH_DESC_LONG		_( "The path of the command to start when the user select the menu item " \
-										"in the Nautilus popup menu." )
-#define ACTION_PARAMETERS_DESC_SHORT _( "The parameters of the command" )
-/* too long string for iso c: 665 (max=509) */
-#define ACTION_PARAMETERS_DESC_LONG	_( "The parameters of the command to start when the user selects the menu " \
-										"item in the Nautilus popup menu.\n\nThe parameters can contain some " \
-										"special tokens which are replaced by Nautilus information before starting " \
-										"the command:\n\n%d: base folder of the selected file(s)\n%f: the name of " \
-										"the selected file or the first one if many are selected\n%h: hostname of " \
-										"the URI\n%m: space-separated list of the basenames of the selected " \
-										"file(s)/folder(s)\n%M: space-separated list of the selected file(s)/folder(s), " \
-										"with their full paths\n%p: port number of the first URI\n%R: space-separated " \
-										"list of selected URIs\n%s: scheme of the URI\n%u: URI\n%U: username of the " \
-										"URI\n%%: a percent sign." )
-#define ACTION_BASENAMES_DESC_SHORT	_( "The list of pattern to match the selected file(s)/folder(s)" )
-#define ACTION_BASENAMES_DESC_LONG	_( "A list of strings with joker '*' or '?' to match the name of the selected " \
-										"file(s)/folder(s). Each selected items must match at least one of the " \
-										"filename patterns for the action to appear. " \
-										"This only applies when targeting selection." )
-#define ACTION_MATCHCASE_DESC_SHORT _( "'true' if the filename patterns have to be case sensitive, 'false' otherwise" )
-#define ACTION_MATCHCASE_DESC_LONG	_( "If you need to match a filename in a case-sensitive manner, set this key to " \
-										"'true'. If you also want, for example '*.jpg' to match 'photo.JPG', " \
-										"set 'false'. This only applies when targeting selection." )
-#define ACTION_MIMETYPES_DESC_SHORT	_( "The list of patterns to match the mimetypes of the selected file(s)" )
-#define ACTION_MIMETYPES_DESC_LONG	_( "A list of strings with joker '*' or '?' to match the mimetypes of the selected " \
-										"file(s). Each selected items must match at least one of the " \
-										"mimetype patterns for the action to appear. " \
-										"This only applies when targeting selection." )
-#define ACTION_ISFILE_DESC_SHORT	_( "'true' if the selection can have files, 'false' otherwise" )
-#define ACTION_ISFILE_DESC_LONG		_( "This setting is tied in with the 'isdir' setting. The valid combinations " \
-										"are:\n\nisfile=TRUE and isdir=FALSE: the selection may hold only files\n" \
-										"isfile=FALSE and isdir=TRUE: the selection may hold only folders\n" \
-										"isfile=TRUE and isdir=TRUE: the selection may hold both files and folders\n" \
-										"isfile=FALSE and isdir=FALSE: this is an invalid combination (your configuration " \
-										"will never appear). This only applies when targeting selection." )
-#define ACTION_ISDIR_DESC_SHORT		_( "'true' if the selection can have folders, 'false' otherwise" )
-#define ACTION_ISDIR_DESC_LONG		_( "This setting is tied in with the 'isfile' setting. The valid combinations " \
-										"are:\n\nisfile=TRUE and isdir=FALSE: the selection may hold only files\n" \
-										"isfile=FALSE and isdir=TRUE: the selection may hold only folders\n" \
-										"isfile=TRUE and isdir=TRUE: the selection may hold both files and folders\n" \
-										"isfile=FALSE and isdir=FALSE: this is an invalid combination (your configuration " \
-										"will never appear). This only applies when targeting selection." )
-#define ACTION_MULTIPLE_DESC_SHORT	_( "'true' if the selection can have several items, 'false' otherwise" )
-#define ACTION_MULTIPLE_DESC_LONG	_( "If you need one or more files or folders to be selected, set this " \
-										"key to 'true'. If you want just one file or folder, set 'false'. " \
-										"This only applies when targeting selection." )
-#define ACTION_SCHEMES_DESC_SHORT	_( "The list of schemes where the selected files should be located" )
-/* too long string for iso c: 510 (max=509) */
-#define ACTION_SCHEMES_DESC_LONG	_( "Defines the list of valid schemes to be matched against the selected " \
-										"items. The scheme is the protocol used to access the files. The " \
-										"keyword to use is the one used in the URI.\n\nExamples of valid " \
-										"URI include:\nfile:///tmp/foo.txt\nsftp:///root test example net/tmp/foo.txt\n\n" \
-										"The most common schemes are:\n\n'file': local files\n'sftp': files accessed via SSH\n" \
-										"'ftp': files accessed via FTP\n'smb': files accessed via Samba (Windows share)\n" \
-										"'dav': files accessed via WebDAV\n\nAll schemes used by Nautilus can be used here.\n" \
-										"This only applies when targeting selection." )
-#define ACTION_FOLDERS_DESC_SHORT	_( "The list of URIs on which the Background item applies" )
-#define ACTION_FOLDERS_DESC_LONG	_( "Defines the list of valid URIs to be matched against the current folder.\n " \
-										"This is only used when targeting background or toolbar. All folders 'under' " \
-										"the specified URI are considered valid." )
-#define ACTION_VERSION_DESC_SHORT	_( "The version of the configuration format" )
-#define ACTION_VERSION_DESC_LONG	_( "The version of the configuration format that will be used to manage " \
-										"backward compatibility." )
-
 G_END_DECLS
 
 #endif /* __NAXML_KEYS_H__ */
diff --git a/src/io-xml/naxml-provider.c b/src/io-xml/naxml-provider.c
index affaa93..a049846 100644
--- a/src/io-xml/naxml-provider.c
+++ b/src/io-xml/naxml-provider.c
@@ -32,14 +32,13 @@
 #include <config.h>
 #endif
 
-#include <glib/gi18n.h>
-
 #include <api/na-ifactory-provider.h>
 #include <api/na-iexporter.h>
 #include <api/na-iimporter.h>
 
 #include "naxml-provider.h"
 #include "naxml-reader.h"
+#include "naxml-writer.h"
 
 /* private class data
  */
@@ -53,43 +52,7 @@ struct NAXMLProviderPrivate {
 	gboolean dispose_has_run;
 };
 
-static NAIExporterFormat st_formats[] = {
-
-	/* GCONF_SCHEMA_V1: a schema with owner, short and long descriptions;
-	 * each action has its own schema addressed by the id
-	 * (historical format up to v1.10.x serie)
-	 */
-	{ "GConfSchemaV1",
-			N_( "Export as a full GConf schema (v_1) file" ),
-			N_( "Export as a GConf schema file with full key descriptions" ),
-			N_( "This used to be the historical export format. " \
-				"The exported file may later be imported via :\n" \
-				"- Import assistant of the Nautilus Actions Configuration Tool,\n" \
-				"- or via the gconftool-2 --import-schema-file command-line tool." ) },
-
-	/* GCONF_SCHEMA_V2: the lightest schema still compatible with gconftool-2 --install-schema-file
-	 * (no owner, no short nor long descriptions) - introduced in v 1.11
-	 */
-	{ "GConfSchemaV2",
-			N_( "Export as a light GConf _schema (v2) file" ),
-			N_( "Export as a light GConf schema file" ),
-			N_( "The exported file may later be imported via :\n" \
-				"- Import assistant of the Nautilus Actions Configuration Tool,\n" \
-				"- or via the gconftool-2 --import-schema-file command-line tool." ) },
-
-	/* GCONF_ENTRY: not a schema, but a dump of the GConf entry
-	 * introduced in v 1.11
-	 */
-	{ "GConfEntry",
-			N_( "Export as a GConf _entry file" ),
-			N_( "Export as a GConf entry file" ),
-			N_( "This should be the preferred format for newly exported actions.\n" \
-				"The exported file may later be imported via :\n" \
-				"- Import assistant of the Nautilus Actions Configuration Tool,\n" \
-				"- or via the gconftool-2 --load command-line tool." ) },
-
-	{ NULL, NULL, NULL }
-};
+extern NAIExporterFormat naxml_formats[];
 
 static GType         st_module_type = 0;
 static GObjectClass *st_parent_class = NULL;
@@ -259,8 +222,8 @@ iexporter_iface_init( NAIExporterInterface *iface )
 	iface->get_version = iexporter_get_version;
 	iface->get_name = iexporter_get_name;
 	iface->get_formats = iexporter_get_formats;
-	iface->to_file = NULL;
-	iface->to_buffer = NULL;
+	iface->to_file = naxml_writer_export_to_file;
+	iface->to_buffer = naxml_writer_export_to_buffer;
 }
 
 static guint
@@ -272,13 +235,13 @@ iexporter_get_version( const NAIExporter *exporter )
 static gchar *
 iexporter_get_name( const NAIExporter *exporter )
 {
-	return( g_strdup( "NAXML Provider" ));
+	return( g_strdup( "NAXML Exporter" ));
 }
 
 static const NAIExporterFormat *
 iexporter_get_formats( const NAIExporter *exporter )
 {
-	return( st_formats );
+	return( naxml_formats );
 }
 
 static void
@@ -292,9 +255,9 @@ ifactory_provider_iface_init( NAIFactoryProviderInterface *iface )
 	iface->read_start = naxml_reader_read_start;
 	iface->read_data = naxml_reader_read_data;
 	iface->read_done = naxml_reader_read_done;
-	iface->write_start = NULL;
-	iface->write_data = NULL;
-	iface->write_done = NULL;
+	iface->write_start = naxml_writer_write_start;
+	iface->write_data = naxml_writer_write_data;
+	iface->write_done = naxml_writer_write_done;
 }
 
 static guint
diff --git a/src/io-xml/na-xml-writer.c b/src/io-xml/naxml-writer.c
similarity index 72%
rename from src/io-xml/na-xml-writer.c
rename to src/io-xml/naxml-writer.c
index b447a18..37cc627 100644
--- a/src/io-xml/na-xml-writer.c
+++ b/src/io-xml/naxml-writer.c
@@ -34,16 +34,20 @@
 
 #include <gio/gio.h>
 #include <libxml/tree.h>
+#include <string.h>
 
+#include <api/na-data-types.h>
 #include <api/na-object-api.h>
+#include <api/na-ifactory-provider.h>
+#include <api/na-iio-provider.h>
 
-#include <io-provider-gconf/nagp-keys.h>
+#include <io-gconf/nagp-keys.h>
 
-#include <runtime/na-iprefs.h>
-#include <runtime/na-utils.h>
+#include "naxml-formats.h"
+#include "naxml-keys.h"
+#include "naxml-writer.h"
 
-#include "na-xml-names.h"
-#include "na-xml-writer.h"
+typedef struct ExportFormatFn ExportFormatFn;
 
 /* private class data
  */
@@ -54,66 +58,85 @@ struct NAXMLWriterClassPrivate {
 /* private instance data
  */
 struct NAXMLWriterPrivate {
-	gboolean  dispose_has_run;
-	gchar    *uuid;
+	gboolean         dispose_has_run;
+	NAIExporter     *provider;
+	NAObjectItem    *exported;
+	GSList          *messages;
+
+	/* positionning these at document level
+	 */
+	xmlDocPtr        doc;
+	ExportFormatFn  *fn_str;
+	gchar           *buffer;
+
+	/* the list node is parent of all entry nodes
+	 * it is set in build_xml_doc() to be used as a parent in each
+	 * entry node
+	 */
+	xmlNodePtr       list_node;
+
+	/* nodes created in write_data_schema_v2(), used in write_data_schema_v1()
+	 */
+	xmlNodePtr       schema_node;
+	xmlNodePtr       locale_node;
+
+	/* when exporting a profile
+	 * it is set in write_done when exporting a profile
+	 */
+	NAObjectAction  *action;
 };
 
-/* instance properties
+/* the association between an export format and the functions
  */
-enum {
-	XML_WRITER_PROP_UUID_ID = 1
+struct ExportFormatFn {
+	gchar  *format;
+	gchar  *root_node;
+	gchar  *list_node;
+	gchar  *element_node;
+	void ( *write_data_fn )( NAXMLWriter *, const NAObjectId *, const NADataBoxed * );
 };
 
-#define XLM_WRITER_PROP_UUID		"na-xml-writer-uuid"
-
 static GObjectClass *st_parent_class = NULL;
 
-static GType        register_type( void );
-static void         class_init( NAXMLWriterClass *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 NAXMLWriter *xml_writer_new( const gchar *uuid );
-static xmlDocPtr    create_xml_schema( NAXMLWriter *writer, gint format, const NAObjectAction *action );
-static void         create_schema_entry(
-								NAXMLWriter *writer,
-								gint format,
-								const gchar *profile_name,
-								const gchar *key,
-								const gchar *value,
-								xmlDocPtr doc,
-								xmlNodePtr list_node,
-								const gchar *type,
-								gboolean is_l10n_value,
-								const gchar *short_desc,
-								const gchar *long_desc );
-static xmlDocPtr    create_xml_dump( NAXMLWriter *writer, gint format, const NAObjectAction *action );
-static void         create_dump_entry(
-								NAXMLWriter *writer,
-								gint format,
-								const gchar *profile_name,
-								const gchar *key,
-								const gchar *value,
-								xmlDocPtr doc,
-								xmlNodePtr list_node,
-								const gchar *type );
-static xmlDocPtr    create_gconf_schema( NAXMLWriter *writer );
-static void         create_gconf_schema_entry(
-								NAXMLWriter *writer,
-								const gchar *entry,
-								xmlDocPtr doc,
-								xmlNodePtr list_node,
-								const gchar *type,
-								const gchar *short_desc,
-								const gchar *long_desc,
-								const gchar *default_value,
-								gboolean is_i18n );
+static GType           register_type( void );
+static void            class_init( NAXMLWriterClass *klass );
+static void            instance_init( GTypeInstance *instance, gpointer klass );
+static void            instance_dispose( GObject *object );
+static void            instance_finalize( GObject *object );
+
+static void            write_data_schema_v1( NAXMLWriter *writer, const NAObjectId *object, const NADataBoxed *boxed );
+static void            write_data_schema_v2( NAXMLWriter *writer, const NAObjectId *object, const NADataBoxed *boxed );
+static void            write_data_dump( NAXMLWriter *writer, const NAObjectId *object, const NADataBoxed *boxed );
+
+static xmlDocPtr       build_xml_doc( NAXMLWriter *writer );
+static ExportFormatFn *find_export_format_fn( GQuark format );
+static guint           writer_to_buffer( NAXMLWriter *writer );
+
+static ExportFormatFn st_export_format_fn[] = {
+
+	{ NAXML_FORMAT_GCONF_SCHEMA_V1,
+					NAXML_KEY_SCHEMA_ROOT,
+					NAXML_KEY_SCHEMA_LIST,
+					NAXML_KEY_SCHEMA_NODE,
+					write_data_schema_v1 },
+
+	{ NAXML_FORMAT_GCONF_SCHEMA_V2,
+					NAXML_KEY_SCHEMA_ROOT,
+					NAXML_KEY_SCHEMA_LIST,
+					NAXML_KEY_SCHEMA_NODE,
+					write_data_schema_v2 },
+
+	{ NAXML_FORMAT_GCONF_ENTRY,
+					NAXML_KEY_DUMP_ROOT,
+					NAXML_KEY_DUMP_LIST,
+					NAXML_KEY_DUMP_NODE,
+					write_data_dump },
+
+	{ NULL }
+};
 
 GType
-na_xml_writer_get_type( void )
+naxml_writer_get_type( void )
 {
 	static GType object_type = 0;
 
@@ -127,7 +150,7 @@ na_xml_writer_get_type( void )
 static GType
 register_type( void )
 {
-	static const gchar *thisfn = "na_xml_writer_register_type";
+	static const gchar *thisfn = "naxml_writer_register_type";
 	GType type;
 
 	static GTypeInfo info = {
@@ -152,9 +175,8 @@ register_type( void )
 static void
 class_init( NAXMLWriterClass *klass )
 {
-	static const gchar *thisfn = "na_xml_writer_class_init";
+	static const gchar *thisfn = "naxml_writer_class_init";
 	GObjectClass *object_class;
-	GParamSpec *spec;
 
 	g_debug( "%s: klass=%p", thisfn, ( void * ) klass );
 
@@ -163,15 +185,6 @@ class_init( NAXMLWriterClass *klass )
 	object_class = G_OBJECT_CLASS( klass );
 	object_class->dispose = instance_dispose;
 	object_class->finalize = instance_finalize;
-	object_class->get_property = instance_get_property;
-	object_class->set_property = instance_set_property;
-
-	spec = g_param_spec_string(
-			XLM_WRITER_PROP_UUID,
-			XLM_WRITER_PROP_UUID,
-			"UUID of the action for which we invoke this XMLWriter", "",
-			G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE );
-	g_object_class_install_property( object_class, XML_WRITER_PROP_UUID_ID, spec );
 
 	klass->private = g_new0( NAXMLWriterClassPrivate, 1 );
 }
@@ -179,12 +192,12 @@ class_init( NAXMLWriterClass *klass )
 static void
 instance_init( GTypeInstance *instance, gpointer klass )
 {
-	static const gchar *thisfn = "na_xml_writer_instance_init";
+	static const gchar *thisfn = "naxml_writer_instance_init";
 	NAXMLWriter *self;
 
 	g_debug( "%s: instance=%p, klass=%p", thisfn, ( void * ) instance, ( void * ) klass );
-	g_return_if_fail( NA_IS_XML_WRITER( instance ));
-	self = NA_XML_WRITER( instance );
+	g_return_if_fail( NAXML_IS_WRITER( instance ));
+	self = NAXML_WRITER( instance );
 
 	self->private = g_new0( NAXMLWriterPrivate, 1 );
 
@@ -192,93 +205,497 @@ instance_init( GTypeInstance *instance, gpointer klass )
 }
 
 static void
-instance_get_property( GObject *object, guint property_id, GValue *value, GParamSpec *spec )
+instance_dispose( GObject *object )
 {
+	static const gchar *thisfn = "naxml_writer_instance_dispose";
 	NAXMLWriter *self;
 
-	g_return_if_fail( NA_IS_XML_WRITER( object ));
-	self = NA_XML_WRITER( object );
+	g_debug( "%s: object=%p", thisfn, ( void * ) object );
+	g_return_if_fail( NAXML_IS_WRITER( object ));
+	self = NAXML_WRITER( object );
 
 	if( !self->private->dispose_has_run ){
 
-		switch( property_id ){
-			case XML_WRITER_PROP_UUID_ID:
-				g_value_set_string( value, self->private->uuid );
-				break;
+		self->private->dispose_has_run = TRUE;
 
-			default:
-				G_OBJECT_WARN_INVALID_PROPERTY_ID( object, property_id, spec );
-				break;
+		/* chain up to the parent class */
+		if( G_OBJECT_CLASS( st_parent_class )->dispose ){
+			G_OBJECT_CLASS( st_parent_class )->dispose( object );
 		}
 	}
 }
 
 static void
-instance_set_property( GObject *object, guint property_id, const GValue *value, GParamSpec *spec )
+instance_finalize( GObject *object )
 {
 	NAXMLWriter *self;
 
-	g_return_if_fail( NA_IS_XML_WRITER( object ));
-	self = NA_XML_WRITER( object );
+	g_return_if_fail( NAXML_IS_WRITER( object ));
+	self = NAXML_WRITER( object );
 
-	if( !self->private->dispose_has_run ){
+	/* do not release self->private->buffer as the pointer has been
+	 * returned to the caller
+	 */
 
-		switch( property_id ){
-			case XML_WRITER_PROP_UUID_ID:
-				g_free( self->private->uuid );
-				self->private->uuid = g_value_dup_string( value );
-				break;
+	g_free( self->private );
 
-			default:
-				G_OBJECT_WARN_INVALID_PROPERTY_ID( object, property_id, spec );
-				break;
+	/* chain call to parent class */
+	if( G_OBJECT_CLASS( st_parent_class )->finalize ){
+		G_OBJECT_CLASS( st_parent_class )->finalize( object );
+	}
+}
+
+/**
+ * naxml_writer_export_to_buffer:
+ * @instance: this #NAIExporter instance.
+ * @parms: a #NAIExporterBufferParms structure.
+ *
+ * Export the specified 'item' to a newly allocated buffer.
+ */
+guint
+naxml_writer_export_to_buffer( const NAIExporter *instance, NAIExporterBufferParms *parms )
+{
+	static const gchar *thisfn = "naxml_writer_export_to_buffer";
+	NAXMLWriter *writer;
+	guint code;
+
+	g_debug( "%s: instance=%p, parms=%p", thisfn, ( void * ) instance, ( void * ) parms );
+
+	code = NA_IEXPORTER_CODE_OK;
+
+	if( !parms->exported || !NA_IS_OBJECT_ITEM( parms->exported )){
+		code = NA_IEXPORTER_CODE_INVALID_ITEM;
+	}
+
+	if( code == NA_IEXPORTER_CODE_OK ){
+		writer = NAXML_WRITER( g_object_new( NAXML_WRITER_TYPE, NULL ));
+
+		writer->private->provider = ( NAIExporter * ) instance;
+		writer->private->exported = parms->exported;
+		writer->private->messages = parms->messages;
+		writer->private->fn_str = find_export_format_fn( parms->format );
+		writer->private->action = NULL;
+
+		if( !writer->private->fn_str ){
+			code = NA_IEXPORTER_CODE_INVALID_FORMAT;
+
+		} else {
+			code = writer_to_buffer( writer );
+			if( code == NA_IEXPORTER_CODE_OK ){
+				parms->buffer = writer->private->buffer;
+			}
 		}
+
+		g_object_unref( writer );
+	}
+
+	g_debug( "%s: returning code=%u", thisfn, code );
+	return( code );
+}
+
+/**
+ * naxml_writer_export_to_file:
+ * @instance: this #NAIExporter instance.
+ * @parms: a #NAIExporterFileParms structure.
+ *
+ * Export the specified 'item' to a newly created file.
+ */
+guint
+naxml_writer_export_to_file( const NAIExporter *instance, NAIExporterFileParms *parms )
+{
+	static const gchar *thisfn = "naxml_writer_export_to_file";
+	NAXMLWriter *writer;
+	guint code;
+
+	g_debug( "%s: instance=%p, parms=%p", thisfn, ( void * ) instance, ( void * ) parms );
+
+	code = NA_IEXPORTER_CODE_OK;
+
+	if( !parms->exported || !NA_IS_OBJECT_ITEM( parms->exported )){
+		code = NA_IEXPORTER_CODE_INVALID_ITEM;
 	}
+
+	if( code == NA_IEXPORTER_CODE_OK ){
+		writer = NAXML_WRITER( g_object_new( NAXML_WRITER_TYPE, NULL ));
+
+		g_object_unref( writer );
+	}
+
+	g_debug( "%s: returning code=%u", thisfn, code );
+	return( code );
+}
+
+static xmlDocPtr
+build_xml_doc( NAXMLWriter *writer )
+{
+	xmlNodePtr root_node;
+
+	writer->private->doc = xmlNewDoc( BAD_CAST( "1.0" ));
+
+	root_node = xmlNewNode( NULL, BAD_CAST( writer->private->fn_str->root_node ));
+	xmlDocSetRootElement( writer->private->doc, root_node );
+
+	writer->private->list_node = xmlNewChild( root_node, NULL, BAD_CAST( writer->private->fn_str->list_node ), NULL );
+
+	na_ifactory_provider_write_item(
+			NA_IFACTORY_PROVIDER( writer->private->provider ),
+			writer,
+			NA_IFACTORY_OBJECT( writer->private->exported ),
+			writer->private->messages ? & writer->private->messages : NULL );
+
+	return( writer->private->doc );
+}
+
+guint
+naxml_writer_write_start( const NAIFactoryProvider *provider, void *writer_data, const NAIFactoryObject *object, GSList **messages  )
+{
+	static const gchar *thisfn = "naxml_writer_write_start";
+	NADataBoxed *boxed;
+	NAXMLWriter *writer;
+
+	if( NA_IS_OBJECT_ITEM( object )){
+
+		na_object_dump( object );
+
+		boxed = na_ifactory_object_get_data_boxed( object, NAFO_DATA_TYPE );
+
+		if( boxed ){
+			writer = NAXML_WRITER( writer_data );
+			( *writer->private->fn_str->write_data_fn )( writer, NA_OBJECT_ID( object ), boxed );
+
+		} else {
+			g_warning( "%s: unable to get %s databox", thisfn, NAFO_DATA_TYPE );
+		}
+	}
+
+	return( NA_IIO_PROVIDER_CODE_OK );
+}
+
+guint
+naxml_writer_write_data( const NAIFactoryProvider *provider, void *writer_data, const NAIFactoryObject *object, const NADataBoxed *boxed, GSList **messages )
+{
+	guint code;
+	NAXMLWriter *writer;
+
+	/*NADataDef *def = na_data_boxed_get_data_def( boxed );
+	g_debug( "naxml_writer_write_data: def=%s", def->name );*/
+
+	code = NA_IIO_PROVIDER_CODE_OK;
+	writer = NAXML_WRITER( writer_data );
+
+	writer->private->schema_node = NULL;
+	writer->private->locale_node = NULL;
+
+	( *writer->private->fn_str->write_data_fn )( writer, NA_OBJECT_ID( object ), boxed );
+
+	return( code );
+}
+
+guint
+naxml_writer_write_done( const NAIFactoryProvider *provider, void *writer_data, const NAIFactoryObject *object, GSList **messages  )
+{
+	GList *children, *ic;
+
+	if( NA_IS_OBJECT_ACTION( object )){
+
+		NAXMLWriter *writer = NAXML_WRITER( writer_data );
+		writer->private->action = NA_OBJECT_ACTION( object );
+		children = na_object_get_items( object );
+
+		for( ic = children ; ic ; ic = ic->next ){
+			na_ifactory_provider_write_item( provider, writer, ( NAIFactoryObject * ) ic->data, messages );
+		}
+	}
+
+	return( NA_IIO_PROVIDER_CODE_OK );
 }
 
 static void
-instance_dispose( GObject *object )
+write_data_schema_v1( NAXMLWriter *writer, const NAObjectId *object, const NADataBoxed *boxed )
+{
+	NADataDef *def;
+
+	write_data_schema_v2( writer, object, boxed );
+
+	def = na_data_boxed_get_data_def( boxed );
+
+	if( !writer->private->locale_node ){
+		writer->private->locale_node = xmlNewChild( writer->private->schema_node, NULL, BAD_CAST( NAXML_KEY_SCHEMA_NODE_LOCALE ), NULL );
+		xmlNewProp( writer->private->locale_node, BAD_CAST( "name" ), BAD_CAST( "C" ));
+	}
+
+	xmlNewChild( writer->private->schema_node, NULL, BAD_CAST( NAXML_KEY_SCHEMA_NODE_OWNER ), BAD_CAST( PACKAGE_TARNAME ));
+
+	xmlNewChild( writer->private->locale_node, NULL, BAD_CAST( NAXML_KEY_SCHEMA_NODE_LOCALE_SHORT ), BAD_CAST( def->short_label ));
+
+	xmlNewChild( writer->private->locale_node, NULL, BAD_CAST( NAXML_KEY_SCHEMA_NODE_LOCALE_LONG ), BAD_CAST( def->long_label ));
+}
+
+/*
+ * <schema>
+ *  <key>/schemas/apps/nautilus-actions/configurations/entry</key>
+ *  <applyto>/apps/nautilus-actions/configurations/item_id/profile_id/entry</applyto>
+ */
+static void
+write_data_schema_v2( NAXMLWriter *writer, const NAObjectId *object, const NADataBoxed *boxed )
+{
+	gchar *object_id;
+	NADataDef *def;
+	xmlChar *content;
+	xmlNodePtr parent_value_node;
+	gchar *value_str;
+
+	def = na_data_boxed_get_data_def( boxed );
+	value_str = na_data_boxed_get_as_string( boxed );
+
+	/* do no export empty values, but for string list
+	 */
+	if( !value_str || !strlen( value_str )){
+		return;
+	}
+
+	/* boolean value must be lowercase
+	 */
+	if( def->type == NAFD_TYPE_BOOLEAN ){
+		gchar *tmp = g_ascii_strdown( value_str, -1 );
+		g_free( value_str );
+		value_str = tmp;
+	}
+
+	writer->private->schema_node = xmlNewChild( writer->private->list_node, NULL, BAD_CAST( NAXML_KEY_SCHEMA_NODE ), NULL );
+
+	object_id = na_object_get_id( object );
+
+	if( writer->private->action ){
+		gchar *id = na_object_get_id( writer->private->action );
+		gchar *tmp = g_strdup_printf( "%s/%s", id, object_id );
+		g_free( id );
+		g_free( object_id );
+		object_id = tmp;
+	}
+
+	content = BAD_CAST( g_build_path( "/", NAGP_SCHEMAS_PATH, def->gconf_entry, NULL ));
+	xmlNewChild( writer->private->schema_node, NULL, BAD_CAST( NAXML_KEY_SCHEMA_NODE_KEY ), content );
+	xmlFree( content );
+
+	content = BAD_CAST( g_build_path( "/", NAGP_CONFIGURATIONS_PATH, object_id, def->gconf_entry, NULL ));
+	xmlNewChild( writer->private->schema_node, NULL, BAD_CAST( NAXML_KEY_SCHEMA_NODE_APPLYTO ), content );
+	xmlFree( content );
+
+	xmlNewChild( writer->private->schema_node, NULL, BAD_CAST( NAXML_KEY_SCHEMA_NODE_TYPE ), BAD_CAST( na_data_types_get_gconf_dump_key( def->type )));
+	if( def->type == NAFD_TYPE_STRING_LIST ){
+		xmlNewChild( writer->private->schema_node, NULL, BAD_CAST( NAXML_KEY_SCHEMA_NODE_LISTTYPE ), BAD_CAST( "string" ));
+	}
+
+	parent_value_node = writer->private->schema_node;
+
+	if( def->localizable ){
+		writer->private->locale_node = xmlNewChild( writer->private->schema_node, NULL, BAD_CAST( NAXML_KEY_SCHEMA_NODE_LOCALE ), NULL );
+		xmlNewProp( writer->private->locale_node, BAD_CAST( "name" ), BAD_CAST( "C" ));
+		parent_value_node = writer->private->locale_node;
+	}
+
+	content = xmlEncodeSpecialChars( writer->private->doc, BAD_CAST( value_str ));
+	xmlNewChild( parent_value_node, NULL, BAD_CAST( NAXML_KEY_SCHEMA_NODE_DEFAULT ), content );
+	xmlFree( content );
+
+	g_free( value_str );
+	g_free( object_id );
+}
+
+static void
+write_data_dump( NAXMLWriter *writer, const NAObjectId *object, const NADataBoxed *boxed )
+{
+	xmlNodePtr entry_node;
+	gchar *entry;
+	NADataDef *def;
+	xmlNodePtr value_node;
+	xmlNodePtr value_list_node, value_list_value_node;
+	GSList *list, *is;
+	xmlChar *encoded_content;
+	gchar *value_str;
+
+	value_str = NULL;
+	def = na_data_boxed_get_data_def( boxed );
+
+	/* do no export empty values, but for string list
+	 */
+	if( def->type != NAFD_TYPE_STRING_LIST ){
+		value_str = na_data_boxed_get_as_string( boxed );
+		if( !value_str || !strlen( value_str )){
+			return;
+		}
+	}
+
+	/* boolean value must be lowercase
+	 */
+	if( def->type == NAFD_TYPE_BOOLEAN ){
+		gchar *tmp = g_ascii_strdown( value_str, -1 );
+		g_free( value_str );
+		value_str = tmp;
+	}
+
+	entry_node = xmlNewChild( writer->private->list_node, NULL, BAD_CAST( writer->private->fn_str->element_node ), NULL );
+
+	if( writer->private->action ){
+		gchar *id = na_object_get_id( object );
+		entry = g_strdup_printf( "%s/%s", id, def->gconf_entry );
+		g_free( id );
+	} else {
+		entry = g_strdup( def->gconf_entry );
+	}
+	xmlNewChild( entry_node, NULL, BAD_CAST( NAXML_KEY_DUMP_NODE_KEY ), BAD_CAST( entry ));
+
+	value_node = xmlNewChild( entry_node, NULL, BAD_CAST( NAXML_KEY_DUMP_NODE_VALUE ), NULL );
+
+	if( def->type == NAFD_TYPE_STRING_LIST ){
+		value_list_node = xmlNewChild( value_node, NULL, BAD_CAST( NAXML_KEY_DUMP_NODE_VALUE_LIST ), NULL );
+		xmlNewProp( value_list_node, BAD_CAST( NAXML_KEY_DUMP_NODE_VALUE_LIST_PARM_TYPE ), BAD_CAST( NAXML_KEY_DUMP_NODE_VALUE_TYPE_STRING ));
+		value_list_value_node = xmlNewChild( value_list_node, NULL, BAD_CAST( NAXML_KEY_DUMP_NODE_VALUE ), NULL );
+		list = ( GSList * ) na_data_boxed_get_as_void( boxed );
+
+		for( is = list ; is ; is = is->next ){
+			encoded_content = xmlEncodeSpecialChars( writer->private->doc, BAD_CAST(( gchar * ) is->data ));
+			xmlNewChild( value_list_value_node, NULL, BAD_CAST( NAXML_KEY_DUMP_NODE_VALUE_TYPE_STRING ), encoded_content );
+			xmlFree( encoded_content );
+		}
+
+	} else {
+		encoded_content = xmlEncodeSpecialChars( writer->private->doc, BAD_CAST( value_str ));
+		xmlNewChild( value_node, NULL, BAD_CAST( na_data_types_get_gconf_dump_key( def->type )), encoded_content );
+		xmlFree( encoded_content );
+		g_free( value_str );
+	}
+
+	g_free( entry );
+}
+
+static ExportFormatFn *
+find_export_format_fn( GQuark format )
+{
+	ExportFormatFn *found;
+	ExportFormatFn *i;
+
+	found = NULL;
+	i = st_export_format_fn;
+
+	while( i->format && !found ){
+		if( g_quark_from_string( i->format ) == format ){
+			found = i;
+		}
+		i++;
+	}
+
+	return( found );
+}
+
+static guint
+writer_to_buffer( NAXMLWriter *writer )
+{
+	guint code;
+	xmlDocPtr doc;
+	xmlChar *text;
+	int textlen;
+
+	code = NA_IEXPORTER_CODE_OK;
+	doc = build_xml_doc( writer );
+
+	xmlDocDumpFormatMemoryEnc( doc, &text, &textlen, "UTF-8", 1 );
+	writer->private->buffer = g_strdup(( const gchar * ) text );
+
+	xmlFree( text );
+	xmlFreeDoc (doc);
+	xmlCleanupParser();
+
+	return( code );
+}
+
+#if 0
+static NAXMLWriter *xml_writer_new( const gchar *uuid );
+static xmlDocPtr    create_xml_schema( NAXMLWriter *writer, gint format, const NAObjectAction *action );
+static void         create_schema_entry(
+								NAXMLWriter *writer,
+								gint format,
+								const gchar *profile_name,
+								const gchar *key,
+								const gchar *value,
+								xmlDocPtr doc,
+								xmlNodePtr list_node,
+								const gchar *type,
+								gboolean is_l10n_value,
+								const gchar *short_desc,
+								const gchar *long_desc );
+static xmlDocPtr    create_xml_dump( NAXMLWriter *writer, gint format, const NAObjectAction *action );
+static void         create_dump_entry(
+								NAXMLWriter *writer,
+								gint format,
+								const gchar *profile_name,
+								const gchar *key,
+								const gchar *value,
+								xmlDocPtr doc,
+								xmlNodePtr list_node,
+								const gchar *type );
+static xmlDocPtr    create_gconf_schema( NAXMLWriter *writer );
+static void         create_gconf_schema_entry(
+								NAXMLWriter *writer,
+								const gchar *entry,
+								xmlDocPtr doc,
+								xmlNodePtr list_node,
+								const gchar *type,
+								const gchar *short_desc,
+								const gchar *long_desc,
+								const gchar *default_value,
+								gboolean is_i18n );
+
+static void
+instance_get_property( GObject *object, guint property_id, GValue *value, GParamSpec *spec )
 {
-	static const gchar *thisfn = "na_xml_writer_instance_dispose";
 	NAXMLWriter *self;
 
-	g_debug( "%s: object=%p", thisfn, ( void * ) object );
 	g_return_if_fail( NA_IS_XML_WRITER( object ));
 	self = NA_XML_WRITER( object );
 
 	if( !self->private->dispose_has_run ){
 
-		self->private->dispose_has_run = TRUE;
+		switch( property_id ){
+			case XML_WRITER_PROP_UUID_ID:
+				g_value_set_string( value, self->private->uuid );
+				break;
 
-		/* chain up to the parent class */
-		if( G_OBJECT_CLASS( st_parent_class )->dispose ){
-			G_OBJECT_CLASS( st_parent_class )->dispose( object );
+			default:
+				G_OBJECT_WARN_INVALID_PROPERTY_ID( object, property_id, spec );
+				break;
 		}
 	}
 }
 
 static void
-instance_finalize( GObject *object )
+instance_set_property( GObject *object, guint property_id, const GValue *value, GParamSpec *spec )
 {
 	NAXMLWriter *self;
 
 	g_return_if_fail( NA_IS_XML_WRITER( object ));
 	self = NA_XML_WRITER( object );
 
-	g_free( self->private->uuid );
+	if( !self->private->dispose_has_run ){
 
-	g_free( self->private );
+		switch( property_id ){
+			case XML_WRITER_PROP_UUID_ID:
+				g_free( self->private->uuid );
+				self->private->uuid = g_value_dup_string( value );
+				break;
 
-	/* chain call to parent class */
-	if( G_OBJECT_CLASS( st_parent_class )->finalize ){
-		G_OBJECT_CLASS( st_parent_class )->finalize( object );
+			default:
+				G_OBJECT_WARN_INVALID_PROPERTY_ID( object, property_id, spec );
+				break;
+		}
 	}
 }
 
 static NAXMLWriter *
-xml_writer_new( const gchar *uuid )
+writer_new( const gchar *uuid )
 {
-	return( g_object_new( NA_XML_WRITER_TYPE, XLM_WRITER_PROP_UUID, uuid, NULL ));
+	return( g_object_new( NAXML_WRITER_TYPE, NULL ));
 }
 
 /**
@@ -1077,3 +1494,4 @@ create_gconf_schema_entry( NAXMLWriter *writer,
 
 	xmlNewChild( locale_node, NULL, BAD_CAST( NACT_GCONF_SCHEMA_LONG ), BAD_CAST( long_desc ));
 }
+#endif
diff --git a/src/io-xml/na-xml-writer.h b/src/io-xml/naxml-writer.h
similarity index 54%
rename from src/io-xml/na-xml-writer.h
rename to src/io-xml/naxml-writer.h
index 722183c..33fa190 100644
--- a/src/io-xml/na-xml-writer.h
+++ b/src/io-xml/naxml-writer.h
@@ -28,32 +28,30 @@
  *   ... and many others (see AUTHORS)
  */
 
-#ifndef __NA_COMMON_XML_WRITER_H__
-#define __NA_COMMON_XML_WRITER_H__
+#ifndef __NAXML_WRITER_H__
+#define __NAXML_WRITER_H__
 
 /**
- * SECTION: na_xml_writer
+ * SECTION: naxml_writer
  * @short_description: #NAXMLWriter class definition.
- * @include: common/na-xml-writer.h
+ * @include: io-xml/naxml-writer.h
  *
- * This class exports Nautilus Actions as XML files.
- *
- * This class is embedded in libnact library as it is used by
- * nautilus-actions-new utility.
+ * This class exports Nautilus-Actions actions and menus as XML files.
  */
 
-#include <private/na-object-action-class.h>
+#include <api/na-data-boxed.h>
+#include <api/na-iexporter.h>
 
 G_BEGIN_DECLS
 
-#define NA_XML_WRITER_TYPE					( na_xml_writer_get_type())
-#define NA_XML_WRITER( object )				( G_TYPE_CHECK_INSTANCE_CAST( object, NA_XML_WRITER_TYPE, NAXMLWriter ))
-#define NA_XML_WRITER_CLASS( klass )		( G_TYPE_CHECK_CLASS_CAST( klass, NA_XML_WRITER_TYPE, NAXMLWriterClass ))
-#define NA_IS_XML_WRITER( object )			( G_TYPE_CHECK_INSTANCE_TYPE( object, NA_XML_WRITER_TYPE ))
-#define NA_IS_XML_WRITER_CLASS( klass )		( G_TYPE_CHECK_CLASS_TYPE(( klass ), NA_XML_WRITER_TYPE ))
-#define NA_XML_WRITER_GET_CLASS( object )	( G_TYPE_INSTANCE_GET_CLASS(( object ), NA_XML_WRITER_TYPE, NAXMLWriterClass ))
+#define NAXML_WRITER_TYPE					( naxml_writer_get_type())
+#define NAXML_WRITER( object )				( G_TYPE_CHECK_INSTANCE_CAST( object, NAXML_WRITER_TYPE, NAXMLWriter ))
+#define NAXML_WRITER_CLASS( klass )			( G_TYPE_CHECK_CLASS_CAST( klass, NAXML_WRITER_TYPE, NAXMLWriterClass ))
+#define NAXML_IS_WRITER( object )			( G_TYPE_CHECK_INSTANCE_TYPE( object, NAXML_WRITER_TYPE ))
+#define NAXML_IS_WRITER_CLASS( klass )		( G_TYPE_CHECK_CLASS_TYPE(( klass ), NAXML_WRITER_TYPE ))
+#define NAXML_WRITER_GET_CLASS( object )	( G_TYPE_INSTANCE_GET_CLASS(( object ), NAXML_WRITER_TYPE, NAXMLWriterClass ))
 
-typedef struct NAXMLWriterPrivate NAXMLWriterPrivate;
+typedef struct NAXMLWriterPrivate      NAXMLWriterPrivate;
 
 typedef struct {
 	GObject             parent;
@@ -69,13 +67,22 @@ typedef struct {
 }
 	NAXMLWriterClass;
 
-GType  na_xml_writer_get_type( void );
+GType  naxml_writer_get_type( void );
+
+guint  naxml_writer_export_to_buffer( const NAIExporter *instance, NAIExporterBufferParms *parms );
+guint  naxml_writer_export_to_file  ( const NAIExporter *instance, NAIExporterFileParms *parms );
+
+guint  naxml_writer_write_start( const NAIFactoryProvider *writer, void *writer_data, const NAIFactoryObject *object, GSList **messages  );
+guint  naxml_writer_write_data ( const NAIFactoryProvider *writer, void *writer_data, const NAIFactoryObject *object, const NADataBoxed *boxed, GSList **messages );
+guint  naxml_writer_write_done ( const NAIFactoryProvider *writer, void *writer_data, const NAIFactoryObject *object, GSList **messages  );
 
+#if 0
 gchar *na_xml_writer_export( const NAObjectAction *action, const gchar *folder, gint format, GSList **msg );
 gchar *na_xml_writer_get_output_fname( const NAObjectAction *action, const gchar *folder, gint format );
 gchar *na_xml_writer_get_xml_buffer( const NAObjectAction *action, gint format );
 void   na_xml_writer_output_xml( const gchar *xml, const gchar *filename, GSList **msg );
+#endif
 
 G_END_DECLS
 
-#endif /* __NA_COMMON_XML_WRITER_H__ */
+#endif /* __NAXML_WRITER_H__ */
diff --git a/src/nact/nact-clipboard.c b/src/nact/nact-clipboard.c
index 9494cfb..f43c5aa 100644
--- a/src/nact/nact-clipboard.c
+++ b/src/nact/nact-clipboard.c
@@ -381,14 +381,20 @@ nact_clipboard_dnd_get_data( NactClipboard *clipboard, gboolean *copy_data )
 gchar *
 nact_clipboard_dnd_get_text( NactClipboard *clipboard, GList *rows )
 {
+	static const gchar *thisfn = "nact_clipboard_dnd_get_text";
 	gchar *buffer;
 
 	g_return_val_if_fail( NACT_IS_CLIPBOARD( clipboard ), NULL );
 
+	g_debug( "%s: clipboard=%p, rows=%p (count=%u)",
+			thisfn, ( void * ) clipboard, ( void * ) rows, g_list_length( rows ));
+
 	buffer = NULL;
 
 	if( !clipboard->private->dispose_has_run ){
+
 		buffer = export_rows( clipboard, rows, NULL );
+		g_debug( "%s: returning buffer=%p (length=%lu)", thisfn, ( void * ) buffer, g_utf8_strlen( buffer, -1 ));
 	}
 
 	return( buffer );
@@ -413,15 +419,18 @@ nact_clipboard_dnd_drag_end( NactClipboard *clipboard )
 	if( !clipboard->private->dispose_has_run ){
 
 		selection = gtk_clipboard_wait_for_contents( clipboard->private->dnd, NACT_CLIPBOARD_NACT_ATOM );
-		if( selection ){
+		g_debug( "%s: selection=%p", thisfn, ( void * ) selection );
 
+		if( selection ){
 			data = ( NactClipboardDndData * ) selection->data;
 			g_debug( "%s: data=%p (NactClipboardDndData)", thisfn, ( void * ) data );
+
 			if( data->target == NACT_XCHANGE_FORMAT_XDS ){
 				export_rows( clipboard, data->rows, data->folder );
 			}
+
+			gtk_selection_data_free( selection );
 		}
-		gtk_selection_data_free( selection );
 	}
 }
 
@@ -436,6 +445,8 @@ nact_clipboard_dnd_drag_end( NactClipboard *clipboard )
 void
 nact_clipboard_dnd_clear( NactClipboard *clipboard )
 {
+	g_debug( "nact_clipboard_dnd_clear: clipboard=%p", ( void * ) clipboard );
+
 	gtk_clipboard_clear( clipboard->private->dnd );
 }
 
@@ -542,11 +553,12 @@ export_row_object( NactClipboard *clipboard, NAObject *object, const gchar *dest
 	gchar *buffer;
 	GQuark format;
 	gchar *fname;
-	GSList *msg;
+	GSList *msgs;
+
+	data = g_string_new( "" );
 
 	if( NA_IS_OBJECT_MENU( object )){
 		subitems = na_object_get_items( object );
-		data = g_string_new( "" );
 
 		for( isub = subitems ; isub ; isub = isub->next ){
 			buffer = export_row_object( clipboard, isub->data, dest_folder, exported );
@@ -555,12 +567,9 @@ export_row_object( NactClipboard *clipboard, NAObject *object, const gchar *dest
 				g_free( buffer );
 			}
 		}
-
-		return( g_string_free( data, FALSE ));
 	}
 
-	msg = NULL;
-	buffer = NULL;
+	msgs = NULL;
 	action = ( NAObjectAction * ) object;
 	if( NA_IS_OBJECT_PROFILE( object )){
 		action = NA_OBJECT_ACTION( na_object_get_parent( object ));
@@ -582,16 +591,20 @@ export_row_object( NactClipboard *clipboard, NAObject *object, const gchar *dest
 		if( format != IPREFS_EXPORT_NO_EXPORT ){
 
 			if( dest_folder ){
-				fname = na_exporter_to_file( NA_PIVOT( updater ), NA_OBJECT_ITEM( action), dest_folder, format, &msg );
+				fname = na_exporter_to_file( NA_PIVOT( updater ), NA_OBJECT_ITEM( action), dest_folder, format, &msgs );
 				g_free( fname );
 
 			} else {
-				buffer = na_exporter_to_buffer( NA_PIVOT( updater ), NA_OBJECT_ITEM( action ), format, NULL );
+				buffer = na_exporter_to_buffer( NA_PIVOT( updater ), NA_OBJECT_ITEM( action ), format, &msgs );
+				if( buffer && strlen( buffer )){
+					data = g_string_append( data, buffer );
+					g_free( buffer );
+				}
 			}
 		}
 	}
 
-	return( buffer );
+	return( g_string_free( data, FALSE ));
 }
 
 /**
diff --git a/src/nact/nact-tree-model-dnd.c b/src/nact/nact-tree-model-dnd.c
index e81db43..1502edc 100644
--- a/src/nact/nact-tree-model-dnd.c
+++ b/src/nact/nact-tree-model-dnd.c
@@ -40,6 +40,7 @@
 #include <api/na-object-api.h>
 
 #include <core/na-iprefs.h>
+#include <core/na-gnome-vfs-uri.h>
 #include <core/na-importer.h>
 
 #include "nact-application.h"
@@ -273,6 +274,7 @@ nact_tree_model_dnd_imulti_drag_source_drag_data_get( EggTreeMultiDragSource *dr
 	gchar *dest_folder, *folder;
 	gboolean is_writable;
 	gboolean copy_data;
+	NAGnomeVFSURI *vfs;
 
 	atom_name = gdk_atom_name( selection_data->target );
 	g_debug( "%s: drag_source=%p, context=%p, action=%d, selection_data=%p, rows=%p, atom=%s",
@@ -298,10 +300,20 @@ nact_tree_model_dnd_imulti_drag_source_drag_data_get( EggTreeMultiDragSource *dr
 				break;
 
 			case NACT_XCHANGE_FORMAT_XDS:
+				/* get the dest default filename as an uri
+				 * e.g. file:///home/pierre/data/eclipse/nautilus-actions/trash/xds.txt
+				 */
 				folder = get_xds_atom_value( context );
-				dest_folder = g_path_get_dirname( folder );
+				/* get the dest folder as a path
+				 */
+				vfs = g_new0( NAGnomeVFSURI, 1 );
+				na_gnome_vfs_uri_parse( vfs, folder );
+				dest_folder = g_path_get_dirname( vfs->path );
+				na_gnome_vfs_uri_free( vfs );
 				g_free( folder );
-				is_writable = na_core_utils_dir_is_writable_uri( dest_folder );
+				/* check that target folder is writable
+				 */
+				is_writable = na_core_utils_dir_is_writable_path( dest_folder );
 				gtk_selection_data_set( selection_data, selection_data->target, 8, ( guchar * )( is_writable ? "S" : "F" ), 1 );
 				if( is_writable ){
 					nact_clipboard_dnd_set( model->private->clipboard, info, rows, dest_folder, TRUE );
@@ -940,22 +952,45 @@ on_drag_drop( GtkWidget *widget, GdkDragContext *context, gint x, gint y, guint
  * Author: Christian Neumair
  * Copyright: 2005 Free Software Foundation, Inc
  * License: GPL
+ *
+ * On a 32-bits system:
+ * get_xds_atom_value: actual_length=63, actual_length=15
+ * get_xds_atom_value: ret=file:///home/pierre/data/eclipse/nautilus-actions/trash/xds.txt0x8299
+ * get_xds_atom_value: dup=file:///home/pierre/data/eclipse/nautilus-actions/trash/xds.txt
+ * get_xds_atom_value: ret=file:///home/pi
  */
 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;
+	gchar *ret;
+	gint actual_length;
+
+	g_return_val_if_fail( context != NULL, NULL );
+	g_return_val_if_fail( context->source_window != NULL, NULL );
+
+	gdk_property_get( context->source_window,		/* a GdkWindow */
+						XDS_ATOM, 					/* the property to retrieve */
+						TEXT_ATOM,					/* the desired property type */
+						0, 							/* offset (in 4 bytes chunks) */
+						MAX_XDS_ATOM_VAL_LEN,		/* max length (in 4 bytes chunks) */
+						FALSE, 						/* whether to delete the property */
+						NULL, 						/* actual property type */
+						NULL, 						/* actual format */
+						&actual_length,				/* actual length (in 4 bytes chunks) */
+						( guchar ** ) &ret );		/* data pointer */
+
+	g_debug( "get_xds_atom_value: actual_length=%d, actual_length=%d", actual_length, actual_length/sizeof( glong ));
+	g_debug( "get_xds_atom_value: ret=%s", ret );
+
+	gchar *dup = g_strdup( ret );
+	dup[actual_length] = '\0';
+	g_debug( "get_xds_atom_value: dup=%s", dup );
+
+	ret[actual_length/sizeof( glong )] = '\0';
+	g_debug( "get_xds_atom_value: ret=%s", ret );
+	g_free( ret );
+
+	return( dup );
 }
 
 /*



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