[nautilus-actions] NAIOptionsList, NAIOption: new interfaces



commit 5b01f47e4650abe52b25fce49b9ce85966ba8d61
Author: Pierre Wieser <pwieser trychlos org>
Date:   Tue Dec 27 07:20:28 2011 +0100

    NAIOptionsList, NAIOption: new interfaces

 ChangeLog                          |   21 +
 src/core/Makefile.am               |   10 +-
 src/core/na-gtk-utils.c            |  168 +++++++-
 src/core/na-gtk-utils.h            |   15 +
 src/core/na-import-mode.c          |  193 +++++++++
 src/core/na-import-mode.h          |   74 ++++
 src/core/na-ioption.c              |  278 ++++++++++++
 src/core/na-ioption.h              |  164 +++++++
 src/core/na-ioptions-list.c        |  818 ++++++++++++++++++++++++++++++++++++
 src/core/na-ioptions-list.h        |  215 ++++++++++
 src/nact/base-gtk-utils.c          |  115 +-----
 src/nact/base-gtk-utils.h          |    2 -
 src/nact/nact-export-ask.c         |    3 +-
 src/nact/nact-preferences-editor.c |   21 +-
 14 files changed, 1972 insertions(+), 125 deletions(-)
---
diff --git a/ChangeLog b/ChangeLog
index adf80b4..5a6e397 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -11,6 +11,27 @@
 	* src/nact/nact-application.c:
 	* src/nact/nact-application.h (nact_application_new): Have an empty constructor.
 
+2011-12-27 Pierre Wieser <pwieser trychlos org>
+
+	* src/core/na-import-mode.c:
+	* src/core/na-import-mode.h:
+	* src/core/na-ioption.c:
+	* src/core/na-ioption.h:
+	* src/core/na-ioptions-list.c:
+	* src/core/na-ioptions-list.h: New files.
+
+	* src/core/Makefile.am: Updated accordingly.
+
+	* src/core/na-gtk-utils.c:
+	* src/core/na-gtk-utils.h:
+	* src/nact/base-gtk-utils.c:
+	* src/nact/base-gtk-utils.h (base_gtk_utils_set_editable,
+	base_gtk_utils_radio_set_initial_state,
+	base_gtk_utils_radio_reset_initial_state): Move functions to na-gtk-utils.
+
+	* src/nact/nact-export-ask.c:
+	* src/nact/nact-preferences-editor.c: Updated accordingly.
+
 2011-12-25 Pierre Wieser <pwieser trychlos org>
 
 	* src/core/na-gtk-utils.c:
diff --git a/src/core/Makefile.am b/src/core/Makefile.am
index 9894106..91a4b48 100644
--- a/src/core/Makefile.am
+++ b/src/core/Makefile.am
@@ -79,12 +79,18 @@ libna_core_la_SOURCES = \
 	na-ifactory-provider.c								\
 	na-iimporter.c										\
 	na-iio-provider.c									\
-	na-io-provider.c									\
-	na-io-provider.h									\
+	na-import-mode.c									\
+	na-import-mode.h									\
 	na-importer.c										\
 	na-importer.h										\
 	na-importer-ask.c									\
 	na-importer-ask.h									\
+	na-io-provider.c									\
+	na-io-provider.h									\
+	na-ioption.c										\
+	na-ioption.h										\
+	na-ioptions-list.c									\
+	na-ioptions-list.h									\
 	na-iprefs.c											\
 	na-iprefs.h											\
 	na-module.c											\
diff --git a/src/core/na-gtk-utils.c b/src/core/na-gtk-utils.c
index c49429d..41faebf 100644
--- a/src/core/na-gtk-utils.c
+++ b/src/core/na-gtk-utils.c
@@ -54,16 +54,14 @@ na_gtk_utils_find_widget_by_type( GtkContainer *container, GType type )
 	GList *children = gtk_container_get_children( container );
 	GList *ic;
 	GtkWidget *found = NULL;
-	GtkWidget *child;
-	const gchar *child_name;
 
 	for( ic = children ; ic && !found ; ic = ic->next ){
 
 		if( GTK_IS_WIDGET( ic->data )){
 			if( G_OBJECT_TYPE( ic->data ) == type ){
 				found = GTK_WIDGET( ic->data );
-			} else if( GTK_IS_CONTAINER( child )){
-				found = na_gtk_utils_find_widget_by_type( GTK_CONTAINER( child ), type );
+			} else if( GTK_IS_CONTAINER( ic->data )){
+				found = na_gtk_utils_find_widget_by_type( GTK_CONTAINER( ic->data ), type );
 			}
 		}
 	}
@@ -297,3 +295,165 @@ free_int_list( GList *list )
 {
 	g_list_free( list );
 }
+
+/**
+ * na_gtk_utils_set_editable:
+ * @widget: the #GtkWdiget.
+ * @editable: whether the @widget is editable or not.
+ *
+ * Try to set a visual indication of whether the @widget is editable or not.
+ *
+ * Having a GtkWidget should be enough, but we also deal with a GtkTreeViewColumn.
+ * So the most-bottom common ancestor is just GObject (since GtkObject having been
+ * deprecated in Gtk+-3.0)
+ *
+ * Note that using 'sensitivity' property is just a work-around because the
+ * two things have distinct semantics:
+ * - editable: whether we are allowed to modify the value (is not read-only)
+ * - sensitive: whether the value is relevant (has a sense in this context)
+ */
+void
+na_gtk_utils_set_editable( GObject *widget, gboolean editable )
+{
+	GList *renderers, *irender;
+
+/* GtkComboBoxEntry is deprecated from Gtk+3
+ * see. http://git.gnome.org/browse/gtk+/commit/?id=9612c648176378bf237ad0e1a8c6c995b0ca7c61
+ * while 'has_entry' property exists since 2.24
+ */
+#if GTK_CHECK_VERSION( 2,24,0 )
+	if( GTK_IS_COMBO_BOX( widget ) && gtk_combo_box_get_has_entry( GTK_COMBO_BOX( widget ))){
+#else
+	if( GTK_IS_COMBO_BOX_ENTRY( widget )){
+#endif
+		/* idem as GtkEntry */
+		gtk_editable_set_editable( GTK_EDITABLE( gtk_bin_get_child( GTK_BIN( widget ))), editable );
+		g_object_set( G_OBJECT( gtk_bin_get_child( GTK_BIN( widget ))), "can-focus", editable, NULL );
+		/* disable the listbox button itself */
+		gtk_combo_box_set_button_sensitivity( GTK_COMBO_BOX( widget ), editable ? GTK_SENSITIVITY_ON : GTK_SENSITIVITY_OFF );
+
+	} else if( GTK_IS_COMBO_BOX( widget )){
+		/* disable the listbox button itself */
+		gtk_combo_box_set_button_sensitivity( GTK_COMBO_BOX( widget ), editable ? GTK_SENSITIVITY_ON : GTK_SENSITIVITY_OFF );
+
+	} else if( GTK_IS_ENTRY( widget )){
+		gtk_editable_set_editable( GTK_EDITABLE( widget ), editable );
+		/* removing the frame leads to a disturbing modification of the
+		 * height of the control */
+		/*g_object_set( G_OBJECT( widget ), "has-frame", editable, NULL );*/
+		/* this prevents the caret to be displayed when we click in the entry */
+		g_object_set( G_OBJECT( widget ), "can-focus", editable, NULL );
+
+	} else if( GTK_IS_TEXT_VIEW( widget )){
+		g_object_set( G_OBJECT( widget ), "can-focus", editable, NULL );
+		gtk_text_view_set_editable( GTK_TEXT_VIEW( widget ), editable );
+
+	} else if( GTK_IS_TOGGLE_BUTTON( widget )){
+		/* transforms to a quasi standard GtkButton */
+		/*g_object_set( G_OBJECT( widget ), "draw-indicator", editable, NULL );*/
+		/* this at least prevent the keyboard focus to go to the button
+		 * (which is better than nothing) */
+		g_object_set( G_OBJECT( widget ), "can-focus", editable, NULL );
+
+	} else if( GTK_IS_TREE_VIEW_COLUMN( widget )){
+		renderers = gtk_cell_layout_get_cells( GTK_CELL_LAYOUT( GTK_TREE_VIEW_COLUMN( widget )));
+		for( irender = renderers ; irender ; irender = irender->next ){
+			if( GTK_IS_CELL_RENDERER_TEXT( irender->data )){
+				g_object_set( G_OBJECT( irender->data ), "editable", editable, "editable-set", TRUE, NULL );
+			}
+		}
+		g_list_free( renderers );
+
+	} else if( GTK_IS_BUTTON( widget )){
+		gtk_widget_set_sensitive( GTK_WIDGET( widget ), editable );
+	}
+}
+
+/**
+ * na_gtk_utils_radio_set_initial_state:
+ * @button: the #GtkRadioButton button which is initially active.
+ * @handler: the corresponding "toggled" handler.
+ * @user_data: the user data associated to the handler.
+ * @editable: whether this radio button group is editable.
+ * @sensitive: whether this radio button group is sensitive.
+ *
+ * This function should be called for the button which is initially active
+ * inside of a radio button group when the radio group may happen to not be
+ * editable.
+ * This function should be called only once for the radio button group.
+ *
+ * It does the following operations:
+ * - set the button as active
+ * - set other buttons of the radio button group as inactive
+ * - set all buttons of radio button group as @editable
+ *
+ * The initially active @button, along with its @handler, are recorded
+ * as properties of the radio button group (actually as properties of each
+ * radio button of the group), so that they can later be used to reset the
+ * initial state.
+ */
+void
+na_gtk_utils_radio_set_initial_state( GtkRadioButton *button,
+		GCallback handler, void *user_data, gboolean editable, gboolean sensitive )
+{
+	GSList *group, *ig;
+	GtkRadioButton *other;
+
+	group = gtk_radio_button_get_group( button );
+
+	for( ig = group ; ig ; ig = ig->next ){
+		other = GTK_RADIO_BUTTON( ig->data );
+		g_object_set_data( G_OBJECT( other ), NA_TOGGLE_DATA_BUTTON, button );
+		g_object_set_data( G_OBJECT( other ), NA_TOGGLE_DATA_HANDLER, handler );
+		g_object_set_data( G_OBJECT( other ), NA_TOGGLE_DATA_USER_DATA, user_data );
+		g_object_set_data( G_OBJECT( other ), NA_TOGGLE_DATA_EDITABLE, GUINT_TO_POINTER( editable ));
+		na_gtk_utils_set_editable( G_OBJECT( other ), editable );
+		gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( other ), FALSE );
+		gtk_widget_set_sensitive( GTK_WIDGET( other ), sensitive );
+	}
+
+	gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( button ), TRUE );
+}
+
+/**
+ * na_gtk_utils_radio_reset_initial_state:
+ * @button: the #GtkRadioButton being toggled.
+ * @handler: the corresponding "toggled" handler.
+ * @data: data associated with the @handler callback.
+ *
+ * When clicking on a read-only radio button, this function ensures that
+ * the radio button is not modified. It may be called whether the radio
+ * button group is editable or not (does nothing if group is actually
+ * editable).
+ */
+void
+na_gtk_utils_radio_reset_initial_state( GtkRadioButton *button, GCallback handler )
+{
+	GtkToggleButton *initial_button;
+	GCallback initial_handler;
+	gboolean active;
+	gboolean editable;
+	gpointer user_data;
+
+	active = gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON( button ));
+	editable = ( gboolean ) GPOINTER_TO_UINT( g_object_get_data( G_OBJECT( button ), NA_TOGGLE_DATA_EDITABLE ));
+
+	if( active && !editable ){
+		initial_button = GTK_TOGGLE_BUTTON( g_object_get_data( G_OBJECT( button ), NA_TOGGLE_DATA_BUTTON ));
+		initial_handler = G_CALLBACK( g_object_get_data( G_OBJECT( button ), NA_TOGGLE_DATA_HANDLER ));
+		user_data = g_object_get_data( G_OBJECT( button ), NA_TOGGLE_DATA_USER_DATA );
+
+		if( handler ){
+			g_signal_handlers_block_by_func(( gpointer ) button, handler, user_data );
+		}
+		g_signal_handlers_block_by_func(( gpointer ) initial_button, initial_handler, user_data );
+
+		gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( button ), FALSE );
+		gtk_toggle_button_set_active( initial_button, TRUE );
+
+		g_signal_handlers_unblock_by_func(( gpointer ) initial_button, initial_handler, user_data );
+		if( handler ){
+			g_signal_handlers_unblock_by_func(( gpointer ) button, handler, user_data );
+		}
+	}
+}
diff --git a/src/core/na-gtk-utils.h b/src/core/na-gtk-utils.h
index 7346283..1aa3953 100644
--- a/src/core/na-gtk-utils.h
+++ b/src/core/na-gtk-utils.h
@@ -54,10 +54,25 @@ void       na_gtk_utils_dump_children          ( GtkContainer *container );
 void       na_gtk_utils_restore_window_position( GtkWindow *toplevel, const gchar *wsp_name );
 void       na_gtk_utils_save_window_position   ( GtkWindow *toplevel, const gchar *wsp_name );
 
+/* widget status
+ */
+void       na_gtk_utils_set_editable( GObject *widget, gboolean editable );
+
+void       na_gtk_utils_radio_set_initial_state  ( GtkRadioButton *button,
+				GCallback toggled_handler, void *user_data,
+				gboolean editable, gboolean sensitive );
+
+void       na_gtk_utils_radio_reset_initial_state( GtkRadioButton *button, GCallback toggled_handler );
+
 /* default height of a panel bar (dirty hack!)
  */
 #define DEFAULT_HEIGHT		22
 
+#define NA_TOGGLE_DATA_EDITABLE			"na-toggle-data-editable"
+#define NA_TOGGLE_DATA_BUTTON			"na-toggle-data-button"
+#define NA_TOGGLE_DATA_HANDLER			"na-toggle-data-handler"
+#define NA_TOGGLE_DATA_USER_DATA		"na-toggle-data-user-data"
+
 G_END_DECLS
 
 #endif /* __CORE_API_NA_GTK_UTILS_H__ */
diff --git a/src/core/na-import-mode.c b/src/core/na-import-mode.c
new file mode 100644
index 0000000..98a6587
--- /dev/null
+++ b/src/core/na-import-mode.c
@@ -0,0 +1,193 @@
+/*
+ * 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, 2011 Pierre Wieser and others (see AUTHORS)
+ *
+ * This Program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this Library; see the file COPYING.  If not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place,
+ * Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Authors:
+ *   Frederic Ruaudel <grumz grumz net>
+ *   Rodrigo Moya <rodrigo gnome-db org>
+ *   Pierre Wieser <pwieser trychlos org>
+ *   ... and many others (see AUTHORS)
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "na-import-mode.h"
+#include "na-ioption.h"
+
+/* private class data
+ */
+struct _NAImportModeClassPrivate {
+	void *empty;						/* so that gcc -pedantic is happy */
+};
+
+/* private instance data
+ */
+struct _NAImportModePrivate {
+	gboolean     dispose_has_run;
+};
+
+static GObjectClass *st_parent_class = NULL;
+
+static GType  register_type( void );
+static void   class_init( NAImportModeClass *klass );
+static void   ioption_iface_init( NAIOptionInterface *iface );
+static guint  ioption_get_version( const NAIOption *instance );
+static void   instance_init( GTypeInstance *instance, gpointer klass );
+static void   instance_dispose( GObject *object );
+static void   instance_finalize( GObject *object );
+
+GType
+na_import_mode_get_type( void )
+{
+	static GType object_type = 0;
+
+	if( !object_type ){
+		object_type = register_type();
+	}
+
+	return( object_type );
+}
+
+static GType
+register_type( void )
+{
+	static const gchar *thisfn = "na_import_mode_register_type";
+	GType type;
+
+	static GTypeInfo info = {
+		sizeof( NAImportModeClass ),
+		( GBaseInitFunc ) NULL,
+		( GBaseFinalizeFunc ) NULL,
+		( GClassInitFunc ) class_init,
+		NULL,
+		NULL,
+		sizeof( NAImportMode ),
+		0,
+		( GInstanceInitFunc ) instance_init
+	};
+
+	g_debug( "%s", thisfn );
+
+	static const GInterfaceInfo ioption_iface_info = {
+		( GInterfaceInitFunc ) ioption_iface_init,
+		NULL,
+		NULL
+	};
+
+	type = g_type_register_static( G_TYPE_OBJECT, "NAImportMode", &info, 0 );
+
+	g_type_add_interface_static( type, NA_IOPTION_TYPE, &ioption_iface_info );
+
+	return( type );
+}
+
+static void
+class_init( NAImportModeClass *klass )
+{
+	static const gchar *thisfn = "na_import_mode_class_init";
+	GObjectClass *object_class;
+
+	g_debug( "%s: klass=%p", thisfn, ( void * ) klass );
+
+	st_parent_class = g_type_class_peek_parent( klass );
+
+	object_class = G_OBJECT_CLASS( klass );
+	object_class->dispose = instance_dispose;
+	object_class->finalize = instance_finalize;
+
+	klass->private = g_new0( NAImportModeClassPrivate, 1 );
+}
+
+static void
+ioption_iface_init( NAIOptionInterface *iface )
+{
+	static const gchar *thisfn = "na_import_mode_ioption_iface_init";
+
+	g_debug( "%s: iface=%p", thisfn, ( void * ) iface );
+
+	iface->get_version = ioption_get_version;
+}
+
+static guint
+ioption_get_version( const NAIOption *instance )
+{
+	return( 1 );
+}
+
+static void
+instance_init( GTypeInstance *instance, gpointer klass )
+{
+	static const gchar *thisfn = "na_import_mode_instance_init";
+	NAImportMode *self;
+
+	g_return_if_fail( NA_IS_IMPORT_MODE( instance ));
+
+	g_debug( "%s: instance=%p (%s), klass=%p",
+			thisfn, ( void * ) instance, G_OBJECT_TYPE_NAME( instance ), ( void * ) klass );
+	self = NA_IMPORT_MODE( instance );
+
+	self->private = g_new0( NAImportModePrivate, 1 );
+
+	self->private->dispose_has_run = FALSE;
+}
+
+static void
+instance_dispose( GObject *object )
+{
+	static const gchar *thisfn = "na_import_mode_instance_dispose";
+	NAImportMode *self;
+
+	g_return_if_fail( NA_IS_IMPORT_MODE( object ));
+
+	self = NA_IMPORT_MODE( object );
+
+	if( !self->private->dispose_has_run ){
+
+		g_debug( "%s: object=%p (%s)", thisfn, ( void * ) object, G_OBJECT_TYPE_NAME( object ));
+
+		self->private->dispose_has_run = TRUE;
+
+		/* chain up to the parent class */
+		if( G_OBJECT_CLASS( st_parent_class )->dispose ){
+			G_OBJECT_CLASS( st_parent_class )->dispose( object );
+		}
+	}
+}
+
+static void
+instance_finalize( GObject *object )
+{
+	static const gchar *thisfn = "na_import_mode_instance_finalize";
+	NAImportMode *self;
+
+	g_return_if_fail( NA_IS_IMPORT_MODE( object ));
+
+	g_debug( "%s: object=%p", thisfn, ( void * ) object );
+	self = NA_IMPORT_MODE( object );
+
+	/* chain call to parent class */
+	if( G_OBJECT_CLASS( st_parent_class )->finalize ){
+		G_OBJECT_CLASS( st_parent_class )->finalize( object );
+	}
+}
diff --git a/src/core/na-import-mode.h b/src/core/na-import-mode.h
new file mode 100644
index 0000000..64b0c63
--- /dev/null
+++ b/src/core/na-import-mode.h
@@ -0,0 +1,74 @@
+/*
+ * Nautilus-Actions
+ * A Nautilus extension which offers configurable context menu actions.
+ *
+ * Copyright (C) 2005 The GNOME Foundation
+ * Copyright (C) 2006, 2007, 2008 Frederic Ruaudel and others (see AUTHORS)
+ * Copyright (C) 2009, 2010, 2011 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 __CORE_NA_IMPORT_MODE_H__
+#define __CORE_NA_IMPORT_MODE_H__
+
+/* @title: NAImportMode
+ * @short_description: The #NAImportMode Class Definition
+ * @include: core/na-import-mode.h
+ *
+ * This class gathers and manages the different import modes we are able
+ * to deal with.
+ */
+
+#include <gdk-pixbuf/gdk-pixbuf.h>
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+#define NA_IMPORT_MODE_TYPE           ( na_import_mode_get_type())
+#define NA_IMPORT_MODE( o )           ( G_TYPE_CHECK_INSTANCE_CAST( o, NA_IMPORT_MODE_TYPE, NAImportMode ))
+#define NA_IMPORT_MODE_CLASS( c )     ( G_TYPE_CHECK_CLASS_CAST( c, NA_IMPORT_MODE_TYPE, NAImportModeClass ))
+#define NA_IS_IMPORT_MODE( o )        ( G_TYPE_CHECK_INSTANCE_TYPE( o, NA_IMPORT_MODE_TYPE ))
+#define NA_IS_IMPORT_MODE_CLASS( c )  ( G_TYPE_CHECK_CLASS_TYPE(( c ), NA_IMPORT_MODE_TYPE ))
+#define NA_IMPORT_MODE_GET_CLASS( o ) ( G_TYPE_INSTANCE_GET_CLASS(( o ), NA_IMPORT_MODE_TYPE, NAImportModeClass ))
+
+typedef struct _NAImportModePrivate        NAImportModePrivate;
+
+typedef struct {
+	GObject              parent;
+	NAImportModePrivate *private;
+}
+	NAImportMode;
+
+typedef struct _NAImportModeClassPrivate   NAImportModeClassPrivate;
+
+typedef struct {
+	GObjectClass              parent;
+	NAImportModeClassPrivate *private;
+}
+	NAImportModeClass;
+
+GType         na_import_mode_get_type( void );
+
+G_END_DECLS
+
+#endif /* __CORE_NA_IMPORT_MODE_H__ */
diff --git a/src/core/na-ioption.c b/src/core/na-ioption.c
new file mode 100644
index 0000000..6857d48
--- /dev/null
+++ b/src/core/na-ioption.c
@@ -0,0 +1,278 @@
+/*
+ * Nautilus-Actions
+ * A Nautilus extension which offers configurable context menu actions.
+ *
+ * Copyright (C) 2005 The GNOME Foundation
+ * Copyright (C) 2006, 2007, 2008 Frederic Ruaudel and others (see AUTHORS)
+ * Copyright (C) 2009, 2010, 2011 Pierre Wieser and others (see AUTHORS)
+ *
+ * This Program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this Library; see the file COPYING.  If not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place,
+ * Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Authors:
+ *   Frederic Ruaudel <grumz grumz net>
+ *   Rodrigo Moya <rodrigo gnome-db org>
+ *   Pierre Wieser <pwieser trychlos org>
+ *   ... and many others (see AUTHORS)
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "na-ioption.h"
+
+/* private interface data
+ */
+struct _NAIOptionInterfacePrivate {
+	void *empty;						/* so that gcc -pedantic is happy */
+};
+
+#define IOPTION_DATA_INITIALIZED		"ioption-data-initialized"
+
+static gboolean st_ioption_iface_initialized = FALSE;
+static gboolean st_ioption_iface_finalized   = FALSE;
+
+static GType    register_type( void );
+static void     interface_base_init( NAIOptionInterface *iface );
+static void     interface_base_finalize( NAIOptionInterface *iface );
+static guint    ioption_get_version( const NAIOption *instance );
+static void     check_for_initialized_instance( NAIOption *instance );
+static void     on_instance_finalized( gpointer user_data, GObject *instance );
+static gboolean option_get_initialized( NAIOption *instance );
+static void     option_set_initialized( NAIOption *instance, gboolean initialized );
+
+/**
+ * na_ioption_get_type:
+ *
+ * Returns: the #GType type of this interface.
+ */
+GType
+na_ioption_get_type( void )
+{
+	static GType type = 0;
+
+	if( !type ){
+		type = register_type();
+	}
+
+	return( type );
+}
+
+/*
+ * na_ioption_register_type:
+ *
+ * Registers this interface.
+ */
+static GType
+register_type( void )
+{
+	static const gchar *thisfn = "na_ioption_register_type";
+	GType type;
+
+	static const GTypeInfo info = {
+		sizeof( NAIOptionInterface ),
+		( GBaseInitFunc ) interface_base_init,
+		( GBaseFinalizeFunc ) interface_base_finalize,
+		NULL,
+		NULL,
+		NULL,
+		0,
+		0,
+		NULL
+	};
+
+	g_debug( "%s", thisfn );
+
+	type = g_type_register_static( G_TYPE_INTERFACE, "NAIOption", &info, 0 );
+
+	g_type_interface_add_prerequisite( type, G_TYPE_OBJECT );
+
+	return( type );
+}
+
+static void
+interface_base_init( NAIOptionInterface *iface )
+{
+	static const gchar *thisfn = "na_ioption_interface_base_init";
+
+	if( !st_ioption_iface_initialized ){
+
+		g_debug( "%s: iface=%p (%s)", thisfn, ( void * ) iface, G_OBJECT_CLASS_NAME( iface ));
+
+		iface->private = g_new0( NAIOptionInterfacePrivate, 1 );
+
+		iface->get_version = ioption_get_version;
+
+		st_ioption_iface_initialized = TRUE;
+	}
+}
+
+static void
+interface_base_finalize( NAIOptionInterface *iface )
+{
+	static const gchar *thisfn = "na_ioption_interface_base_finalize";
+
+	if( st_ioption_iface_initialized && !st_ioption_iface_finalized ){
+
+		g_debug( "%s: iface=%p", thisfn, ( void * ) iface );
+
+		st_ioption_iface_finalized = TRUE;
+
+		g_free( iface->private );
+	}
+}
+
+static guint
+ioption_get_version( const NAIOption *instance )
+{
+	return( 1 );
+}
+
+/*
+ * na_ioption_instance_init:
+ * @instance: the object which implements this #NAIOptionsList interface.
+ *
+ * Initialize all #NAIOptionsList-relative properties of the implementation
+ * object at instanciation time.
+ */
+static void
+check_for_initialized_instance( NAIOption *instance )
+{
+	static const gchar *thisfn = "na_ioption_check_for_initialized_instance";
+
+	if( !option_get_initialized( instance )){
+
+		g_debug( "%s: instance=%p", thisfn, ( void * ) instance );
+
+		g_object_weak_ref( G_OBJECT( instance ), ( GWeakNotify ) on_instance_finalized, NULL );
+
+		option_set_initialized( instance, TRUE );
+	}
+}
+
+static void
+on_instance_finalized( gpointer user_data, GObject *instance )
+{
+	static const gchar *thisfn = "na_ioption_on_instance_finalized";
+
+	g_debug( "%s: user_data=%p, instance=%p", thisfn, ( void * ) user_data, ( void * ) instance );
+}
+
+/* whether the instance has been initialized
+ *
+ * initializing the instance let us register a 'weak notify' signal on the instance
+ * we will so be able to free any allocated resources when the instance will be
+ * finalized
+ */
+static gboolean
+option_get_initialized( NAIOption *instance )
+{
+	gboolean initialized;
+
+	initialized = ( gboolean ) GPOINTER_TO_UINT( g_object_get_data( G_OBJECT( instance ), IOPTION_DATA_INITIALIZED ));
+
+	return( initialized );
+}
+
+static void
+option_set_initialized( NAIOption *instance, gboolean initialized )
+{
+	g_object_set_data( G_OBJECT( instance ), IOPTION_DATA_INITIALIZED, GUINT_TO_POINTER( initialized ));
+}
+
+/*
+ * na_ioption_get_description:
+ * @format: this #NAExportFormat object.
+ *
+ * Returns: the UTF-8 localizable description of the format, as a newly
+ * allocated string which should be g_free() by the caller.
+ */
+gchar *
+na_ioption_get_description( const NAIOption *option )
+{
+	gchar *description;
+
+	g_return_val_if_fail( NA_IS_IOPTION( option ), NULL );
+
+	check_for_initialized_instance( NA_IOPTION( option ));
+	description = NULL;
+
+	if( NA_IOPTION_GET_INTERFACE( option )->get_description ){
+		description = NA_IOPTION_GET_INTERFACE( option )->get_description( option );
+	}
+
+	return( description );
+}
+
+/*
+ * na_ioption_get_label:
+ * @option: this #NAIOption instance.
+ *
+ * Returns: the UTF-8 localizable label of the format, as a newly
+ * allocated string which should be g_free() by the caller.
+ */
+gchar *
+na_ioption_get_label( const NAIOption *option )
+{
+	gchar *label;
+
+	g_return_val_if_fail( NA_IS_IOPTION( option ), NULL );
+
+	check_for_initialized_instance( NA_IOPTION( option ));
+	label = NULL;
+
+	if( NA_IOPTION_GET_INTERFACE( option )->get_label ){
+		label = NA_IOPTION_GET_INTERFACE( option )->get_label( option );
+	}
+
+	return( label );
+}
+
+/*
+ * na_ioption_get_pixbuf:
+ * @option: this #NAIOption instance.
+ *
+ * Returns: a new reference to the #GdkPixbuf image associated with this format,
+ * or %NULL.
+ */
+GdkPixbuf *
+na_ioption_get_pixbuf( const NAIOption *option )
+{
+	GdkPixbuf *pixbuf;
+
+	g_return_val_if_fail( NA_IS_IOPTION( option ), NULL );
+
+	check_for_initialized_instance( NA_IOPTION( option ));
+	pixbuf = NULL;
+
+	if( NA_IOPTION_GET_INTERFACE( option )->get_pixbuf ){
+		pixbuf = NA_IOPTION_GET_INTERFACE( option )->get_pixbuf( option );
+	}
+
+	return( pixbuf );
+}
+
+/*
+ * na_ioption_free_option:
+ * @option: this #NAIOption instance.
+ *
+ * Release the resources associated to the @option.
+ */
+void
+na_ioption_free_option( NAIOption *option )
+{
+	g_return_if_fail( NA_IS_IOPTION( option ));
+}
diff --git a/src/core/na-ioption.h b/src/core/na-ioption.h
new file mode 100644
index 0000000..dece761
--- /dev/null
+++ b/src/core/na-ioption.h
@@ -0,0 +1,164 @@
+/*
+ * Nautilus-Actions
+ * A Nautilus extension which offers configurable context menu actions.
+ *
+ * Copyright (C) 2005 The GNOME Foundation
+ * Copyright (C) 2006, 2007, 2008 Frederic Ruaudel and others (see AUTHORS)
+ * Copyright (C) 2009, 2010, 2011 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 __CORE_NA_IOPTION_H__
+#define __CORE_NA_IOPTION_H__
+
+/*
+ * SECTION: ioptions
+ * @title: NAIOption
+ * @short_description: The Option Interface v 1
+ * @include: core/na-ioption.h
+ *
+ * The #NAIOption interface is to be implemented by #GObject -derived object which
+ * are part of a #NAIOptionsList interface.
+ *
+ * <refsect2>
+ *  <title>Versions historic</title>
+ *  <table>
+ *    <title>Historic of the versions of the #NAIOption interface</title>
+ *    <tgroup rowsep="1" colsep="1" align="center" cols="3">
+ *      <colspec colname="na-version" />
+ *      <colspec colname="api-version" />
+ *      <colspec colname="current" />
+ *      <thead>
+ *        <row>
+ *          <entry>&prodname; version</entry>
+ *          <entry>#NAIOption interface version</entry>
+ *          <entry></entry>
+ *        </row>
+ *      </thead>
+ *      <tbody>
+ *        <row>
+ *          <entry>since 3.2</entry>
+ *          <entry>1</entry>
+ *          <entry>current version</entry>
+ *        </row>
+ *      </tbody>
+ *    </tgroup>
+ *  </table>
+ * </refsect2>
+ */
+
+#include "gdk-pixbuf/gdk-pixbuf.h"
+
+G_BEGIN_DECLS
+
+#define NA_IOPTION_TYPE               ( na_ioption_get_type())
+#define NA_IOPTION( i )               ( G_TYPE_CHECK_INSTANCE_CAST( i, NA_IOPTION_TYPE, NAIOption ))
+#define NA_IS_IOPTION( i )            ( G_TYPE_CHECK_INSTANCE_TYPE( i, NA_IOPTION_TYPE ))
+#define NA_IOPTION_GET_INTERFACE( i ) ( G_TYPE_INSTANCE_GET_INTERFACE(( i ), NA_IOPTION_TYPE, NAIOptionInterface ))
+
+typedef struct _NAIOption                      NAIOption;
+typedef struct _NAIOptionInterfacePrivate      NAIOptionInterfacePrivate;
+typedef struct _NAIOptionImportFromUriParms    NAIOptionImportFromUriParms;
+typedef struct _NAIOptionManageImportModeParms NAIOptionManageImportModeParms;
+
+/*
+ * NAIOptionInterface:
+ * @get_version:     returns the version of this interface that the
+ *                   instance implements.
+ * @get_description: returns the description of the option.
+ * @get_label:       returns the label of the option.
+ * @get_pixbuf:      returns the image associated to the option.
+ *
+ * This defines the interface that a #NAIOption implementation should provide.
+ */
+typedef struct {
+	/*< private >*/
+	GTypeInterface             parent;
+	NAIOptionInterfacePrivate *private;
+
+	/*< public >*/
+	/*
+	 * get_version:
+	 * @instance: the #NAIOption instance of the implementation.
+	 *
+	 * This method is supposed to let know to any caller which version of this
+	 * interface the implementation provides. This may be useful when this
+	 * interface will itself be upgraded.
+	 *
+	 * If this method is not provided by the implementation, one should suppose
+	 * that the implemented version is at last the version 1.
+	 *
+	 * Returns: the version of this interface provided by the implementation.
+	 *
+	 * Since: 3.2
+	 */
+	guint       ( *get_version )    ( const NAIOption *instance );
+
+	/*
+	 * get_description:
+	 * @instance: the #NAIOption instance of the implementation.
+	 *
+	 * Returns: the description of the option, as a newly allocated string
+	 * which should be g_free() by the caller.
+	 *
+	 * Since: 3.2
+	 */
+	gchar *     ( *get_description )( const NAIOption *instance );
+
+	/*
+	 * get_label:
+	 * @instance: the #NAIOption instance of the implementation.
+	 *
+	 * Returns: the label of the option, as a newly allocated string
+	 * which should be g_free() by the caller.
+	 *
+	 * Since: 3.2
+	 */
+	gchar *     ( *get_label )      ( const NAIOption *instance );
+
+	/*
+	 * get_pixbuf:
+	 * @instance: the #NAIOption instance of the implementation.
+	 *
+	 * Returns: the image assocated to the option, as a newly allocated string
+	 * which should be g_object_unref() by the caller.
+	 *
+	 * Since: 3.2
+	 */
+	GdkPixbuf * ( *get_pixbuf )     ( const NAIOption *instance );
+}
+	NAIOptionInterface;
+
+#define NA_IOPTION_PROP_OPTION
+
+GType      na_ioption_get_type( void );
+
+gchar     *na_ioption_get_description( const NAIOption *option );
+gchar     *na_ioption_get_label      ( const NAIOption *option );
+GdkPixbuf *na_ioption_get_pixbuf     ( const NAIOption *option );
+
+void       na_ioption_free_option    ( NAIOption *option );
+
+G_END_DECLS
+
+#endif /* __CORE_NA_IOPTION_H__ */
diff --git a/src/core/na-ioptions-list.c b/src/core/na-ioptions-list.c
new file mode 100644
index 0000000..186dde8
--- /dev/null
+++ b/src/core/na-ioptions-list.c
@@ -0,0 +1,818 @@
+/*
+ * 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, 2011 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-core-utils.h>
+
+#include "na-gtk-utils.h"
+#include "na-ioptions-list.h"
+
+/* private interface data
+ */
+struct _NAIOptionsListInterfacePrivate {
+	void *empty;						/* so that gcc -pedantic is happy */
+};
+
+/* column ordering in the tree view mode
+ */
+enum {
+	IMAGE_COLUMN = 0,
+	LABEL_COLUMN,
+	TOOLTIP_COLUMN,
+	OBJECT_COLUMN,
+	N_COLUMN
+};
+
+#define IOPTIONS_LIST_DATA_CONTAINER		"ioptions-list-data-container"
+#define IOPTIONS_LIST_DATA_EDITABLE			"ioptions-list-data-editable"
+#define IOPTIONS_LIST_DATA_INITIALIZED		"ioptions-list-data-initialized"
+#define IOPTIONS_LIST_DATA_OPTION			"ioptions-list-data-option"
+#define IOPTIONS_LIST_DATA_PARENT			"ioptions-list-data-parent"
+#define IOPTIONS_LIST_DATA_SENSITIVE		"ioptions-list-data-sensitive"
+#define IOPTIONS_LIST_DATA_WITH_ASK			"ioptions-list-data-with-ask"
+
+static gboolean st_ioptions_list_iface_initialized = FALSE;
+static gboolean st_ioptions_list_iface_finalized   = FALSE;
+
+static GType      register_type( void );
+static void       interface_base_init( NAIOptionsListInterface *iface );
+static void       interface_base_finalize( NAIOptionsListInterface *iface );
+static guint      ioptions_list_get_version( const NAIOptionsList *instance );
+static void       ioptions_list_free_options( const NAIOptionsList *instance, GList *options );
+static void       ioptions_list_free_ask_option( const NAIOptionsList *instance, NAIOption *option );
+static GList     *options_list_get_options( const NAIOptionsList *instance );
+static void       options_list_free_options( const NAIOptionsList *instance, GList *options );
+static NAIOption *options_list_get_ask_option( const NAIOptionsList *instance );
+static void       options_list_free_ask_option( const NAIOptionsList *instance, NAIOption *ask_option );
+static NAIOption *options_list_get_container_option( GtkWidget *container );
+static void       options_list_set_container_option( GtkWidget *container, const NAIOption *option );
+static GtkWidget *options_list_get_container_parent( NAIOptionsList *instance );
+static void       options_list_set_container_parent( NAIOptionsList *instance, GtkWidget *parent );
+static gboolean   options_list_get_editable( NAIOptionsList *instance );
+static void       options_list_set_editable( NAIOptionsList *instance, gboolean editable );
+static gboolean   options_list_get_initialized( NAIOptionsList *instance );
+static void       options_list_set_initialized( NAIOptionsList *instance, gboolean initialized );
+static NAIOption *options_list_get_option( NAIOptionsList *instance );
+static void       options_list_set_option( NAIOptionsList *instance, NAIOption *option );
+static gboolean   options_list_get_sensitive( NAIOptionsList *instance );
+static void       options_list_set_sensitive( NAIOptionsList *instance, gboolean sensitive );
+static gboolean   options_list_get_with_ask( NAIOptionsList *instance );
+static void       options_list_set_with_ask( NAIOptionsList *instance, gboolean with_ask );
+static void       check_for_initialized_instance( NAIOptionsList *instance );
+static void       on_instance_finalized( gpointer user_data, GObject *instance );
+static void       radio_button_create_group( NAIOptionsList *instance );
+static void       radio_button_draw_vbox( GtkWidget *container_parent, const NAIOption *option );
+static void       radio_button_weak_notify( NAIOption *option, GObject *vbox );
+static void       tree_view_create_model( NAIOptionsList *instance );
+static void       tree_view_populate( NAIOptionsList *instance );
+static void       tree_view_add_item( GtkTreeView *listview, GtkTreeModel *model, const NAIOption *option );
+static void       tree_view_weak_notify( GtkTreeModel *model, GObject *tree_view );
+static void       radio_button_select_iter( GtkWidget *container_option, NAIOptionsList *instance );
+static gboolean   tree_view_select_iter( GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, NAIOptionsList *instance );
+
+/**
+ * na_ioptions_list_get_type:
+ *
+ * Returns: the #GType type of this interface.
+ */
+GType
+na_ioptions_list_get_type( void )
+{
+	static GType type = 0;
+
+	if( !type ){
+		type = register_type();
+	}
+
+	return( type );
+}
+
+/*
+ * na_ioptions_list_register_type:
+ *
+ * Registers this interface.
+ */
+static GType
+register_type( void )
+{
+	static const gchar *thisfn = "na_ioptions_list_register_type";
+	GType type;
+
+	static const GTypeInfo info = {
+		sizeof( NAIOptionsListInterface ),
+		( GBaseInitFunc ) interface_base_init,
+		( GBaseFinalizeFunc ) interface_base_finalize,
+		NULL,
+		NULL,
+		NULL,
+		0,
+		0,
+		NULL
+	};
+
+	g_debug( "%s", thisfn );
+
+	type = g_type_register_static( G_TYPE_INTERFACE, "NAIOptionsList", &info, 0 );
+
+	g_type_interface_add_prerequisite( type, G_TYPE_OBJECT );
+
+	return( type );
+}
+
+static void
+interface_base_init( NAIOptionsListInterface *iface )
+{
+	static const gchar *thisfn = "na_ioptions_list_interface_base_init";
+
+	if( !st_ioptions_list_iface_initialized ){
+
+		g_debug( "%s: iface=%p (%s)", thisfn, ( void * ) iface, G_OBJECT_CLASS_NAME( iface ));
+
+		iface->private = g_new0( NAIOptionsListInterfacePrivate, 1 );
+
+		iface->get_version = ioptions_list_get_version;
+		iface->get_options = NULL;
+		iface->free_options = ioptions_list_free_options;
+		iface->get_ask_option = NULL;
+		iface->free_ask_option = ioptions_list_free_ask_option;
+
+		st_ioptions_list_iface_initialized = TRUE;
+	}
+}
+
+static void
+interface_base_finalize( NAIOptionsListInterface *iface )
+{
+	static const gchar *thisfn = "na_ioptions_list_interface_base_finalize";
+
+	if( st_ioptions_list_iface_initialized && !st_ioptions_list_iface_finalized ){
+
+		g_debug( "%s: iface=%p", thisfn, ( void * ) iface );
+
+		st_ioptions_list_iface_finalized = TRUE;
+
+		g_free( iface->private );
+	}
+}
+
+/*
+ * defaults implemented by the interface
+ */
+static guint
+ioptions_list_get_version( const NAIOptionsList *instance )
+{
+	return( 1 );
+}
+
+static void
+ioptions_list_free_options( const NAIOptionsList *instance, GList *options )
+{
+	static const gchar *thisfn = "na_ioptions_list_free_options";
+
+	g_debug( "%s: instance=%p, options=%p", thisfn, ( void * ) instance, ( void * ) options );
+
+	g_list_foreach( options, ( GFunc ) g_object_unref, NULL );
+	g_list_free( options );
+}
+
+static void
+ioptions_list_free_ask_option( const NAIOptionsList *instance, NAIOption *ask_option )
+{
+	static const gchar *thisfn = "na_ioptions_list_free_ask_option";
+
+	g_debug( "%s: instance=%p, ask_option=%p", thisfn, ( void * ) instance, ( void * ) ask_option );
+
+	g_object_unref( ask_option );
+}
+
+/*
+ * call these functions will trigger either the implementation method
+ * or the default provided by the interface
+ */
+static GList *
+options_list_get_options( const NAIOptionsList *instance )
+{
+	GList *options;
+
+	options = NULL;
+
+	if( NA_IOPTIONS_LIST_GET_INTERFACE( instance )->get_options ){
+		options = NA_IOPTIONS_LIST_GET_INTERFACE( instance )->get_options( instance );
+	}
+
+	return( options );
+}
+
+static void
+options_list_free_options( const NAIOptionsList *instance, GList *options )
+{
+	if( NA_IOPTIONS_LIST_GET_INTERFACE( instance )->free_options ){
+		NA_IOPTIONS_LIST_GET_INTERFACE( instance )->free_options( instance, options );
+	}
+}
+
+static NAIOption *
+options_list_get_ask_option( const NAIOptionsList *instance )
+{
+	NAIOption *option;
+
+	option = NULL;
+
+	if( NA_IOPTIONS_LIST_GET_INTERFACE( instance )->get_ask_option ){
+		option = NA_IOPTIONS_LIST_GET_INTERFACE( instance )->get_ask_option( instance );
+	}
+
+	return( option );
+}
+
+static void
+options_list_free_ask_option( const NAIOptionsList *instance, NAIOption *ask_option )
+{
+	if( NA_IOPTIONS_LIST_GET_INTERFACE( instance )->free_ask_option ){
+		NA_IOPTIONS_LIST_GET_INTERFACE( instance )->free_ask_option( instance, ask_option );
+	}
+}
+
+/*
+ * get/set properties
+ */
+/* the option associated to this 'option' container
+ */
+static NAIOption *
+options_list_get_container_option( GtkWidget *container )
+{
+	NAIOption *option;
+
+	option = ( NAIOption * ) g_object_get_data( G_OBJECT( container ), IOPTIONS_LIST_DATA_CONTAINER );
+
+	return( option );
+}
+
+static void
+options_list_set_container_option( GtkWidget *container, const NAIOption *option )
+{
+	g_object_set_data( G_OBJECT( container ), IOPTIONS_LIST_DATA_CONTAINER, ( gpointer ) option );
+}
+
+/* the global parent container, i.e. a GtkVBox or a GtkTreeView
+ *
+ * the container parent is provided when calling na_ioptions_list_display_init()
+ * function; storing it as a data of the instance just let us to know it without
+ * having to require it in subsequent function calls
+ */
+static GtkWidget *
+options_list_get_container_parent( NAIOptionsList *instance )
+{
+	GtkWidget *parent;
+
+	parent = ( GtkWidget * ) g_object_get_data( G_OBJECT( instance ), IOPTIONS_LIST_DATA_PARENT );
+
+	return( parent );
+}
+
+static void
+options_list_set_container_parent( NAIOptionsList *instance, GtkWidget *parent )
+{
+	g_object_set_data( G_OBJECT( instance ), IOPTIONS_LIST_DATA_PARENT, parent );
+}
+
+/* whether the selectable user's preference is editable
+ *
+ * most of the time, a user's preference is not editable if it is set as mandatory,
+ * or if the whole user's preference are not writable
+ */
+static gboolean
+options_list_get_editable( NAIOptionsList *instance )
+{
+	gboolean editable;
+
+	editable = ( gboolean ) GPOINTER_TO_UINT( g_object_get_data( G_OBJECT( instance ), IOPTIONS_LIST_DATA_EDITABLE ));
+
+	return( editable );
+}
+
+static void
+options_list_set_editable( NAIOptionsList *instance, gboolean editable )
+{
+	g_object_set_data( G_OBJECT( instance ), IOPTIONS_LIST_DATA_EDITABLE, GUINT_TO_POINTER( editable ));
+}
+
+/* whether the instance has been initialized
+ *
+ * initializing the instance let us register a 'weak notify' signal on the instance
+ * we will so be able to free any allocated resources when the instance will be
+ * finalized
+ */
+static gboolean
+options_list_get_initialized( NAIOptionsList *instance )
+{
+	gboolean initialized;
+
+	initialized = ( gboolean ) GPOINTER_TO_UINT( g_object_get_data( G_OBJECT( instance ), IOPTIONS_LIST_DATA_INITIALIZED ));
+
+	return( initialized );
+}
+
+static void
+options_list_set_initialized( NAIOptionsList *instance, gboolean initialized )
+{
+	g_object_set_data( G_OBJECT( instance ), IOPTIONS_LIST_DATA_INITIALIZED, GUINT_TO_POINTER( initialized ));
+}
+
+/* the current option
+ */
+static NAIOption *
+options_list_get_option( NAIOptionsList *instance )
+{
+	NAIOption *option;
+
+	option = ( NAIOption * ) g_object_get_data( G_OBJECT( instance ), IOPTIONS_LIST_DATA_OPTION );
+
+	return( option );
+}
+
+static void
+options_list_set_option( NAIOptionsList *instance, NAIOption *option )
+{
+	g_object_set_data( G_OBJECT( instance ), IOPTIONS_LIST_DATA_OPTION, option );
+}
+
+/* whether the selectable user's preference is sensitive
+ *
+ * an option should be made insensitive when it is not relevant in
+ * the considered case
+ */
+static gboolean
+options_list_get_sensitive( NAIOptionsList *instance )
+{
+	gboolean sensitive;
+
+	sensitive = ( gboolean ) GPOINTER_TO_UINT( g_object_get_data( G_OBJECT( instance ), IOPTIONS_LIST_DATA_SENSITIVE ));
+
+	return( sensitive );
+}
+
+static void
+options_list_set_sensitive( NAIOptionsList *instance, gboolean sensitive )
+{
+	g_object_set_data( G_OBJECT( instance ), IOPTIONS_LIST_DATA_SENSITIVE, GUINT_TO_POINTER( sensitive ));
+}
+
+/* whether the options list must include an 'Ask me' option
+ */
+static gboolean
+options_list_get_with_ask( NAIOptionsList *instance )
+{
+	gboolean with_ask;
+
+	with_ask = ( gboolean ) GPOINTER_TO_UINT( g_object_get_data( G_OBJECT( instance ), IOPTIONS_LIST_DATA_WITH_ASK ));
+
+	return( with_ask );
+}
+
+static void
+options_list_set_with_ask( NAIOptionsList *instance, gboolean with_ask )
+{
+	g_object_set_data( G_OBJECT( instance ), IOPTIONS_LIST_DATA_WITH_ASK, GUINT_TO_POINTER( with_ask ));
+}
+
+/*
+ * na_ioptions_list_instance_init:
+ * @instance: the object which implements this #NAIOptionsList interface.
+ *
+ * Initialize all #NAIOptionsList-relative properties of the implementation
+ * object at instanciation time.
+ */
+static void
+check_for_initialized_instance( NAIOptionsList *instance )
+{
+	static const gchar *thisfn = "na_ioptions_list_check_for_initialized_instance";
+
+	if( !options_list_get_initialized( instance )){
+
+		g_debug( "%s: instance=%p", thisfn, ( void * ) instance );
+
+		g_object_weak_ref( G_OBJECT( instance ), ( GWeakNotify ) on_instance_finalized, NULL );
+
+		options_list_set_initialized( instance, TRUE );
+	}
+}
+
+static void
+on_instance_finalized( gpointer user_data, GObject *instance )
+{
+	static const gchar *thisfn = "na_ioptions_list_on_instance_finalized";
+
+	g_debug( "%s: user_data=%p, instance=%p", thisfn, ( void * ) user_data, ( void * ) instance );
+}
+
+/*
+ * na_ioptions_list_display_init:
+ * @instance: the object which implements this #NAIOptionsList interface.
+ * @parent: the #GtkWidget container_parent is which we are goint to setup the items
+ *  list. @parent may be a #GtkVBox or a #GtkTreeView.
+ * @with_ask: whether we should also display an 'Ask me' option.
+ * @editable: whether the selectable user's preference is editable;
+ *  Most of time, a user's preference is not editable if it is set as mandatory,
+ *  or if the whole user's preferences are not writable.
+ * @sensitive: whether the radio button group is to be sensitive;
+ *  a widget should not be sensitive if the selectable option is not relevant
+ *  in the considered case.
+ *
+ * Initialize the gtk objects which will be used to display the selection.
+ */
+void
+na_ioptions_list_display_init( NAIOptionsList *instance,
+		GtkWidget *parent, gboolean with_ask, gboolean editable, gboolean sensitive )
+{
+	static const gchar *thisfn = "na_ioptions_list_display_init";
+
+	g_return_if_fail( st_ioptions_list_iface_initialized && !st_ioptions_list_iface_finalized );
+
+	check_for_initialized_instance( instance );
+
+	g_debug( "%s: instance=%p (%s), parent=%p (%s), with_ask=%s, editable=%s, sensitive=%s",
+			thisfn,
+			( void * ) instance, G_OBJECT_TYPE_NAME( instance ),
+			( void * ) parent, G_OBJECT_TYPE_NAME( parent ),
+			with_ask ? "True":"False",
+			editable ? "True":"False",
+			sensitive ? "True":"False" );
+
+	options_list_set_container_parent( instance, parent );
+	options_list_set_with_ask( instance, with_ask );
+	options_list_set_editable( instance, editable );
+	options_list_set_sensitive( instance, sensitive );
+
+	if( GTK_IS_BOX( parent )){
+		radio_button_create_group( instance );
+
+	} else if( GTK_IS_TREE_VIEW( parent )){
+		tree_view_create_model( instance );
+		tree_view_populate( instance );
+
+	} else {
+		g_warning( "%s: unknown parent type: %s", thisfn, G_OBJECT_TYPE_NAME( parent ));
+	}
+}
+
+static void
+radio_button_create_group( NAIOptionsList *instance )
+{
+	static const gchar *thisfn = "na_ioptions_list_create_radio_button_group";
+	GList *options, *iopt;
+	NAIOption *option;
+	GtkWidget *parent;
+
+	g_debug( "%s: instance=%p", thisfn, ( void * ) instance );
+
+	parent = options_list_get_container_parent( instance );
+	options = options_list_get_options( instance );
+
+	/* draw the formats as a group of radio buttons
+	 */
+	for( iopt = options ; iopt ; iopt = iopt->next ){
+		radio_button_draw_vbox( parent, NA_IOPTION( iopt->data ));
+	}
+
+	options_list_free_options( instance, options );
+
+	/* eventually add the 'Ask me' mode
+	 */
+	if( options_list_get_with_ask( instance )){
+		option = options_list_get_ask_option( instance );
+		radio_button_draw_vbox( parent, option );
+		options_list_free_ask_option( instance, option );
+	}
+}
+
+/*
+ * @container_parent_parent used to be a glade-defined GtkVBox in which we dynamically
+ * add for each mode:
+ *  +- vbox
+ *  |   +- radio button + label
+ *  |   +- hbox
+ *  |   |   +- description (assistant mode only)
+ *
+ *  Starting with Gtk 3.2, container_parent is a GtkGrid attached to the
+ *  glade-defined GtkVBox. For each mode, we are defining:
+ *  +- grid
+ *  |   +- radio button
+ *  |   +- description (assistant mode only)
+ *
+ *  id=-1 but for the 'Ask me' mode
+ */
+static void
+radio_button_draw_vbox( GtkWidget *container_parent, const NAIOption *option )
+{
+#if 0
+	static const gchar *thisfn = "na_ioptions_list_radio_button_draw_vbox";
+#endif
+	static GtkRadioButton *first_button = NULL;
+	GtkWidget *container_option;
+	gchar *description;
+	GtkRadioButton *button;
+	gchar *label;
+
+#if GTK_CHECK_VERSION( 3,2,0 )
+	/* create a grid container_parent which will embed two lines */
+	container_option = gtk_grid_new();
+#else
+	/* create a vbox which will embed two children */
+	container_option = gtk_vbox_new( FALSE, 0 );
+#endif
+	gtk_box_pack_start( GTK_BOX( container_parent ), container_option, FALSE, TRUE, 0 );
+	description = na_ioption_get_description( option );
+	g_object_set( G_OBJECT( container_option ), "tooltip-text", description, NULL );
+	g_free( description );
+
+	/* first line/child is the radio button
+	 */
+	button = GTK_RADIO_BUTTON( gtk_radio_button_new( NULL ));
+	if( !first_button ){
+		first_button = button;
+	}
+	g_object_set( G_OBJECT( button ), "group", first_button, NULL );
+
+#if GTK_CHECK_VERSION( 3, 2, 0 )
+	gtk_grid_attach( GTK_GRID( container_option ), GTK_WIDGET( button ), 0, 0, 1, 1 );
+#else
+	gtk_box_pack_start( GTK_BOX( container_option ), GTK_WIDGET( button ), FALSE, TRUE, 0 );
+#endif
+
+	label = na_ioption_get_label( option );
+	gtk_button_set_label( GTK_BUTTON( button ), label );
+	g_free( label );
+	gtk_button_set_use_underline( GTK_BUTTON( button ), TRUE );
+
+#if 0
+	vbox_data = g_new0( VBoxData, 1 );
+	g_debug( "%s: container_option=%p, allocating VBoxData at %p",
+			thisfn, ( void * ) container_option, ( void * ) vbox_data );
+
+	vbox_data->container_parent_vbox = container_parent;
+	vbox_data->button = button;
+	vbox_data->format = g_object_ref(( gpointer ) format );
+
+	g_object_set_data( G_OBJECT( container_option ), EXPORT_FORMAT_PROP_VBOX_DATA, vbox_data );
+	g_object_weak_ref( G_OBJECT( container_option ), ( GWeakNotify ) format_weak_notify, ( gpointer ) vbox_data );
+#endif
+
+	options_list_set_container_option( container_option, option );
+	g_object_weak_ref( G_OBJECT( container_option ), ( GWeakNotify ) radio_button_weak_notify, ( gpointer ) option );
+}
+
+/*
+ * release the data structure attached to each individual 'option' container
+ * when destroying the window
+ */
+static void
+radio_button_weak_notify( NAIOption *option, GObject *vbox )
+{
+	static const gchar *thisfn = "na_iptions_list_radio_button_weak_notify";
+
+	g_debug( "%s: option=%p, vbox=%p", thisfn, ( void * ) option, ( void * ) vbox );
+
+	na_ioption_free_option( option );
+}
+
+static void
+tree_view_create_model( NAIOptionsList *instance )
+{
+	static const gchar *thisfn = "na_ioptions_list_tree_view_create_model";
+	GtkWidget *parent;
+	GtkListStore *model;
+	GtkTreeViewColumn *column;
+	GtkTreeSelection *selection;
+
+	parent = options_list_get_container_parent( instance );
+	g_return_if_fail( GTK_IS_TREE_VIEW( parent ));
+
+	g_debug( "%s: instance=%p, parent=%p", thisfn, ( void * ) instance, ( void * ) parent );
+
+	model = gtk_list_store_new( N_COLUMN, GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_OBJECT );
+	gtk_tree_view_set_model( GTK_TREE_VIEW( parent ), GTK_TREE_MODEL( model ));
+	g_object_unref( model );
+
+	/* create visible columns on the tree view
+	 */
+	column = gtk_tree_view_column_new_with_attributes(
+			"image",
+			gtk_cell_renderer_pixbuf_new(),
+			"pixbuf", IMAGE_COLUMN,
+			NULL );
+	gtk_tree_view_append_column( GTK_TREE_VIEW( parent ), column );
+
+	column = gtk_tree_view_column_new_with_attributes(
+			"label",
+			gtk_cell_renderer_text_new(),
+			"text", LABEL_COLUMN,
+			NULL );
+	gtk_tree_view_append_column( GTK_TREE_VIEW( parent ), column );
+
+	g_object_set( G_OBJECT( parent ), "tooltip-column", TOOLTIP_COLUMN, NULL );
+
+	selection = gtk_tree_view_get_selection( GTK_TREE_VIEW( parent ));
+	gtk_tree_selection_set_mode( selection, GTK_SELECTION_BROWSE );
+
+	g_object_weak_ref( G_OBJECT( parent ), ( GWeakNotify ) tree_view_weak_notify, ( gpointer ) model );
+}
+
+static void
+tree_view_populate( NAIOptionsList *instance )
+{
+	static const gchar *thisfn = "nact_export_format_tree_view_populate";
+	GtkWidget *parent;
+	GtkTreeModel *model;
+	NAIOption *option;
+	GList *options, *iopt;
+
+	parent = options_list_get_container_parent( instance );
+	g_return_if_fail( GTK_IS_TREE_VIEW( parent ));
+
+	g_debug( "%s: instance=%p, parent=%p", thisfn, ( void * ) instance, ( void * ) parent );
+
+	model = gtk_tree_view_get_model( GTK_TREE_VIEW( parent ));
+	options = options_list_get_options( instance );
+
+	for( iopt = options ; iopt ; iopt = iopt->next ){
+		option = NA_IOPTION( iopt->data );
+		tree_view_add_item( GTK_TREE_VIEW( parent ), model, option );
+	}
+
+	/* eventually add the 'Ask me' mode
+	 */
+	if( options_list_get_with_ask( instance )){
+		option = options_list_get_ask_option( instance );
+		tree_view_add_item( GTK_TREE_VIEW( parent ), model, option );
+		options_list_free_ask_option( instance, option );
+	}
+}
+
+static void
+tree_view_add_item( GtkTreeView *listview, GtkTreeModel *model, const NAIOption *option )
+{
+	GtkTreeIter iter;
+	gchar *label, *label2, *description;
+	GdkPixbuf *pixbuf;
+
+	label = na_ioption_get_label( option );
+	label2 = na_core_utils_str_remove_char( label, "_" );
+	description = na_ioption_get_description( option );
+	pixbuf = na_ioption_get_pixbuf( option );
+	gtk_list_store_append( GTK_LIST_STORE( model ), &iter );
+	gtk_list_store_set(
+			GTK_LIST_STORE( model ),
+			&iter,
+			IMAGE_COLUMN, pixbuf,
+			LABEL_COLUMN, label2,
+			TOOLTIP_COLUMN, description,
+			OBJECT_COLUMN, option,
+			-1 );
+	if( pixbuf ){
+		g_object_unref( pixbuf );
+	}
+	g_free( label );
+	g_free( label2 );
+	g_free( description );
+}
+
+/*
+ * release the data structure attached to each individual 'option' container
+ * when destroying the window
+ */
+static void
+tree_view_weak_notify( GtkTreeModel *model, GObject *tree_view )
+{
+	static const gchar *thisfn = "na_iptions_list_tree_view_weak_notify";
+
+	g_debug( "%s: model=%p, tree_view=%p", thisfn, ( void * ) model, ( void * ) tree_view );
+
+	gtk_list_store_clear( GTK_LIST_STORE( model ));
+}
+
+/*
+ * na_ioptions_list_set_default:
+ * @instance: the object which implements this #NAIOptionsList interface.
+ * @default_option: the #NAIOption to be set as the default.
+ *
+ * Set the default, either of the radio button group or of the tree view.
+ */
+void
+na_ioptions_list_set_default( NAIOptionsList *instance, NAIOption *default_option )
+{
+	static const gchar *thisfn = "na_ioptions_list_set_default";
+	GtkWidget *parent;
+	GtkTreeModel *model;
+
+	if( st_ioptions_list_iface_initialized && !st_ioptions_list_iface_finalized ){
+		g_debug( "%s: instance=%p (%s), default_option=%p (%s)",
+				thisfn,
+				( void * ) instance, G_OBJECT_TYPE_NAME( instance ),
+				( void * ) default_option, G_OBJECT_TYPE_NAME( default_option ));
+
+		parent = options_list_get_container_parent( instance );
+		g_return_if_fail( GTK_IS_WIDGET( parent ));
+
+		options_list_set_option( instance, default_option );
+
+		if( GTK_IS_BOX( parent )){
+			gtk_container_foreach( GTK_CONTAINER( parent ),
+					( GtkCallback ) radio_button_select_iter, instance );
+
+		} else if( GTK_IS_TREE_VIEW( parent )){
+			model = gtk_tree_view_get_model( GTK_TREE_VIEW( parent ));
+			gtk_tree_model_foreach( model, ( GtkTreeModelForeachFunc ) tree_view_select_iter, instance );
+
+		} else {
+			g_warning( "%s: unknown parent type: %s", thisfn, G_OBJECT_TYPE_NAME( parent ));
+		}
+	}
+}
+
+/*
+ * container_mode is a GtkVBox, or a GtkGrid starting with Gtk 3.2
+ *
+ * iterating through each radio button of the group:
+ * - connecting to 'toggled' signal
+ * - activating the button which holds our default value
+ */
+static void
+radio_button_select_iter( GtkWidget *container_option, NAIOptionsList *instance )
+{
+	NAIOption *option;
+	NAIOption *default_option;
+	GtkWidget *button;
+	gboolean editable, sensitive;
+
+	button = NULL;
+	default_option = options_list_get_option( instance );
+	option = options_list_get_container_option( container_option );
+
+	if( option == default_option ){
+		button = na_gtk_utils_find_widget_by_type( GTK_CONTAINER( container_option ), GTK_TYPE_RADIO_BUTTON );
+		g_return_if_fail( GTK_IS_RADIO_BUTTON( button ));
+		editable = options_list_get_editable( instance );
+		sensitive = options_list_get_sensitive( instance );
+		na_gtk_utils_radio_set_initial_state( GTK_RADIO_BUTTON( button ),
+				NULL, NULL, editable, sensitive );
+	}
+}
+
+/*
+ * walks through the rows of the liststore until the function returns %TRUE
+ */
+static gboolean
+tree_view_select_iter( GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, NAIOptionsList *instance )
+{
+	gboolean stop;
+	GtkTreeView *tree_view;
+	NAIOption *default_option, *option;
+	GtkTreeSelection *selection;
+
+	stop = FALSE;
+	tree_view = ( GtkTreeView * ) options_list_get_container_parent( instance );
+	g_return_val_if_fail( GTK_IS_TREE_VIEW( tree_view ), TRUE );
+	default_option = options_list_get_option( instance );
+
+	gtk_tree_model_get( model, iter, OBJECT_COLUMN, &option, -1 );
+	g_object_unref( option );
+
+	if( option == default_option ){
+		selection = gtk_tree_view_get_selection( tree_view );
+		gtk_tree_selection_select_iter( selection, iter );
+		stop = TRUE;
+	}
+
+	return( stop );
+}
diff --git a/src/core/na-ioptions-list.h b/src/core/na-ioptions-list.h
new file mode 100644
index 0000000..2ba97b7
--- /dev/null
+++ b/src/core/na-ioptions-list.h
@@ -0,0 +1,215 @@
+/*
+ * 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, 2011 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 __CORE_NA_IOPTIONS_LIST_H__
+#define __CORE_NA_IOPTIONS_LIST_H__
+
+/*
+ * SECTION: ioptions_list
+ * @title: NAIOptionsList
+ * @short_description: The OptionsList Interface v 1
+ * @include: core/na-ioptions-list.h
+ *
+ * The #NAIOptionsList interface is to be used when we have one option to choose
+ * among several. The interface takes care of:
+ * <itemizedlist>
+ *   <listitem>
+ *     <para>
+ *       displaying the items, either as a radio button group or as a tree view,
+ *       inside of a parent container;
+ *     </para>
+ *     <para>
+ *       maybe displaying a tooltip and/or a pixbuf for each option;
+ *     </para>
+ *     <para>
+ *       maybe adding an 'Ask me' option;
+ *     </para>
+ *     <para>
+ *       setting a default option, identified by its identifier, which can
+ *       be anything resolvable to a #gpointer value;
+ *     </para>
+ *     <para>
+ *       returning the selected option as a #gpointer value;
+ *     </para>
+ *     <para>
+ *       freeing the allocated resources at end.
+ *     </para>
+ *   </listitem>
+ * </itemizedlist>
+ *
+ * In order this interface to work, each option has to be seen as a #GObject
+ * -derived object, which itself should implement the #NAIOption companion
+ * interface.
+ *
+ * More, the instance which would want to implement this #NAIOptionsList
+ * interface should also implement one of #NAIOptionsRadioButton or
+ * #NAIOptionsTreeView interfaces.
+ *
+ * <refsect2>
+ *  <title>Versions historic</title>
+ *  <table>
+ *    <title>Historic of the versions of the #NAIOptionsList interface</title>
+ *    <tgroup rowsep="1" colsep="1" align="center" cols="3">
+ *      <colspec colname="na-version" />
+ *      <colspec colname="api-version" />
+ *      <colspec colname="current" />
+ *      <thead>
+ *        <row>
+ *          <entry>&prodname; version</entry>
+ *          <entry>#NAIOptionsList interface version</entry>
+ *          <entry></entry>
+ *        </row>
+ *      </thead>
+ *      <tbody>
+ *        <row>
+ *          <entry>since 3.2</entry>
+ *          <entry>1</entry>
+ *          <entry>current version</entry>
+ *        </row>
+ *      </tbody>
+ *    </tgroup>
+ *  </table>
+ * </refsect2>
+ */
+
+#include <gtk/gtk.h>
+
+#include "na-ioption.h"
+
+G_BEGIN_DECLS
+
+#define NA_IOPTIONS_LIST_TYPE               ( na_ioptions_list_get_type())
+#define NA_IOPTIONS_LIST( i )               ( G_TYPE_CHECK_INSTANCE_CAST( i, NA_IOPTIONS_LIST_TYPE, NAIOptionsList ))
+#define NA_IS_IOPTIONS_LIST( i )            ( G_TYPE_CHECK_INSTANCE_TYPE( i, NA_IOPTIONS_LIST_TYPE ))
+#define NA_IOPTIONS_LIST_GET_INTERFACE( i ) ( G_TYPE_INSTANCE_GET_INTERFACE(( i ), NA_IOPTIONS_LIST_TYPE, NAIOptionsListInterface ))
+
+typedef struct _NAIOptionsList                      NAIOptionsList;
+typedef struct _NAIOptionsListInterfacePrivate      NAIOptionsListInterfacePrivate;
+typedef struct _NAIOptionsListImportFromUriParms    NAIOptionsListImportFromUriParms;
+typedef struct _NAIOptionsListManageImportModeParms NAIOptionsListManageImportModeParms;
+
+/*
+ * NAIOptionsListInterface:
+ * @get_version:     returns the version of this interface that the
+ *                   instance implements.
+ *
+ * This defines the interface that a #NAIOptionsList implementation should provide.
+ */
+typedef struct {
+	/*< private >*/
+	GTypeInterface                  parent;
+	NAIOptionsListInterfacePrivate *private;
+
+	/*< public >*/
+	/*
+	 * get_version:
+	 * @instance: the #NAIOptionsList instance of the implementation.
+	 *
+	 * This method is supposed to let know to any caller which version of this
+	 * interface the implementation provides. This may be useful when this
+	 * interface will itself be upgraded.
+	 *
+	 * If this method is not provided by the implementation, one should suppose
+	 * that the implemented version is at last the version 1.
+	 *
+	 * Returns: the version of this interface provided by the implementation.
+	 *
+	 * Since: 3.2
+	 */
+	guint       ( *get_version ) ( const NAIOptionsList *instance );
+
+	/*
+	 * get_options:
+	 * @instance: the #NAIOptionsList instance of the implementation.
+	 *
+	 * This method may be called at more or less early stage of the build
+	 * of the display, either rather early when displaying a radio button
+	 * group, or later in the case of a tree view.
+	 *
+	 * Returns: a #GList list of #NAIOptions object instances.
+	 *
+	 * Since: 3.2
+	 */
+	GList *     ( *get_options ) ( const NAIOptionsList *instance );
+
+	/*
+	 * free_options:
+	 * @instance: the #NAIOptionsList instance of the implementation.
+	 * @options: a #GList of #NAIoption objects as returned by get_options() method.
+	 *
+	 * Release the resources allocated to the @options list.
+	 *
+	 * Note that the interface defaults to just g_object_unref() each
+	 * instance of the @options list, the g_list_free() the list itself.
+	 * So if your implementation may satisfy itself with this default, you
+	 * just do not need to implement the method.
+	 *
+	 * Since: 3.2
+	 */
+	void        ( *free_options )( const NAIOptionsList *instance, GList *options );
+
+	/*
+	 * get_ask_option:
+	 * @instance: the #NAIOptionsList instance of the implementation.
+	 *
+	 * Ask the implementation to provide a #NAIOption which defines the
+	 * 'Ask me' option.
+	 *
+	 * Returns: a #NAIOption which defines the 'Ask me' option.
+	 *
+	 * Since: 3.2
+	 */
+	NAIOption * ( *get_ask_option ) ( const NAIOptionsList *instance );
+
+	/*
+	 * free_ask_option:
+	 * @instance: the #NAIOptionsList instance of the implementation.
+	 * @ask_option: the #NAIoption to be released.
+	 *
+	 * Release the resources allocated to the @ask_option instance.
+	 *
+	 * Note that the interface defaults to just g_object_unref() the object.
+	 * So if your implementation may satisfy itself with this default, you just
+	 * do not need to implement the method.
+	 *
+	 * Since: 3.2
+	 */
+	void        ( *free_ask_option )( const NAIOptionsList *instance, NAIOption *ask_option );
+}
+	NAIOptionsListInterface;
+
+GType na_ioptions_list_get_type( void );
+
+void  na_ioptions_list_display_init( NAIOptionsList *instance, GtkWidget *parent, gboolean with_ask, gboolean editable, gboolean sensitive );
+void  na_ioptions_list_set_default ( NAIOptionsList *instance, NAIOption *default_option );
+
+G_END_DECLS
+
+#endif /* __CORE_NA_IOPTIONS_LIST_H__ */
diff --git a/src/nact/base-gtk-utils.c b/src/nact/base-gtk-utils.c
index fc8ef6c..f90ae00 100644
--- a/src/nact/base-gtk-utils.c
+++ b/src/nact/base-gtk-utils.c
@@ -39,10 +39,6 @@
 
 #include "base-gtk-utils.h"
 
-#define NACT_PROP_TOGGLE_BUTTON				"nact-prop-toggle-button"
-#define NACT_PROP_TOGGLE_HANDLER			"nact-prop-toggle-handler"
-#define NACT_PROP_TOGGLE_USER_DATA			"nact-prop-toggle-user-data"
-
 #define DEFAULT_WIDTH		22
 
 /**
@@ -103,58 +99,7 @@ base_gtk_utils_save_window_position( const BaseWindow *window, const gchar *wsp_
 void
 base_gtk_utils_set_editable( GObject *widget, gboolean editable )
 {
-	GList *renderers, *irender;
-
-/* GtkComboBoxEntry is deprecated from Gtk+3
- * see. http://git.gnome.org/browse/gtk+/commit/?id=9612c648176378bf237ad0e1a8c6c995b0ca7c61
- * while 'has_entry' property exists since 2.24
- */
-#if GTK_CHECK_VERSION( 2, 24, 0 )
-	if( GTK_IS_COMBO_BOX( widget ) && gtk_combo_box_get_has_entry( GTK_COMBO_BOX( widget ))){
-#else
-	if( GTK_IS_COMBO_BOX_ENTRY( widget )){
-#endif
-		/* idem as GtkEntry */
-		gtk_editable_set_editable( GTK_EDITABLE( gtk_bin_get_child( GTK_BIN( widget ))), editable );
-		g_object_set( G_OBJECT( gtk_bin_get_child( GTK_BIN( widget ))), "can-focus", editable, NULL );
-		/* disable the listbox button itself */
-		gtk_combo_box_set_button_sensitivity( GTK_COMBO_BOX( widget ), editable ? GTK_SENSITIVITY_ON : GTK_SENSITIVITY_OFF );
-
-	} else if( GTK_IS_COMBO_BOX( widget )){
-		/* disable the listbox button itself */
-		gtk_combo_box_set_button_sensitivity( GTK_COMBO_BOX( widget ), editable ? GTK_SENSITIVITY_ON : GTK_SENSITIVITY_OFF );
-
-	} else if( GTK_IS_ENTRY( widget )){
-		gtk_editable_set_editable( GTK_EDITABLE( widget ), editable );
-		/* removing the frame leads to a disturbing modification of the
-		 * height of the control */
-		/*g_object_set( G_OBJECT( widget ), "has-frame", editable, NULL );*/
-		/* this prevents the caret to be displayed when we click in the entry */
-		g_object_set( G_OBJECT( widget ), "can-focus", editable, NULL );
-
-	} else if( GTK_IS_TEXT_VIEW( widget )){
-		g_object_set( G_OBJECT( widget ), "can-focus", editable, NULL );
-		gtk_text_view_set_editable( GTK_TEXT_VIEW( widget ), editable );
-
-	} else if( GTK_IS_TOGGLE_BUTTON( widget )){
-		/* transforms to a quasi standard GtkButton */
-		/*g_object_set( G_OBJECT( widget ), "draw-indicator", editable, NULL );*/
-		/* this at least prevent the keyboard focus to go to the button
-		 * (which is better than nothing) */
-		g_object_set( G_OBJECT( widget ), "can-focus", editable, NULL );
-
-	} else if( GTK_IS_TREE_VIEW_COLUMN( widget )){
-		renderers = gtk_cell_layout_get_cells( GTK_CELL_LAYOUT( GTK_TREE_VIEW_COLUMN( widget )));
-		for( irender = renderers ; irender ; irender = irender->next ){
-			if( GTK_IS_CELL_RENDERER_TEXT( irender->data )){
-				g_object_set( G_OBJECT( irender->data ), "editable", editable, "editable-set", TRUE, NULL );
-			}
-		}
-		g_list_free( renderers );
-
-	} else if( GTK_IS_BUTTON( widget )){
-		gtk_widget_set_sensitive( GTK_WIDGET( widget ), editable );
-	}
+	na_gtk_utils_set_editable( widget, editable );
 }
 
 /**
@@ -184,23 +129,7 @@ void
 base_gtk_utils_radio_set_initial_state( GtkRadioButton *button,
 		GCallback handler, void *user_data, gboolean editable, gboolean sensitive )
 {
-	GSList *group, *ig;
-	GtkRadioButton *other;
-
-	group = gtk_radio_button_get_group( button );
-
-	for( ig = group ; ig ; ig = ig->next ){
-		other = GTK_RADIO_BUTTON( ig->data );
-		g_object_set_data( G_OBJECT( other ), NACT_PROP_TOGGLE_BUTTON, button );
-		g_object_set_data( G_OBJECT( other ), NACT_PROP_TOGGLE_HANDLER, handler );
-		g_object_set_data( G_OBJECT( other ), NACT_PROP_TOGGLE_USER_DATA, user_data );
-		g_object_set_data( G_OBJECT( other ), NACT_PROP_TOGGLE_EDITABLE, GUINT_TO_POINTER( editable ));
-		base_gtk_utils_set_editable( G_OBJECT( other ), editable );
-		gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( other ), FALSE );
-		gtk_widget_set_sensitive( GTK_WIDGET( other ), sensitive );
-	}
-
-	gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( button ), TRUE );
+	na_gtk_utils_radio_set_initial_state( button, handler, user_data, editable, sensitive );
 }
 
 /**
@@ -217,33 +146,7 @@ base_gtk_utils_radio_set_initial_state( GtkRadioButton *button,
 void
 base_gtk_utils_radio_reset_initial_state( GtkRadioButton *button, GCallback handler )
 {
-	GtkToggleButton *initial_button;
-	GCallback initial_handler;
-	gboolean active;
-	gboolean editable;
-	gpointer user_data;
-
-	active = gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON( button ));
-	editable = ( gboolean ) GPOINTER_TO_UINT( g_object_get_data( G_OBJECT( button ), NACT_PROP_TOGGLE_EDITABLE ));
-
-	if( active && !editable ){
-		initial_button = GTK_TOGGLE_BUTTON( g_object_get_data( G_OBJECT( button ), NACT_PROP_TOGGLE_BUTTON ));
-		initial_handler = G_CALLBACK( g_object_get_data( G_OBJECT( button ), NACT_PROP_TOGGLE_HANDLER ));
-		user_data = g_object_get_data( G_OBJECT( button ), NACT_PROP_TOGGLE_USER_DATA );
-
-		if( handler ){
-			g_signal_handlers_block_by_func(( gpointer ) button, handler, user_data );
-		}
-		g_signal_handlers_block_by_func(( gpointer ) initial_button, initial_handler, user_data );
-
-		gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( button ), FALSE );
-		gtk_toggle_button_set_active( initial_button, TRUE );
-
-		g_signal_handlers_unblock_by_func(( gpointer ) initial_button, initial_handler, user_data );
-		if( handler ){
-			g_signal_handlers_unblock_by_func(( gpointer ) button, handler, user_data );
-		}
-	}
+	na_gtk_utils_radio_reset_initial_state( button, handler );
 }
 
 /**
@@ -279,9 +182,9 @@ base_gtk_utils_toggle_set_initial_state( BaseWindow *window,
 	if( button ){
 		base_window_signal_connect( window, G_OBJECT( button ), "toggled", handler );
 
-		g_object_set_data( G_OBJECT( button ), NACT_PROP_TOGGLE_HANDLER, handler );
-		g_object_set_data( G_OBJECT( button ), NACT_PROP_TOGGLE_USER_DATA, window );
-		g_object_set_data( G_OBJECT( button ), NACT_PROP_TOGGLE_EDITABLE, GUINT_TO_POINTER( editable ));
+		g_object_set_data( G_OBJECT( button ), NA_TOGGLE_DATA_HANDLER, handler );
+		g_object_set_data( G_OBJECT( button ), NA_TOGGLE_DATA_USER_DATA, window );
+		g_object_set_data( G_OBJECT( button ), NA_TOGGLE_DATA_EDITABLE, GUINT_TO_POINTER( editable ));
 
 		base_gtk_utils_set_editable( G_OBJECT( button ), editable );
 		gtk_widget_set_sensitive( GTK_WIDGET( button ), sensitive );
@@ -307,12 +210,12 @@ base_gtk_utils_toggle_reset_initial_state( GtkToggleButton *button )
 	gpointer user_data;
 	gboolean active;
 
-	editable = ( gboolean ) GPOINTER_TO_UINT( g_object_get_data( G_OBJECT( button ), NACT_PROP_TOGGLE_EDITABLE ));
+	editable = ( gboolean ) GPOINTER_TO_UINT( g_object_get_data( G_OBJECT( button ), NA_TOGGLE_DATA_EDITABLE ));
 
 	if( !editable ){
 		active = gtk_toggle_button_get_active( button );
-		handler = G_CALLBACK( g_object_get_data( G_OBJECT( button ), NACT_PROP_TOGGLE_HANDLER ));
-		user_data = g_object_get_data( G_OBJECT( button ), NACT_PROP_TOGGLE_USER_DATA );
+		handler = G_CALLBACK( g_object_get_data( G_OBJECT( button ), NA_TOGGLE_DATA_HANDLER ));
+		user_data = g_object_get_data( G_OBJECT( button ), NA_TOGGLE_DATA_USER_DATA );
 
 		g_signal_handlers_block_by_func(( gpointer ) button, handler, user_data );
 		gtk_toggle_button_set_active( button, !active );
diff --git a/src/nact/base-gtk-utils.h b/src/nact/base-gtk-utils.h
index 0744872..0a4d4a9 100644
--- a/src/nact/base-gtk-utils.h
+++ b/src/nact/base-gtk-utils.h
@@ -49,8 +49,6 @@ void       base_gtk_utils_save_window_position   ( const BaseWindow *window, con
 
 /* widget status
  */
-#define NACT_PROP_TOGGLE_EDITABLE			"nact-prop-toggle-editable"
-
 void       base_gtk_utils_set_editable( GObject *widget, gboolean editable );
 
 void       base_gtk_utils_radio_set_initial_state  ( GtkRadioButton *button,
diff --git a/src/nact/nact-export-ask.c b/src/nact/nact-export-ask.c
index 2d0d7b6..2c05efe 100644
--- a/src/nact/nact-export-ask.c
+++ b/src/nact/nact-export-ask.c
@@ -37,6 +37,7 @@
 #include <api/na-object-api.h>
 
 #include <core/na-exporter.h>
+#include <core/na-gtk-utils.h>
 #include <core/na-iprefs.h>
 
 #include "nact-application.h"
@@ -355,7 +356,7 @@ keep_choice_on_toggled( GtkToggleButton *button, NactExportAsk *editor )
 {
 	gboolean editable;
 
-	editable = ( gboolean ) GPOINTER_TO_UINT( g_object_get_data( G_OBJECT( button ), NACT_PROP_TOGGLE_EDITABLE ));
+	editable = ( gboolean ) GPOINTER_TO_UINT( g_object_get_data( G_OBJECT( button ), NA_TOGGLE_DATA_EDITABLE ));
 
 	if( editable ){
 		editor->private->keep_last_choice = gtk_toggle_button_get_active( button );
diff --git a/src/nact/nact-preferences-editor.c b/src/nact/nact-preferences-editor.c
index 5cf69e3..559d73e 100644
--- a/src/nact/nact-preferences-editor.c
+++ b/src/nact/nact-preferences-editor.c
@@ -38,6 +38,7 @@
 #include <api/na-iimporter.h>
 
 #include <core/na-desktop-environment.h>
+#include <core/na-gtk-utils.h>
 #include <core/na-iprefs.h>
 #include <core/na-tokens.h>
 
@@ -529,7 +530,7 @@ order_mode_on_toggled( NactPreferencesEditor *editor, GtkToggleButton *toggle_bu
 	gboolean editable;
 	gboolean active;
 
-	editable = ( gboolean ) GPOINTER_TO_UINT( g_object_get_data( G_OBJECT( toggle_button ), NACT_PROP_TOGGLE_EDITABLE ));
+	editable = ( gboolean ) GPOINTER_TO_UINT( g_object_get_data( G_OBJECT( toggle_button ), NA_TOGGLE_DATA_EDITABLE ));
 
 	if( editable ){
 		active = gtk_toggle_button_get_active( toggle_button );
@@ -562,7 +563,7 @@ root_menu_on_toggled( GtkToggleButton *button, NactPreferencesEditor *editor )
 {
 	gboolean editable;
 
-	editable = ( gboolean ) GPOINTER_TO_UINT( g_object_get_data( G_OBJECT( button ), NACT_PROP_TOGGLE_EDITABLE ));
+	editable = ( gboolean ) GPOINTER_TO_UINT( g_object_get_data( G_OBJECT( button ), NA_TOGGLE_DATA_EDITABLE ));
 
 	if( editable ){
 		editor->private->root_menu = gtk_toggle_button_get_active( button );
@@ -593,7 +594,7 @@ about_item_on_toggled( GtkToggleButton *button, NactPreferencesEditor *editor )
 {
 	gboolean editable;
 
-	editable = ( gboolean ) GPOINTER_TO_UINT( g_object_get_data( G_OBJECT( button ), NACT_PROP_TOGGLE_EDITABLE ));
+	editable = ( gboolean ) GPOINTER_TO_UINT( g_object_get_data( G_OBJECT( button ), NA_TOGGLE_DATA_EDITABLE ));
 
 	if( editable ){
 		editor->private->about_item = gtk_toggle_button_get_active( button );
@@ -774,7 +775,7 @@ relabel_menu_on_toggled( GtkToggleButton *button, NactPreferencesEditor *editor
 {
 	gboolean editable;
 
-	editable = ( gboolean ) GPOINTER_TO_UINT( g_object_get_data( G_OBJECT( button ), NACT_PROP_TOGGLE_EDITABLE ));
+	editable = ( gboolean ) GPOINTER_TO_UINT( g_object_get_data( G_OBJECT( button ), NA_TOGGLE_DATA_EDITABLE ));
 
 	if( editable ){
 		editor->private->relabel_menu = gtk_toggle_button_get_active( button );
@@ -805,7 +806,7 @@ relabel_action_on_toggled( GtkToggleButton *button, NactPreferencesEditor *edito
 {
 	gboolean editable;
 
-	editable = ( gboolean ) GPOINTER_TO_UINT( g_object_get_data( G_OBJECT( button ), NACT_PROP_TOGGLE_EDITABLE ));
+	editable = ( gboolean ) GPOINTER_TO_UINT( g_object_get_data( G_OBJECT( button ), NA_TOGGLE_DATA_EDITABLE ));
 
 	if( editable ){
 		editor->private->relabel_action = gtk_toggle_button_get_active( button );
@@ -836,7 +837,7 @@ relabel_profile_on_toggled( GtkToggleButton *button, NactPreferencesEditor *edit
 {
 	gboolean editable;
 
-	editable = ( gboolean ) GPOINTER_TO_UINT( g_object_get_data( G_OBJECT( button ), NACT_PROP_TOGGLE_EDITABLE ));
+	editable = ( gboolean ) GPOINTER_TO_UINT( g_object_get_data( G_OBJECT( button ), NA_TOGGLE_DATA_EDITABLE ));
 
 	if( editable ){
 		editor->private->relabel_profile = gtk_toggle_button_get_active( button );
@@ -868,7 +869,7 @@ esc_quit_on_toggled( GtkToggleButton *button, NactPreferencesEditor *editor )
 	gboolean editable;
 	GtkWidget *confirm_button;
 
-	editable = ( gboolean ) GPOINTER_TO_UINT( g_object_get_data( G_OBJECT( button ), NACT_PROP_TOGGLE_EDITABLE ));
+	editable = ( gboolean ) GPOINTER_TO_UINT( g_object_get_data( G_OBJECT( button ), NA_TOGGLE_DATA_EDITABLE ));
 
 	if( editable ){
 		editor->private->esc_quit = gtk_toggle_button_get_active( button );
@@ -902,7 +903,7 @@ esc_confirm_on_toggled( GtkToggleButton *button, NactPreferencesEditor *editor )
 {
 	gboolean editable;
 
-	editable = ( gboolean ) GPOINTER_TO_UINT( g_object_get_data( G_OBJECT( button ), NACT_PROP_TOGGLE_EDITABLE ));
+	editable = ( gboolean ) GPOINTER_TO_UINT( g_object_get_data( G_OBJECT( button ), NA_TOGGLE_DATA_EDITABLE ));
 
 	if( editable ){
 		editor->private->esc_confirm = gtk_toggle_button_get_active( button );
@@ -949,7 +950,7 @@ auto_save_on_toggled( GtkToggleButton *button, NactPreferencesEditor *editor )
 	GtkWidget *widget;
 	gboolean sensitive;
 
-	editable = ( gboolean ) GPOINTER_TO_UINT( g_object_get_data( G_OBJECT( button ), NACT_PROP_TOGGLE_EDITABLE ));
+	editable = ( gboolean ) GPOINTER_TO_UINT( g_object_get_data( G_OBJECT( button ), NA_TOGGLE_DATA_EDITABLE ));
 
 	if( editable ){
 		editor->private->auto_save = gtk_toggle_button_get_active( button );
@@ -1059,7 +1060,7 @@ import_mode_on_toggled( NactPreferencesEditor *editor, GtkToggleButton *toggle_b
 	gboolean editable;
 	gboolean active;
 
-	editable = ( gboolean ) GPOINTER_TO_UINT( g_object_get_data( G_OBJECT( toggle_button ), NACT_PROP_TOGGLE_EDITABLE ));
+	editable = ( gboolean ) GPOINTER_TO_UINT( g_object_get_data( G_OBJECT( toggle_button ), NA_TOGGLE_DATA_EDITABLE ));
 
 	if( editable ){
 		active = gtk_toggle_button_get_active( toggle_button );



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