[nautilus-actions: 18/45] Work around for more-than-once-run bug #589746



commit 64b15c077c94b9116c12ab61635dd2d045e4001b
Author: Pierre Wieser <pwieser trychlos org>
Date:   Sun Jul 26 12:13:28 2009 +0200

    Work around for more-than-once-run bug #589746

 ChangeLog                         |   13 +++
 src/nact/Makefile.am              |    2 +
 src/nact/base-application-class.h |   91 +++++++++++++++++++
 src/nact/base-application.c       |   58 ++++++------
 src/nact/base-application.h       |   68 +++------------
 src/nact/base-window-class.h      |   89 ++++++++++++++++++
 src/nact/base-window.c            |   64 +++++++-------
 src/nact/base-window.h            |   59 +++----------
 src/nact/nact-application.c       |   43 +++++-----
 src/nact/nact-application.h       |    1 +
 src/nact/nact-assist-export.c     |   27 ++++--
 src/nact/nact-assist-import.c     |   22 ++---
 src/nact/nact-assist-import.h     |    4 +-
 src/nact/nact-assistant.c         |   29 ++++++
 src/nact/nact-gconf-reader.c      |   26 ++++--
 src/nact/nact-gconf-reader.h      |    7 +-
 src/nact/nact-iactions-list.c     |   52 ++++++++---
 src/nact/nact-iactions-list.h     |    1 +
 src/nact/nact-imenubar.c          |  181 +++++++++++++++++++++++++++++--------
 src/nact/nact-main-window.c       |   31 ++++++-
 src/nact/nact-main-window.h       |    5 +-
 21 files changed, 596 insertions(+), 277 deletions(-)
---
diff --git a/ChangeLog b/ChangeLog
index 099d1dd..e353996 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,16 @@
+2009-07-26 Pierre Wieser <pwieser trychlos org>
+
+	* src/nact/base-application-class.h:
+	* src/nact/base-window-class.h: New files.
+
+	* src/nact/base-application.c:
+	* src/nact/base-application.h
+	(base_application_get_ui_filename): New function.
+
+	* src/nact/nact-assistant.c:
+	Reload the GtkBuilder XML file each time we run the assistant
+	(see http://bugzilla.gnome.org/show_bug.cgi?id=589746).
+
 2009-07-25 Pierre Wieser <pwieser trychlos org>
 
 	* src/common/na-action-class.h:
diff --git a/src/nact/Makefile.am b/src/nact/Makefile.am
index cb3da93..3029abb 100644
--- a/src/nact/Makefile.am
+++ b/src/nact/Makefile.am
@@ -42,8 +42,10 @@ AM_CPPFLAGS += \
 nautilus_actions_config_SOURCES = \
 	base-application.c									\
 	base-application.h									\
+	base-application-class.h							\
 	base-window.c										\
 	base-window.h										\
+	base-window-class.h									\
 	nact-application.c									\
 	nact-application.h									\
 	nact-assistant.c									\
diff --git a/src/nact/base-application-class.h b/src/nact/base-application-class.h
new file mode 100644
index 0000000..edae6ef
--- /dev/null
+++ b/src/nact/base-application-class.h
@@ -0,0 +1,91 @@
+/*
+ * Nautilus Actions
+ * A Nautilus extension which offers configurable context menu actions.
+ *
+ * Copyright (C) 2005 The GNOME Foundation
+ * Copyright (C) 2006, 2007, 2008 Frederic Ruaudel and others (see AUTHORS)
+ * Copyright (C) 2009 Pierre Wieser and others (see AUTHORS)
+ *
+ * This Program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this Library; see the file COPYING.  If not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place,
+ * Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Authors:
+ *   Frederic Ruaudel <grumz grumz net>
+ *   Rodrigo Moya <rodrigo gnome-db org>
+ *   Pierre Wieser <pwieser trychlos org>
+ *   ... and many others (see AUTHORS)
+ */
+
+#ifndef __BASE_APPLICATION_CLASS_H__
+#define __BASE_APPLICATION_CLASS_H__
+
+/*
+ * BaseApplication class definition.
+ *
+ * This is a base class for Gtk+ programs.
+ */
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define BASE_APPLICATION_TYPE					( base_application_get_type())
+#define BASE_APPLICATION( object )				( G_TYPE_CHECK_INSTANCE_CAST( object, BASE_APPLICATION_TYPE, BaseApplication ))
+#define BASE_APPLICATION_CLASS( klass )			( G_TYPE_CHECK_CLASS_CAST( klass, BASE_APPLICATION_TYPE, BaseApplicationClass ))
+#define BASE_IS_APPLICATION( object )			( G_TYPE_CHECK_INSTANCE_TYPE( object, BASE_APPLICATION_TYPE ))
+#define BASE_IS_APPLICATION_CLASS( klass )		( G_TYPE_CHECK_CLASS_TYPE(( klass ), BASE_APPLICATION_TYPE ))
+#define BASE_APPLICATION_GET_CLASS( object )	( G_TYPE_INSTANCE_GET_CLASS(( object ), BASE_APPLICATION_TYPE, BaseApplicationClass ))
+
+typedef struct BaseApplicationPrivate BaseApplicationPrivate;
+
+typedef struct {
+	GObject                 parent;
+	BaseApplicationPrivate *private;
+}
+	BaseApplication;
+
+typedef struct BaseApplicationClassPrivate BaseApplicationClassPrivate;
+
+typedef struct {
+	GObjectClass                 parent;
+	BaseApplicationClassPrivate *private;
+
+	/* virtual functions */
+	int       ( *run )                         ( BaseApplication *appli );
+	void      ( *initialize )                  ( BaseApplication *appli );
+	void      ( *initialize_i18n )             ( BaseApplication *appli );
+	void      ( *initialize_gtk )              ( BaseApplication *appli );
+	void      ( *initialize_application_name ) ( BaseApplication *appli );
+	void      ( *initialize_icon_name )        ( BaseApplication *appli );
+	void      ( *initialize_unique )           ( BaseApplication *appli );
+	void      ( *initialize_ui )               ( BaseApplication *appli );
+	gboolean  ( *is_willing_to_run )           ( BaseApplication *appli );
+	void      ( *advertise_willing_to_run )    ( BaseApplication *appli );
+	void      ( *advertise_not_willing_to_run )( BaseApplication *appli );
+	void      ( *start )                       ( BaseApplication *appli );
+	void      ( *finish )                      ( BaseApplication *appli );
+	gchar *   ( *get_unique_name )             ( BaseApplication *appli );
+	gchar *   ( *get_application_name )        ( BaseApplication *appli );
+	gchar *   ( *get_icon_name )               ( BaseApplication *appli );
+	gchar *   ( *get_ui_filename )             ( BaseApplication *appli );
+	GObject * ( *get_main_window )             ( BaseApplication *appli );
+}
+	BaseApplicationClass;
+
+GType base_application_get_type( void );
+
+G_END_DECLS
+
+#endif /* __BASE_APPLICATION_CLASS_H__ */
diff --git a/src/nact/base-application.c b/src/nact/base-application.c
index 6008e90..e18ee6b 100644
--- a/src/nact/base-application.c
+++ b/src/nact/base-application.c
@@ -37,6 +37,7 @@
 #include <unique/unique.h>
 
 #include "base-application.h"
+#include "base-window.h"
 
 /* private class data
  */
@@ -56,7 +57,7 @@ struct BaseApplicationPrivate {
 	int         code;
 	GtkBuilder *ui_xml;
 	gchar      *ui_fname;
-	GObject    *main_window;
+	BaseWindow *main_window;
 };
 
 /* instance properties
@@ -99,8 +100,7 @@ static void           v_advertise_not_willing_to_run( BaseApplication *applicati
 static void           v_start( BaseApplication *application );
 static void           v_finish( BaseApplication *application );
 static gchar         *v_get_unique_name( BaseApplication *application );
-static GObject       *v_get_main_window( BaseApplication *application );
-static gchar         *v_get_ui_filename( BaseApplication *application );
+static BaseWindow    *v_get_main_window( BaseApplication *application );
 
 static void           do_initialize( BaseApplication *application );
 static void           do_initialize_i18n( BaseApplication *application );
@@ -464,6 +464,27 @@ base_application_run( BaseApplication *application )
 }
 
 gchar *
+base_application_get_ui_filename( BaseApplication *application )
+{
+	static const gchar *thisfn = "base_application_get_ui_filename";
+	g_debug( "%s: icon=%p", thisfn, application );
+
+	g_assert( BASE_IS_APPLICATION( application ));
+
+	gchar *name;
+	g_object_get( G_OBJECT( application ), PROP_APPLICATION_UI_FILENAME_STR, &name, NULL );
+
+	if( !name || !strlen( name )){
+		name = BASE_APPLICATION_GET_CLASS( application )->get_ui_filename( application );
+		if( name && strlen( name )){
+			g_object_set( G_OBJECT( application ), PROP_APPLICATION_UI_FILENAME_STR, name, NULL );
+		}
+	}
+
+	return( name );
+}
+
+gchar *
 base_application_get_name( BaseApplication *application )
 {
 	/*static const gchar *thisfn = "base_application_get_name";
@@ -505,7 +526,7 @@ base_application_get_icon_name( BaseApplication *application )
 	return( name );
 }
 
-GObject *
+BaseWindow *
 base_application_get_main_window( BaseApplication *application )
 {
 	static const gchar *thisfn = "base_application_get_main_window";
@@ -788,28 +809,7 @@ v_get_unique_name( BaseApplication *application )
 	return( name );
 }
 
-static gchar *
-v_get_ui_filename( BaseApplication *application )
-{
-	static const gchar *thisfn = "base_application_v_get_ui_filename";
-	g_debug( "%s: icon=%p", thisfn, application );
-
-	g_assert( BASE_IS_APPLICATION( application ));
-
-	gchar *name;
-	g_object_get( G_OBJECT( application ), PROP_APPLICATION_UI_FILENAME_STR, &name, NULL );
-
-	if( !name || !strlen( name )){
-		name = BASE_APPLICATION_GET_CLASS( application )->get_ui_filename( application );
-		if( name && strlen( name )){
-			g_object_set( G_OBJECT( application ), PROP_APPLICATION_UI_FILENAME_STR, name, NULL );
-		}
-	}
-
-	return( name );
-}
-
-static GObject *
+static BaseWindow *
 v_get_main_window( BaseApplication *application )
 {
 	static const gchar *thisfn = "base_application_v_get_main_window";
@@ -821,7 +821,7 @@ v_get_main_window( BaseApplication *application )
 
 		g_assert( BASE_APPLICATION_GET_CLASS( application )->get_main_window );
 
-		GObject *main_window = BASE_APPLICATION_GET_CLASS( application )->get_main_window( application );
+		BaseWindow *main_window = BASE_WINDOW( BASE_APPLICATION_GET_CLASS( application )->get_main_window( application ));
 		application->private->main_window = main_window;
 	}
 
@@ -922,7 +922,7 @@ static void
 do_initialize_ui( BaseApplication *application )
 {
 	GError *error = NULL;
-	gchar *ui_name = v_get_ui_filename( application );
+	gchar *ui_name = base_application_get_ui_filename( application );
 
 	application->private->ui_xml = gtk_builder_new();
 
@@ -1000,7 +1000,7 @@ do_start( BaseApplication *application )
 	static const gchar *thisfn = "base_application_do_start";
 	g_debug( "%s: application=%p", thisfn, application );
 
-	BaseWindow *window = BASE_WINDOW( v_get_main_window( application ));
+	BaseWindow *window = v_get_main_window( application );
 	g_assert( window );
 	g_assert( BASE_IS_WINDOW( window ));
 
diff --git a/src/nact/base-application.h b/src/nact/base-application.h
index ef47ee7..5f31703 100644
--- a/src/nact/base-application.h
+++ b/src/nact/base-application.h
@@ -37,56 +37,13 @@
  * This is a base class for Gtk+ programs.
  */
 
-#include <glib-object.h>
 #include <gtk/gtk.h>
 
-#include "base-window.h"
+#include "base-application-class.h"
+#include "base-window-class.h"
 
 G_BEGIN_DECLS
 
-#define BASE_APPLICATION_TYPE					( base_application_get_type())
-#define BASE_APPLICATION( object )				( G_TYPE_CHECK_INSTANCE_CAST( object, BASE_APPLICATION_TYPE, BaseApplication ))
-#define BASE_APPLICATION_CLASS( klass )			( G_TYPE_CHECK_CLASS_CAST( klass, BASE_APPLICATION_TYPE, BaseApplicationClass ))
-#define BASE_IS_APPLICATION( object )			( G_TYPE_CHECK_INSTANCE_TYPE( object, BASE_APPLICATION_TYPE ))
-#define BASE_IS_APPLICATION_CLASS( klass )		( G_TYPE_CHECK_CLASS_TYPE(( klass ), BASE_APPLICATION_TYPE ))
-#define BASE_APPLICATION_GET_CLASS( object )	( G_TYPE_INSTANCE_GET_CLASS(( object ), BASE_APPLICATION_TYPE, BaseApplicationClass ))
-
-typedef struct BaseApplicationPrivate BaseApplicationPrivate;
-
-typedef struct {
-	GObject                 parent;
-	BaseApplicationPrivate *private;
-}
-	BaseApplication;
-
-typedef struct BaseApplicationClassPrivate BaseApplicationClassPrivate;
-
-typedef struct {
-	GObjectClass                 parent;
-	BaseApplicationClassPrivate *private;
-
-	/* virtual functions */
-	int       ( *run )                         ( BaseApplication *appli );
-	void      ( *initialize )                  ( BaseApplication *appli );
-	void      ( *initialize_i18n )             ( BaseApplication *appli );
-	void      ( *initialize_gtk )              ( BaseApplication *appli );
-	void      ( *initialize_application_name ) ( BaseApplication *appli );
-	void      ( *initialize_icon_name )        ( BaseApplication *appli );
-	void      ( *initialize_unique )           ( BaseApplication *appli );
-	void      ( *initialize_ui )               ( BaseApplication *appli );
-	gboolean  ( *is_willing_to_run )           ( BaseApplication *appli );
-	void      ( *advertise_willing_to_run )    ( BaseApplication *appli );
-	void      ( *advertise_not_willing_to_run )( BaseApplication *appli );
-	void      ( *start )                       ( BaseApplication *appli );
-	void      ( *finish )                      ( BaseApplication *appli );
-	gchar   * ( *get_unique_name )             ( BaseApplication *appli );
-	gchar   * ( *get_application_name )        ( BaseApplication *appli );
-	gchar   * ( *get_icon_name )               ( BaseApplication *appli );
-	gchar   * ( *get_ui_filename )             ( BaseApplication *appli );
-	GObject * ( *get_main_window )             ( BaseApplication *appli );
-}
-	BaseApplicationClass;
-
 /* instance properties
  */
 #define PROP_APPLICATION_ARGC_STR				"base-application-argc"
@@ -100,20 +57,19 @@ typedef struct {
 #define PROP_APPLICATION_UI_FILENAME_STR		"base-application-ui-filename"
 #define PROP_APPLICATION_MAIN_WINDOW_STR		"base-application-main-window"
 
-GType      base_application_get_type( void );
-
-int        base_application_run( BaseApplication *application );
+int         base_application_run( BaseApplication *application );
 
-gchar     *base_application_get_name( BaseApplication *application );
-gchar     *base_application_get_icon_name( BaseApplication *application );
-GObject   *base_application_get_main_window( BaseApplication *application );
+gchar      *base_application_get_ui_filename( BaseApplication *application );
+gchar      *base_application_get_name( BaseApplication *application );
+gchar      *base_application_get_icon_name( BaseApplication *application );
+BaseWindow *base_application_get_main_window( BaseApplication *application );
 
-GtkWindow *base_application_get_dialog( BaseApplication *application, const gchar *name );
-GtkWidget *base_application_get_widget( BaseApplication *application, BaseWindow *window, const gchar *name );
-GtkWidget *base_application_search_for_widget( BaseApplication *application, GtkWindow *window, const gchar *name );
+GtkWindow  *base_application_get_dialog( BaseApplication *application, const gchar *name );
+GtkWidget  *base_application_get_widget( BaseApplication *application, BaseWindow *window, const gchar *name );
+GtkWidget  *base_application_search_for_widget( BaseApplication *application, GtkWindow *window, const gchar *name );
 
-void       base_application_error_dlg( BaseApplication *application, GtkMessageType type, const gchar *primary, const gchar *secondary );
-gboolean   base_application_yesno_dlg( BaseApplication *application, GtkMessageType type, const gchar *first, const gchar *second );
+void        base_application_error_dlg( BaseApplication *application, GtkMessageType type, const gchar *primary, const gchar *secondary );
+gboolean    base_application_yesno_dlg( BaseApplication *application, GtkMessageType type, const gchar *first, const gchar *second );
 
 G_END_DECLS
 
diff --git a/src/nact/base-window-class.h b/src/nact/base-window-class.h
new file mode 100644
index 0000000..8443b00
--- /dev/null
+++ b/src/nact/base-window-class.h
@@ -0,0 +1,89 @@
+/*
+ * Nautilus Actions
+ * A Nautilus extension which offers configurable context menu actions.
+ *
+ * Copyright (C) 2005 The GNOME Foundation
+ * Copyright (C) 2006, 2007, 2008 Frederic Ruaudel and others (see AUTHORS)
+ * Copyright (C) 2009 Pierre Wieser and others (see AUTHORS)
+ *
+ * This Program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this Library; see the file COPYING.  If not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place,
+ * Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Authors:
+ *   Frederic Ruaudel <grumz grumz net>
+ *   Rodrigo Moya <rodrigo gnome-db org>
+ *   Pierre Wieser <pwieser trychlos org>
+ *   ... and many others (see AUTHORS)
+ */
+
+#ifndef __BASE_WINDOW_CLASS_H__
+#define __BASE_WINDOW_CLASS_H__
+
+/*
+ * BaseWindow class definition.
+ *
+ * This is a base class which encapsulates a Gtk+ windows.
+ * It works together with the BaseApplication class to run a Gtk+
+ * application.
+ */
+
+#include <gtk/gtk.h>
+
+#include "base-application-class.h"
+
+G_BEGIN_DECLS
+
+#define BASE_WINDOW_TYPE				( base_window_get_type())
+#define BASE_WINDOW( object )			( G_TYPE_CHECK_INSTANCE_CAST( object, BASE_WINDOW_TYPE, BaseWindow ))
+#define BASE_WINDOW_CLASS( klass )		( G_TYPE_CHECK_CLASS_CAST( klass, BASE_WINDOW_TYPE, BaseWindowClass ))
+#define BASE_IS_WINDOW( object )		( G_TYPE_CHECK_INSTANCE_TYPE( object, BASE_WINDOW_TYPE ))
+#define BASE_IS_WINDOW_CLASS( klass )	( G_TYPE_CHECK_CLASS_TYPE(( klass ), BASE_WINDOW_TYPE ))
+#define BASE_WINDOW_GET_CLASS( object )	( G_TYPE_INSTANCE_GET_CLASS(( object ), BASE_WINDOW_TYPE, BaseWindowClass ))
+
+typedef struct BaseWindowPrivate BaseWindowPrivate;
+
+typedef struct {
+	GObject            parent;
+	BaseWindowPrivate *private;
+}
+	BaseWindow;
+
+typedef struct BaseWindowClassPrivate BaseWindowClassPrivate;
+
+typedef struct {
+	GObjectClass            parent;
+	BaseWindowClassPrivate *private;
+
+	/* virtual functions */
+	void              ( *init )                 ( BaseWindow *window );
+	void              ( *run )                  ( BaseWindow *window );
+	void              ( *initial_load_toplevel )( BaseWindow *window );
+	void              ( *runtime_init_toplevel )( BaseWindow *window );
+	void              ( *all_widgets_showed )   ( BaseWindow *window );
+	gboolean          ( *dialog_response )      ( GtkDialog *dialog, gint code, BaseWindow *window );
+	gboolean          ( *delete_event )         ( BaseWindow *window, GtkWindow *toplevel, GdkEvent *event );
+	BaseApplication * ( *get_application )      ( BaseWindow *window );
+	gchar *           ( *get_toplevel_name )    ( BaseWindow *window );
+	GtkWindow *       ( *get_toplevel_dialog )  ( BaseWindow *window );
+	GtkWindow *       ( *get_dialog )           ( BaseWindow *window, const gchar *name );
+	GtkWidget *       ( *get_widget )           ( BaseWindow *window, const gchar *name );
+}
+	BaseWindowClass;
+
+GType base_window_get_type( void );
+
+G_END_DECLS
+
+#endif /* __BASE_WINDOW_CLASS_H__ */
diff --git a/src/nact/base-window.c b/src/nact/base-window.c
index 75d8d32..36d3fc1 100644
--- a/src/nact/base-window.c
+++ b/src/nact/base-window.c
@@ -68,35 +68,35 @@ enum {
 
 static GObjectClass *st_parent_class = NULL;
 
-static GType      register_type( void );
-static void       class_init( BaseWindowClass *klass );
-static void       instance_init( GTypeInstance *instance, gpointer klass );
-static void       instance_get_property( GObject *object, guint property_id, GValue *value, GParamSpec *spec );
-static void       instance_set_property( GObject *object, guint property_id, const GValue *value, GParamSpec *spec );
-static void       instance_dispose( GObject *application );
-static void       instance_finalize( GObject *application );
-
-static gchar     *v_get_toplevel_name( BaseWindow *window );
-static void       v_initial_load_toplevel( BaseWindow *window );
-static void       v_runtime_init_toplevel( BaseWindow *window );
-static void       v_all_widgets_showed( BaseWindow *window );
-static gboolean   v_dialog_response( GtkDialog *dialog, gint code, BaseWindow *window );
-static gboolean   v_delete_event( GtkWidget *widget, GdkEvent *event, BaseWindow *window );
-
-static void       do_init_window( BaseWindow *window );
-static void       do_initial_load_toplevel( BaseWindow *window );
-static void       do_runtime_init_toplevel( BaseWindow *window );
-static void       do_all_widgets_showed( BaseWindow *window );
-static void       do_run_window( BaseWindow *window );
-static gboolean   do_dialog_response( GtkDialog *dialog, gint code, BaseWindow *window );
-static GObject   *do_get_application( BaseWindow *window );
-static GtkWindow *do_get_toplevel_dialog( BaseWindow *window );
-static GtkWindow *do_get_dialog( BaseWindow *window, const gchar *name );
-static GtkWidget *do_get_widget( BaseWindow *window, const gchar *name );
-
-static gboolean   is_main_window( BaseWindow *window );
-static gboolean   is_toplevel_initialized( BaseWindow *window, GtkWindow *toplevel );
-static void       set_toplevel_initialized( BaseWindow *window, GtkWindow *toplevel, gboolean init );
+static GType            register_type( void );
+static void             class_init( BaseWindowClass *klass );
+static void             instance_init( GTypeInstance *instance, gpointer klass );
+static void             instance_get_property( GObject *object, guint property_id, GValue *value, GParamSpec *spec );
+static void             instance_set_property( GObject *object, guint property_id, const GValue *value, GParamSpec *spec );
+static void             instance_dispose( GObject *application );
+static void             instance_finalize( GObject *application );
+
+static gchar           *v_get_toplevel_name( BaseWindow *window );
+static void             v_initial_load_toplevel( BaseWindow *window );
+static void             v_runtime_init_toplevel( BaseWindow *window );
+static void             v_all_widgets_showed( BaseWindow *window );
+static gboolean         v_dialog_response( GtkDialog *dialog, gint code, BaseWindow *window );
+static gboolean         v_delete_event( GtkWidget *widget, GdkEvent *event, BaseWindow *window );
+
+static void             do_init_window( BaseWindow *window );
+static void             do_initial_load_toplevel( BaseWindow *window );
+static void             do_runtime_init_toplevel( BaseWindow *window );
+static void             do_all_widgets_showed( BaseWindow *window );
+static void             do_run_window( BaseWindow *window );
+static gboolean         do_dialog_response( GtkDialog *dialog, gint code, BaseWindow *window );
+static BaseApplication *do_get_application( BaseWindow *window );
+static GtkWindow       *do_get_toplevel_dialog( BaseWindow *window );
+static GtkWindow       *do_get_dialog( BaseWindow *window, const gchar *name );
+static GtkWidget       *do_get_widget( BaseWindow *window, const gchar *name );
+
+static gboolean         is_main_window( BaseWindow *window );
+static gboolean         is_toplevel_initialized( BaseWindow *window, GtkWindow *toplevel );
+static void             set_toplevel_initialized( BaseWindow *window, GtkWindow *toplevel, gboolean init );
 
 GType
 base_window_get_type( void )
@@ -374,7 +374,7 @@ base_window_run( BaseWindow *window )
  *
  * @window: this BaseWindow object.
  */
-GObject *
+BaseApplication *
 base_window_get_application( BaseWindow *window )
 {
 	g_assert( BASE_IS_WINDOW( window ));
@@ -628,10 +628,10 @@ do_dialog_response( GtkDialog *dialog, gint code, BaseWindow *window )
 	return( TRUE );
 }
 
-static GObject *
+static BaseApplication *
 do_get_application( BaseWindow *window )
 {
-	return( G_OBJECT( window->private->application ));
+	return( window->private->application );
 }
 
 static GtkWindow *
diff --git a/src/nact/base-window.h b/src/nact/base-window.h
index eef7f8c..6a9b5b7 100644
--- a/src/nact/base-window.h
+++ b/src/nact/base-window.h
@@ -39,47 +39,12 @@
  * application.
  */
 
-#include <glib-object.h>
 #include <gtk/gtk.h>
 
-G_BEGIN_DECLS
-
-#define BASE_WINDOW_TYPE				( base_window_get_type())
-#define BASE_WINDOW( object )			( G_TYPE_CHECK_INSTANCE_CAST( object, BASE_WINDOW_TYPE, BaseWindow ))
-#define BASE_WINDOW_CLASS( klass )		( G_TYPE_CHECK_CLASS_CAST( klass, BASE_WINDOW_TYPE, BaseWindowClass ))
-#define BASE_IS_WINDOW( object )		( G_TYPE_CHECK_INSTANCE_TYPE( object, BASE_WINDOW_TYPE ))
-#define BASE_IS_WINDOW_CLASS( klass )	( G_TYPE_CHECK_CLASS_TYPE(( klass ), BASE_WINDOW_TYPE ))
-#define BASE_WINDOW_GET_CLASS( object )	( G_TYPE_INSTANCE_GET_CLASS(( object ), BASE_WINDOW_TYPE, BaseWindowClass ))
-
-typedef struct BaseWindowPrivate BaseWindowPrivate;
-
-typedef struct {
-	GObject            parent;
-	BaseWindowPrivate *private;
-}
-	BaseWindow;
+#include "base-application-class.h"
+#include "base-window-class.h"
 
-typedef struct BaseWindowClassPrivate BaseWindowClassPrivate;
-
-typedef struct {
-	GObjectClass            parent;
-	BaseWindowClassPrivate *private;
-
-	/* virtual functions */
-	void        ( *init )                 ( BaseWindow *window );
-	void        ( *run )                  ( BaseWindow *window );
-	void        ( *initial_load_toplevel )( BaseWindow *window );
-	void        ( *runtime_init_toplevel )( BaseWindow *window );
-	void        ( *all_widgets_showed )   ( BaseWindow *window );
-	gboolean    ( *dialog_response )      ( GtkDialog *dialog, gint code, BaseWindow *window );
-	gboolean    ( *delete_event )         ( BaseWindow *window, GtkWindow *toplevel, GdkEvent *event );
-	GObject   * ( *get_application )      ( BaseWindow *window );
-	gchar     * ( *get_toplevel_name )    ( BaseWindow *window );
-	GtkWindow * ( *get_toplevel_dialog )  ( BaseWindow *window );
-	GtkWindow * ( *get_dialog )           ( BaseWindow *window, const gchar *name );
-	GtkWidget * ( *get_widget )           ( BaseWindow *window, const gchar *name );
-}
-	BaseWindowClass;
+G_BEGIN_DECLS
 
 /* instance properties
  */
@@ -89,18 +54,16 @@ typedef struct {
 #define PROP_WINDOW_TOPLEVEL_DIALOG_STR		"base-window-toplevel-dialog"
 #define PROP_WINDOW_INITIALIZED_STR			"base-window-is-initialized"
 
-GType      base_window_get_type( void );
-
-void       base_window_init( BaseWindow *window );
-void       base_window_run( BaseWindow *window );
+void             base_window_init( BaseWindow *window );
+void             base_window_run( BaseWindow *window );
 
-GtkWindow *base_window_get_toplevel_dialog( BaseWindow *window );
-GObject   *base_window_get_application( BaseWindow *window );
-GtkWindow *base_window_get_dialog( BaseWindow *window, const gchar *name );
-GtkWidget *base_window_get_widget( BaseWindow *window, const gchar *name );
+GtkWindow       *base_window_get_toplevel_dialog( BaseWindow *window );
+BaseApplication *base_window_get_application( BaseWindow *window );
+GtkWindow       *base_window_get_dialog( BaseWindow *window, const gchar *name );
+GtkWidget       *base_window_get_widget( BaseWindow *window, const gchar *name );
 
-void       base_window_error_dlg( BaseWindow *window, GtkMessageType type, const gchar *primary, const gchar *secondary );
-gboolean   base_window_yesno_dlg( BaseWindow *window, GtkMessageType type, const gchar *first, const gchar *second );
+void             base_window_error_dlg( BaseWindow *window, GtkMessageType type, const gchar *primary, const gchar *secondary );
+gboolean         base_window_yesno_dlg( BaseWindow *window, GtkMessageType type, const gchar *first, const gchar *second );
 
 G_END_DECLS
 
diff --git a/src/nact/nact-application.c b/src/nact/nact-application.c
index b99d269..195e6e7 100644
--- a/src/nact/nact-application.c
+++ b/src/nact/nact-application.c
@@ -36,7 +36,6 @@
 #include <gtk/gtk.h>
 
 #include "nact-application.h"
-#include "nact-main-window.h"
 
 #define GLADE_FILENAME				GLADEDIR "/nautilus-actions-config.ui"
 
@@ -48,8 +47,8 @@ struct NactApplicationClassPrivate {
 /* private instance data
  */
 struct NactApplicationPrivate {
-	gboolean dispose_has_run;
-	NAPivot *pivot;
+	gboolean  dispose_has_run;
+	NAPivot  *pivot;
 };
 
 /* private instance properties
@@ -250,6 +249,21 @@ nact_application_new_with_args( int argc, char **argv )
 	);
 }
 
+/**
+ * Returns a pointer on the NAPivot object.
+ *
+ * @application: this NactApplication object.
+ *
+ * The returned pointer is owned by the NactApplication object.
+ * It should not be freed not unref by the caller.
+ */
+NAPivot *
+nact_application_get_pivot( NactApplication *application )
+{
+	g_assert( NACT_IS_APPLICATION( application ));
+	return( NA_PIVOT( application->private->pivot ));
+}
+
 static void
 warn_other_instance( BaseApplication *application )
 {
@@ -302,24 +316,11 @@ get_main_window( BaseApplication *application )
 	static const gchar *thisfn = "nact_application_get_main_window";
 	g_debug( "%s: application=%p", thisfn, application );
 
-	GObject *window = G_OBJECT( nact_main_window_new( G_OBJECT( application )));
+	BaseWindow *window = BASE_WINDOW( nact_main_window_new( application ));
 
-	na_pivot_add_consumer( NA_PIVOT( nact_application_get_pivot( NACT_APPLICATION( application ))), window );
+	na_pivot_add_consumer(
+			NA_PIVOT( nact_application_get_pivot( NACT_APPLICATION( application ))),
+			G_OBJECT( window ));
 
-	return( window );
-}
-
-/**
- * Returns a pointer on the NAPivot object.
- *
- * @application: this NactApplication object.
- *
- * The returned pointer is owned by the NactApplication object.
- * It should not be freed not unref by the caller.
- */
-NAPivot *
-nact_application_get_pivot( NactApplication *application )
-{
-	g_assert( NACT_IS_APPLICATION( application ));
-	return( NA_PIVOT( application->private->pivot ));
+	return( G_OBJECT( window ));
 }
diff --git a/src/nact/nact-application.h b/src/nact/nact-application.h
index 3232965..71bbd4c 100644
--- a/src/nact/nact-application.h
+++ b/src/nact/nact-application.h
@@ -40,6 +40,7 @@
 #include <common/na-pivot.h>
 
 #include "base-application.h"
+#include "nact-main-window.h"
 
 G_BEGIN_DECLS
 
diff --git a/src/nact/nact-assist-export.c b/src/nact/nact-assist-export.c
index 9fbae76..72d8bda 100644
--- a/src/nact/nact-assist-export.c
+++ b/src/nact/nact-assist-export.c
@@ -40,6 +40,7 @@
 #include <common/na-utils.h>
 
 #include "base-application.h"
+#include "nact-main-window.h"
 #include "nact-assist-export.h"
 #include "nact-gconf-writer.h"
 #include "nact-iactions-list.h"
@@ -72,11 +73,12 @@ struct NactAssistExportClassPrivate {
 /* private instance data
  */
 struct NactAssistExportPrivate {
-	gboolean  dispose_has_run;
-	gchar    *uri;
-	GSList   *fnames;
-	gint      errors;
-	gchar    *reason;
+	gboolean        dispose_has_run;
+	NactMainWindow *main_window;
+	gchar          *uri;
+	GSList         *fnames;
+	gint            errors;
+	gchar          *reason;
 };
 
 static GObjectClass *st_parent_class = NULL;
@@ -92,6 +94,7 @@ static NactAssistExport *assist_new( BaseApplication *application );
 
 static gchar            *do_get_iprefs_window_id( NactWindow *window );
 static gchar            *do_get_dialog_name( BaseWindow *dialog );
+static GSList           *get_actions( NactWindow *window );
 static void              on_initial_load_dialog( BaseWindow *dialog );
 static void              on_runtime_init_dialog( BaseWindow *dialog );
 static void              on_apply( NactAssistant *window, GtkAssistant *assistant );
@@ -197,6 +200,7 @@ iactions_list_iface_init( NactIActionsListInterface *iface )
 	static const gchar *thisfn = "nact_assist_export_iactions_list_iface_init";
 	g_debug( "%s: iface=%p", thisfn, iface );
 
+	iface->get_actions = get_actions;
 	iface->on_selection_changed = on_actions_list_selection_changed;
 }
 
@@ -267,12 +271,14 @@ assist_new( BaseApplication *application )
  * @main: the main window of the application.
  */
 void
-nact_assist_export_run( NactWindow *main )
+nact_assist_export_run( NactWindow *main_window )
 {
-	BaseApplication *appli = BASE_APPLICATION( base_window_get_application( BASE_WINDOW( main )));
+	BaseApplication *appli = BASE_APPLICATION( base_window_get_application( BASE_WINDOW( main_window )));
 
 	NactAssistExport *assist = assist_new( appli );
 
+	assist->private->main_window = NACT_MAIN_WINDOW( main_window );
+
 	base_window_run( BASE_WINDOW( assist ));
 }
 
@@ -288,6 +294,12 @@ do_get_dialog_name( BaseWindow *dialog )
 	return( g_strdup( "ExportAssistant" ));
 }
 
+static GSList *
+get_actions( NactWindow *window )
+{
+	return( nact_main_window_get_actions( NACT_ASSIST_EXPORT( window )->private->main_window ));
+}
+
 static void
 on_initial_load_dialog( BaseWindow *dialog )
 {
@@ -392,6 +404,7 @@ assist_initial_load_actions_list( NactAssistExport *window, GtkAssistant *assist
 {
 	g_assert( NACT_IS_IACTIONS_LIST( window ));
 	nact_iactions_list_initial_load( NACT_WINDOW( window ));
+	nact_iactions_list_set_edition_mode( NACT_WINDOW( window ), FALSE );
 	nact_iactions_list_set_multiple_selection( NACT_WINDOW( window ), TRUE );
 	nact_iactions_list_set_send_selection_changed_on_fill_list( NACT_WINDOW( window ), FALSE );
 }
diff --git a/src/nact/nact-assist-import.c b/src/nact/nact-assist-import.c
index d90a2d3..a379c0d 100644
--- a/src/nact/nact-assist-import.c
+++ b/src/nact/nact-assist-import.c
@@ -79,6 +79,7 @@ struct NactAssistImportClassPrivate {
 struct NactAssistImportPrivate {
 	gboolean  dispose_has_run;
 	GSList   *results;
+	GSList   *actions;
 };
 
 static GObjectClass *st_parent_class = NULL;
@@ -227,14 +228,15 @@ assist_new( BaseApplication *application )
  *
  * @main: the main window of the application.
  */
-void
+GSList *
 nact_assist_import_run( NactWindow *main )
 {
 	BaseApplication *appli = BASE_APPLICATION( base_window_get_application( BASE_WINDOW( main )));
-
 	NactAssistImport *assist = assist_new( appli );
 
 	base_window_run( BASE_WINDOW( assist ));
+
+	return( assist->private->actions );
 }
 
 static gchar *
@@ -456,9 +458,13 @@ prepare_importdone( NactAssistImport *window, GtkAssistant *assistant, GtkWidget
 			tmp = g_strdup_printf( _( "%s\t\tUUID: %s\t%s\n\n" ), text, uuid, label );
 			g_free( label );
 			g_free( uuid );
+
+			window->private->actions = g_slist_prepend( window->private->actions, str->action );
+
 		} else {
 			tmp = g_strdup_printf( "%s\t\t NOT OK\n\n", text );
 		}
+
 		g_free( text );
 		text = tmp;
 
@@ -487,24 +493,14 @@ do_import( NactAssistImport *window, GtkAssistant *assistant )
 	static const gchar *thisfn = "nact_assist_import_do_import";
 	g_debug( "%s: window=%p", thisfn, window );
 
-	NAPivot *pivot = NA_PIVOT( nact_window_get_pivot( NACT_WINDOW( window )));
-
 	GtkWidget *chooser = gtk_assistant_get_nth_page( assistant, ASSIST_PAGE_FILES_SELECTION );
 	GSList *uris = gtk_file_chooser_get_uris( GTK_FILE_CHOOSER( chooser ));
 	GSList *is, *msg;
-	gchar *error;
 
 	for( is = uris ; is ; is = is->next ){
 
 		msg = NULL;
-		NAAction *action = nact_gconf_reader_import( G_OBJECT( window ), ( const gchar * ) is->data, &msg );
-
-		if( action && na_pivot_write_action( pivot, action, &error ) != NA_IIO_PROVIDER_WRITE_OK ){
-			g_object_unref( action );
-			action = NULL;
-			msg = g_slist_append( msg, error );
-			g_free( error );
-		}
+		NAAction *action = nact_gconf_reader_import( NACT_WINDOW( window ), ( const gchar * ) is->data, &msg );
 
 		ImportUriStruct *str = g_new0( ImportUriStruct, 1 );
 		str->uri = g_strdup(( const gchar * ) is->data );
diff --git a/src/nact/nact-assist-import.h b/src/nact/nact-assist-import.h
index 93bea85..2338b43 100644
--- a/src/nact/nact-assist-import.h
+++ b/src/nact/nact-assist-import.h
@@ -62,9 +62,9 @@ typedef struct {
 }
 	NactAssistImportClass;
 
-GType nact_assist_import_get_type( void );
+GType   nact_assist_import_get_type( void );
 
-void  nact_assist_import_run( NactWindow *main );
+GSList *nact_assist_import_run( NactWindow *main );
 
 G_END_DECLS
 
diff --git a/src/nact/nact-assistant.c b/src/nact/nact-assistant.c
index 1befe39..ce85353 100644
--- a/src/nact/nact-assistant.c
+++ b/src/nact/nact-assistant.c
@@ -36,6 +36,7 @@
 #include <glib.h>
 #include <glib/gi18n.h>
 
+#include "base-application.h"
 #include "nact-assistant.h"
 
 /* private class data
@@ -68,6 +69,8 @@ static void     instance_set_property( GObject *object, guint property_id, const
 static void     instance_dispose( GObject *application );
 static void     instance_finalize( GObject *application );
 
+static GtkWindow * get_dialog( BaseWindow *window, const gchar *name );
+
 static void     v_assistant_apply( GtkAssistant *assistant, gpointer user_data );
 static void     v_assistant_cancel( GtkAssistant *assistant, gpointer user_data );
 static void     v_assistant_close( GtkAssistant *assistant, gpointer user_data );
@@ -143,6 +146,7 @@ class_init( NactAssistantClass *klass )
 	klass->private = g_new0( NactAssistantClassPrivate, 1 );
 
 	BaseWindowClass *base_class = BASE_WINDOW_CLASS( klass );
+	base_class->get_dialog = get_dialog;
 	base_class->runtime_init_toplevel = on_runtime_init_toplevel;
 
 	klass->on_escape_key_pressed = on_escape_key_pressed;
@@ -235,6 +239,31 @@ instance_finalize( GObject *window )
 	}
 }
 
+/*
+ * cf. http://bugzilla.gnome.org/show_bug.cgi?id=589746
+ * a GtkFileChooseWidget embedded in a GtkAssistant is not displayed
+ * when run more than once
+ *
+ * as a work-around, reload the XML ui each time we run an assistant !
+ */
+static GtkWindow *
+get_dialog( BaseWindow *window, const gchar *name )
+{
+	GtkBuilder *builder = gtk_builder_new();
+
+	BaseApplication *appli = base_window_get_application( window );
+
+	gchar *fname = base_application_get_ui_filename( appli );
+
+	gtk_builder_add_from_file( builder, fname, NULL );
+
+	g_free( fname );
+
+	GtkWindow *dialog = GTK_WINDOW( gtk_builder_get_object( builder, name ));
+
+	return( dialog );
+}
+
 /**
  * Set 'warn on close' property.
  */
diff --git a/src/nact/nact-gconf-reader.c b/src/nact/nact-gconf-reader.c
index 42d8b3b..caf237c 100644
--- a/src/nact/nact-gconf-reader.c
+++ b/src/nact/nact-gconf-reader.c
@@ -39,9 +39,9 @@
 #include <uuid/uuid.h>
 
 #include <common/na-gconf-keys.h>
-#include <common/na-pivot.h>
 #include <common/na-utils.h>
 
+#include "nact-application.h"
 #include "nact-gconf-keys.h"
 #include "nact-gconf-reader.h"
 #include "nact-assistant.h"
@@ -58,7 +58,7 @@ struct NactGConfReaderClassPrivate {
  */
 struct NactGConfReaderPrivate {
 	gboolean         dispose_has_run;
-	NAPivot         *pivot;
+	NactWindow      *window;
 	NAAction        *action;			/* the action that we will return, or NULL */
 	GSList          *messages;
 	gboolean         uuid_set;			/* set at first uuid, then checked against */
@@ -136,6 +136,7 @@ static gboolean         is_uuid_valid( const gchar *uuid );
 static gchar           *get_profile_name_from_key( const gchar *key, const gchar *uuid );
 static gchar           *get_entry_from_key( const gchar *key );
 static void             free_schema_value( NactGConfReader *reader );
+static gboolean         action_exists( NactGConfReader *reader, const gchar *uuid );
 
 GType
 nact_gconf_reader_get_type( void )
@@ -252,7 +253,7 @@ gconf_reader_new( void )
  * Import the specified file as an NAAction XML description.
  */
 NAAction *
-nact_gconf_reader_import( GObject *window, const gchar *uri, GSList **msg )
+nact_gconf_reader_import( NactWindow *window, const gchar *uri, GSList **msg )
 {
 	static const gchar *thisfn = "nact_gconf_reader_import";
 	g_debug( "%s: window=%p, uri=%s, msg=%p", thisfn, window, uri, msg );
@@ -261,9 +262,9 @@ nact_gconf_reader_import( GObject *window, const gchar *uri, GSList **msg )
 	gboolean found = FALSE;
 
 	NactGConfReader *reader = gconf_reader_new();
+	reader->private->window = window;
 
 	g_assert( NACT_IS_ASSISTANT( window ));
-	reader->private->pivot = NA_PIVOT( nact_window_get_pivot( NACT_WINDOW( window )));
 
 	xmlDoc *doc = xmlParseFile( uri );
 	xmlNode *iter;
@@ -385,9 +386,6 @@ gconf_reader_parse_schemalist( NactGConfReader *reader, xmlNode *schema )
  * data found in schema node is imported into the action if and only if
  * the whole node is correct ; else the error is warned (but not fatal)
  *
- * note that versions previous to 1.11 used to export a full schema
- * we have so always a 'locale' even if the value is in 'default'
- *
  * note also that versions previous to 1.11 used to export profile label
  * as if it were not localized (which is a bug, though not signaled)
  * so if the profile label is not found inside of locale node, we search
@@ -554,8 +552,7 @@ gconf_reader_parse_applyto( NactGConfReader *reader, xmlNode *node )
 	if( ret ){
 		if( !reader->private->uuid_set ){
 
-			NAAction *object = na_pivot_get_action( reader->private->pivot, uuid );
-			if( object ){
+			if( action_exists( reader, uuid )){
 				add_message( reader, ERR_UUID_ALREADY_EXISTS, uuid );
 				ret = FALSE;
 
@@ -566,7 +563,7 @@ gconf_reader_parse_applyto( NactGConfReader *reader, xmlNode *node )
 
 		} else {
 			gchar *ref = na_action_get_uuid( reader->private->action );
-			if( strcmp(( const char * ) uuid, ( const char * ) ref )){
+			if( g_ascii_strcasecmp(( const gchar * ) uuid, ( const gchar * ) ref )){
 				add_message( reader, ERR_INVALID_UUID, ref, uuid, node->line );
 				ret = FALSE;
 			}
@@ -582,6 +579,7 @@ gconf_reader_parse_applyto( NactGConfReader *reader, xmlNode *node )
 
 			if( !reader->private->profile ){
 				reader->private->profile = na_action_profile_new();
+				na_action_profile_set_name( reader->private->profile, profile );
 				na_action_attach_profile( reader->private->action, reader->private->profile );
 			}
 		}
@@ -867,3 +865,11 @@ free_schema_value( NactGConfReader *reader )
 		reader_str[i].entry_found = FALSE;
 	}
 }
+
+static gboolean
+action_exists( NactGConfReader *reader, const gchar *uuid )
+{
+	BaseApplication *appli = base_window_get_application( BASE_WINDOW( reader->private->window ));
+	NactMainWindow *main_window = NACT_MAIN_WINDOW( base_application_get_main_window( appli ));
+	return( nact_main_window_action_exists( main_window, uuid ));
+}
diff --git a/src/nact/nact-gconf-reader.h b/src/nact/nact-gconf-reader.h
index fff9993..d1bd09a 100644
--- a/src/nact/nact-gconf-reader.h
+++ b/src/nact/nact-gconf-reader.h
@@ -38,10 +38,7 @@
  * storage subsystem.
  */
 
-#include <glib-object.h>
-
-#include <common/na-action.h>
-#include <common/na-action-profile.h>
+#include "nact-window.h"
 
 G_BEGIN_DECLS
 
@@ -70,7 +67,7 @@ typedef struct {
 
 GType     nact_gconf_reader_get_type( void );
 
-NAAction *nact_gconf_reader_import( GObject *window, const gchar *uri, GSList **msg );
+NAAction *nact_gconf_reader_import( NactWindow *window, const gchar *uri, GSList **msg );
 
 G_END_DECLS
 
diff --git a/src/nact/nact-iactions-list.c b/src/nact/nact-iactions-list.c
index 4ffbbf3..490d898 100644
--- a/src/nact/nact-iactions-list.c
+++ b/src/nact/nact-iactions-list.c
@@ -56,6 +56,7 @@ enum {
 
 /* data set against GObject
  */
+#define IS_EDITION_MODE					"iactions-list-edition-mode"
 #define ACCEPT_MULTIPLE_SELECTION		"iactions-list-accept-multiple-selection"
 #define IS_FILLING_LIST					"iactions-list-is-filling-list"
 #define SEND_SELECTION_CHANGED_MESSAGE	"iactions-list-send-selection-changed-message"
@@ -82,6 +83,7 @@ static GtkWidget *get_actions_list_widget( NactWindow *window );
 static GSList    *get_expanded_rows( NactWindow *window );
 static void       expand_rows( NactWindow *window, GSList *expanded );
 static void       free_expanded_list( GSList *expanded );
+static gboolean   is_edition_mode( NactWindow *window );
 
 GType
 nact_iactions_list_get_type( void )
@@ -285,14 +287,16 @@ nact_iactions_list_fill( NactWindow *window, gboolean keep_expanded )
 		setup_action( widget, ts_model, &iter, action );
 		g_debug( "%s: action=%p", thisfn, action );
 
-		GSList *profiles = na_action_get_profiles( action );
-		GSList *ip;
-		GtkTreeIter profile_iter;
-		for( ip = profiles ; ip ; ip = ip->next ){
-			NAActionProfile *profile = NA_ACTION_PROFILE( ip->data );
-			gtk_tree_store_append( ts_model, &profile_iter, &iter );
-			gtk_tree_store_set( ts_model, &profile_iter, IACTIONS_LIST_NAOBJECT_COLUMN, profile, -1 );
-			setup_profile( widget, ts_model, &profile_iter, profile );
+		if( is_edition_mode( window )){
+			GSList *profiles = na_action_get_profiles( action );
+			GSList *ip;
+			GtkTreeIter profile_iter;
+			for( ip = profiles ; ip ; ip = ip->next ){
+				NAActionProfile *profile = NA_ACTION_PROFILE( ip->data );
+				gtk_tree_store_append( ts_model, &profile_iter, &iter );
+				gtk_tree_store_set( ts_model, &profile_iter, IACTIONS_LIST_NAOBJECT_COLUMN, profile, -1 );
+				setup_profile( widget, ts_model, &profile_iter, profile );
+			}
 		}
 	}
 	/*g_debug( "%s: at end, actions has %d elements", thisfn, g_slist_length( actions ));*/
@@ -655,6 +659,16 @@ nact_iactions_list_update_selected( NactWindow *window, NAAction *action )
 }
 
 /**
+ * Are we in edition mode (vs. selection only mode) ?
+ */
+void
+nact_iactions_list_set_edition_mode( NactWindow *window, gboolean edition )
+{
+	g_assert( NACT_IS_IACTIONS_LIST( window ));
+	g_object_set_data( G_OBJECT( window ), IS_EDITION_MODE, GINT_TO_POINTER( edition ));
+}
+
+/**
  * Does the IActionsList box support multiple selection ?
  */
 void
@@ -846,14 +860,16 @@ display_label( GtkTreeViewColumn *column, GtkCellRenderer *cell, GtkTreeModel *m
 		gboolean modified = FALSE;
 		gboolean valid = TRUE;
 
-		if( NA_IS_ACTION( object )){
-			modified = v_is_modified_action( window, NA_ACTION( object ));
-			valid = v_is_valid_action( window, NA_ACTION( object ));
+		if( is_edition_mode( window )){
+			if( NA_IS_ACTION( object )){
+				modified = v_is_modified_action( window, NA_ACTION( object ));
+				valid = v_is_valid_action( window, NA_ACTION( object ));
 
-		} else {
-			g_assert( NA_IS_ACTION_PROFILE( object ));
-			modified = v_is_modified_profile( window, NA_ACTION_PROFILE( object ));
-			valid = v_is_valid_profile( window, NA_ACTION_PROFILE( object ));
+			} else {
+				g_assert( NA_IS_ACTION_PROFILE( object ));
+				modified = v_is_modified_profile( window, NA_ACTION_PROFILE( object ));
+				valid = v_is_valid_profile( window, NA_ACTION_PROFILE( object ));
+			}
 		}
 
 		if( modified ){
@@ -1027,3 +1043,9 @@ free_expanded_list( GSList *expanded )
 {
 	g_slist_free( expanded );
 }
+
+static gboolean
+is_edition_mode( NactWindow *window )
+{
+	return( GPOINTER_TO_INT( g_object_get_data( G_OBJECT( window ), IS_EDITION_MODE )));
+}
diff --git a/src/nact/nact-iactions-list.h b/src/nact/nact-iactions-list.h
index f0d2f31..68ee951 100644
--- a/src/nact/nact-iactions-list.h
+++ b/src/nact/nact-iactions-list.h
@@ -87,6 +87,7 @@ gboolean  nact_iactions_list_is_expanded( NactWindow *window, const NAAction *ac
 void      nact_iactions_list_toggle_collapse( NactWindow *window, const NAAction *action );
 void      nact_iactions_list_update_selected( NactWindow *window, NAAction *action );
 
+void      nact_iactions_list_set_edition_mode( NactWindow *window, gboolean mode );
 void      nact_iactions_list_set_multiple_selection( NactWindow *window, gboolean multiple );
 void      nact_iactions_list_set_send_selection_changed_on_fill_list( NactWindow *window, gboolean send_message );
 void      nact_iactions_list_set_is_filling_list( NactWindow *window, gboolean is_filling );
diff --git a/src/nact/nact-imenubar.c b/src/nact/nact-imenubar.c
index 7ec4623..3cd9320 100644
--- a/src/nact/nact-imenubar.c
+++ b/src/nact/nact-imenubar.c
@@ -50,6 +50,7 @@ struct NactIMenubarInterfacePrivate {
 #define PROP_IMENUBAR_DELETED_ACTIONS	"nact-imenubar-deleted-actions"
 #define PROP_IMENUBAR_NEW_PROFILE_ITEM	"nact-imenubar-new-profile-item"
 #define PROP_IMENUBAR_SAVE_ITEM			"nact-imenubar-save-item"
+#define PROP_IMENUBAR_DUPLICATE_ITEM	"nact-imenubar-duplicate-item"
 #define PROP_IMENUBAR_DELETE_ITEM		"nact-imenubar-delete-item"
 #define PROP_IMENUBAR_EXPORT_ITEM		"nact-imenubar-export-item"
 
@@ -72,8 +73,12 @@ static void       on_save_activated( GtkMenuItem *item, NactWindow *window );
 static void       on_save_selected( GtkMenuItem *item, NactWindow *window );
 static void       on_quit_activated( GtkMenuItem *item, NactWindow *window );
 static void       on_quit_selected( GtkMenuItem *item, NactWindow *window );
+static void       add_action( NactWindow *window, NAAction *action );
+static void       add_profile( NactWindow *window, NAAction *action, NAActionProfile *profile );
 
 static void       on_edit_selected( GtkMenuItem *item, NactWindow *window );
+static void       on_duplicate_activated( GtkMenuItem *item, NactWindow *window );
+static void       on_duplicate_selected( GtkItem *item, NactWindow *window );
 static void       on_delete_activated( GtkMenuItem *item, NactWindow *window );
 static void       on_delete_selected( GtkItem *item, NactWindow *window );
 
@@ -83,6 +88,8 @@ static void       on_import_selected( GtkItem *item, NactWindow *window );
 static void       on_export_activated( GtkMenuItem *item, NactWindow *window );
 static void       on_export_selected( GtkItem *item, NactWindow *window );
 
+static void       on_help_activated( GtkMenuItem *item, NactWindow *window );
+static void       on_help_selected( GtkItem *item, NactWindow *window );
 static void       on_about_activated( GtkMenuItem *item, NactWindow *window );
 static void       on_about_selected( GtkItem *item, NactWindow *window );
 
@@ -112,6 +119,8 @@ static GtkWidget *get_new_profile_item( NactWindow *window );
 static void       set_new_profile_item( NactWindow *window, GtkWidget *item );
 static GtkWidget *get_save_item( NactWindow *window );
 static void       set_save_item( NactWindow *window, GtkWidget *item );
+static GtkWidget *get_duplicate_item( NactWindow *window );
+static void       set_duplicate_item( NactWindow *window, GtkWidget *item );
 static GtkWidget *get_delete_item( NactWindow *window );
 static void       set_delete_item( NactWindow *window, GtkWidget *item );
 static GtkWidget *get_export_item( NactWindow *window );
@@ -264,7 +273,7 @@ create_file_menu( NactMainWindow *window, GtkMenuBar *menubar )
 	nact_window_signal_connect( NACT_WINDOW( window ), G_OBJECT( file ), "select", G_CALLBACK( on_file_selected ));
 
 	GtkWidget *item = gtk_image_menu_item_new_from_stock( GTK_STOCK_NEW, NULL );
-	/* i18n: 'New action' item in 'File' menu - use same accelerator than GTK_STOCK_NEW item */
+	/* i18n: 'New action' item in 'File' menu */
 	gtk_menu_item_set_label( GTK_MENU_ITEM( item ), _( "_New action" ));
 	gtk_menu_shell_append( GTK_MENU_SHELL( menu ), item );
 	signal_connect( window, item, G_CALLBACK( on_new_action_activated ), G_CALLBACK( on_new_action_selected ));
@@ -300,8 +309,15 @@ create_edit_menu( NactMainWindow *window, GtkMenuBar *menubar )
 	gtk_menu_item_set_submenu( GTK_MENU_ITEM( edit ), menu );
 	nact_window_signal_connect( NACT_WINDOW( window ), G_OBJECT( edit ), "select", G_CALLBACK( on_edit_selected ));
 
+	GtkWidget *item = gtk_image_menu_item_new_from_stock( GTK_STOCK_COPY, NULL );
+	/* i18n: Duplicate item in Edit menu */
+	gtk_menu_item_set_label( GTK_MENU_ITEM( item ), _( "D_uplicate" ));
+	gtk_menu_shell_append( GTK_MENU_SHELL( menu ), item );
+	set_duplicate_item( NACT_WINDOW( window ), item );
+	signal_connect( window, item, G_CALLBACK( on_duplicate_activated ), G_CALLBACK( on_duplicate_selected ));
+
 	/* i18n: Delete item in Edit menu */
-	GtkWidget *item = gtk_image_menu_item_new_from_stock( GTK_STOCK_DELETE, NULL );
+	item = gtk_image_menu_item_new_from_stock( GTK_STOCK_DELETE, NULL );
 	gtk_menu_shell_append( GTK_MENU_SHELL( menu ), item );
 	set_delete_item( NACT_WINDOW( window ), item );
 	signal_connect( window, item, G_CALLBACK( on_delete_activated ), G_CALLBACK( on_delete_selected ));
@@ -319,13 +335,13 @@ create_tools_menu( NactMainWindow *window, GtkMenuBar *menubar )
 	nact_window_signal_connect( NACT_WINDOW( window ), G_OBJECT( tools ), "select", G_CALLBACK( on_tools_selected ));
 
 	/* i18n: Import item in Tools menu */
-	GtkWidget *item = gtk_image_menu_item_new_with_label( _( "_Import" ));
+	GtkWidget *item = gtk_image_menu_item_new_with_label( _( "_Import assistant..." ));
 	gtk_menu_item_set_use_underline( GTK_MENU_ITEM( item ), TRUE );
 	gtk_menu_shell_append( GTK_MENU_SHELL( menu ), item );
 	signal_connect( window, item, G_CALLBACK( on_import_activated ), G_CALLBACK( on_import_selected ));
 
 	/* i18n: Export item in Tools menu */
-	item = gtk_image_menu_item_new_with_label( _( "_Export" ));
+	item = gtk_image_menu_item_new_with_label( _( "E_xport assistant..." ));
 	gtk_menu_item_set_use_underline( GTK_MENU_ITEM( item ), TRUE );
 	gtk_menu_shell_append( GTK_MENU_SHELL( menu ), item );
 	set_export_item( NACT_WINDOW( window ), item );
@@ -342,7 +358,15 @@ create_help_menu( NactMainWindow *window, GtkMenuBar *menubar )
 	GtkWidget *menu = gtk_menu_new();
 	gtk_menu_item_set_submenu( GTK_MENU_ITEM( help ), menu );
 
-	GtkWidget *item = gtk_image_menu_item_new_from_stock( GTK_STOCK_ABOUT, NULL );
+	GtkWidget *item = gtk_image_menu_item_new_from_stock( GTK_STOCK_HELP, NULL );
+	gtk_menu_shell_append( GTK_MENU_SHELL( menu ), item );
+	signal_connect( window, item, G_CALLBACK( on_help_activated ), G_CALLBACK( on_help_selected ));
+	gtk_widget_set_sensitive( item, FALSE );
+
+	item = gtk_separator_menu_item_new();
+	gtk_menu_shell_append( GTK_MENU_SHELL( menu ), item );
+
+	item = gtk_image_menu_item_new_from_stock( GTK_STOCK_ABOUT, NULL );
 	gtk_menu_shell_append( GTK_MENU_SHELL( menu ), item );
 	signal_connect( window, item, G_CALLBACK( on_about_activated ), G_CALLBACK( on_about_selected ));
 }
@@ -378,17 +402,7 @@ static void
 on_new_action_activated( GtkMenuItem *item, NactWindow *window )
 {
 	NAAction *action = na_action_new_with_profile();
-	na_object_check_edited_status( NA_OBJECT( action ));
-	v_add_action( window, action );
-
-	v_update_actions_list( window );
-	v_setup_dialog_title( window );
-
-	gchar *uuid = na_action_get_uuid( action );
-	gchar *label = na_action_get_label( action );
-	v_select_actions_list( window, NA_ACTION_TYPE, uuid, label );
-	g_free( label );
-	g_free( uuid );
+	add_action( window, action );
 }
 
 static void
@@ -410,19 +424,7 @@ on_new_profile_activated( GtkMenuItem *item, NactWindow *window )
 	NAActionProfile *new_profile = na_action_profile_new();
 	g_debug( "nact_imenubar_on_new_profile_activated: action=%p, profile=%p", action, new_profile );
 
-	na_action_attach_profile( action, new_profile );
-	na_object_check_edited_status( NA_OBJECT( new_profile ));
-
-	v_add_profile( window, new_profile );
-
-	v_setup_dialog_title( window );
-	v_update_actions_list( window );
-
-	gchar *uuid = na_action_get_uuid( action );
-	gchar *label = na_action_profile_get_label( new_profile );
-	v_select_actions_list( window, NA_ACTION_PROFILE_TYPE, uuid, label );
-	g_free( label );
-	g_free( uuid );
+	add_profile( window, action, new_profile );
 }
 
 static void
@@ -539,6 +541,40 @@ on_quit_selected( GtkMenuItem *item, NactWindow *window )
 }
 
 static void
+add_action( NactWindow *window, NAAction *action )
+{
+	na_object_check_edited_status( NA_OBJECT( action ));
+	v_add_action( window, action );
+
+	v_update_actions_list( window );
+	v_setup_dialog_title( window );
+
+	gchar *uuid = na_action_get_uuid( action );
+	gchar *label = na_action_get_label( action );
+	v_select_actions_list( window, NA_ACTION_TYPE, uuid, label );
+	g_free( label );
+	g_free( uuid );
+}
+
+static void
+add_profile( NactWindow *window, NAAction *action, NAActionProfile *profile )
+{
+	na_action_attach_profile( action, profile );
+	na_object_check_edited_status( NA_OBJECT( profile ));
+
+	v_add_profile( window, profile );
+
+	v_setup_dialog_title( window );
+	v_update_actions_list( window );
+
+	gchar *uuid = na_action_get_uuid( action );
+	gchar *label = na_action_profile_get_label( profile );
+	v_select_actions_list( window, NA_ACTION_PROFILE_TYPE, uuid, label );
+	g_free( label );
+	g_free( uuid );
+}
+
+static void
 on_edit_selected( GtkMenuItem *item, NactWindow *window )
 {
 	NAObject *object = v_get_selected( window );
@@ -552,8 +588,58 @@ on_edit_selected( GtkMenuItem *item, NactWindow *window )
 			delete_enabled = ( na_action_get_profiles_count( action ) > 1 );
 		}
 	}
+
+	gboolean duplicate_enabled = delete_enabled;
+
 	GtkWidget *delete_item = get_delete_item( window );
 	gtk_widget_set_sensitive( delete_item, delete_enabled );
+
+	GtkWidget *duplicate_item = get_duplicate_item( window );
+	gtk_widget_set_sensitive( duplicate_item, duplicate_enabled );
+}
+
+static void
+on_duplicate_activated( GtkMenuItem *item, NactWindow *window )
+{
+	static const gchar *thisfn = "nact_imenubar_on_duplicate_activated";
+	g_debug( "%s: item=%p, window=%p", thisfn, item, window );
+
+	NAObject *object = v_get_selected( window );
+
+	NAObject *dup = na_object_duplicate( object );
+
+	if( NA_IS_ACTION( object )){
+
+		gchar *label = na_action_get_label( NA_ACTION( object ));
+		/* i18n: label of a duplicated action */
+		gchar *dup_label = g_strdup_printf( _( "Copy of %s" ), label );
+		na_action_set_label( NA_ACTION( dup ), dup_label );
+		na_action_set_new_uuid( NA_ACTION( dup ));
+		g_free( dup_label );
+		g_free( label );
+
+		add_action( window, NA_ACTION( dup ));
+
+	} else {
+		g_assert( NA_IS_ACTION_PROFILE( object ));
+		NAAction *action = na_action_profile_get_action( NA_ACTION_PROFILE( object ));
+
+		gchar *label = na_action_profile_get_label( NA_ACTION_PROFILE( object ));
+		/* i18n: label of a duplicated profile */
+		gchar *dup_label = g_strdup_printf( _( "Copy of %s" ), label );
+		na_action_profile_set_label( NA_ACTION_PROFILE( dup ), dup_label );
+		g_free( dup_label );
+		g_free( label );
+
+		add_profile( window, action, NA_ACTION_PROFILE( dup ));
+	}
+}
+
+static void
+on_duplicate_selected( GtkItem *item, NactWindow *window )
+{
+	/* i18n: tooltip displayed in the status bar when selecting the Duplicate item */
+	display_status( window, _( "Create a copy of the selected action or profile." ));
 }
 
 static void
@@ -610,14 +696,11 @@ on_tools_selected( GtkMenuItem *item, NactWindow *window )
 static void
 on_import_activated( GtkMenuItem *item, NactWindow *window )
 {
-	static const gchar *thisfn = "nact_imenubar_on_import_activated";
-	g_debug( "%s: item=%p, window=%p", thisfn, item, window );
-
-	nact_assist_import_run( NACT_WINDOW( window ));
-
-	/*g_assert( NACT_IS_MAIN_WINDOW( user_data ));
-	NactWindow *wndmain = NACT_WINDOW( user_data );
-	nact_iactions_list_set_focus( wndmain );*/
+	GSList *list = nact_assist_import_run( window );
+	GSList *ia;
+	for( ia = list ; ia ; ia = ia->next ){
+		add_action( window, NA_ACTION( ia->data ));
+	}
 }
 
 static void
@@ -647,6 +730,18 @@ on_export_selected( GtkItem *item, NactWindow *window )
 	display_status( window, _( "Export one or more actions from your configuration to external XML files." ));
 }
 
+static void
+on_help_activated( GtkMenuItem *item, NactWindow *window )
+{
+}
+
+static void
+on_help_selected( GtkItem *item, NactWindow *window )
+{
+	/* i18n: tooltip displayed in the status bar when selecting the Help item */
+	display_status( window, _( "Display help about this program." ));
+}
+
 /* TODO: make the website url and the mail addresses clickables
  */
 static void
@@ -912,6 +1007,18 @@ set_save_item( NactWindow *window, GtkWidget *item )
 }
 
 static GtkWidget *
+get_duplicate_item( NactWindow *window )
+{
+	return( GTK_WIDGET( g_object_get_data( G_OBJECT( window ), PROP_IMENUBAR_DUPLICATE_ITEM )));
+}
+
+static void
+set_duplicate_item( NactWindow *window, GtkWidget *item )
+{
+	g_object_set_data( G_OBJECT( window ), PROP_IMENUBAR_DUPLICATE_ITEM, item );
+}
+
+static GtkWidget *
 get_delete_item( NactWindow *window )
 {
 	return( GTK_WIDGET( g_object_get_data( G_OBJECT( window ), PROP_IMENUBAR_DELETE_ITEM )));
diff --git a/src/nact/nact-main-window.c b/src/nact/nact-main-window.c
index 9140571..016645b 100644
--- a/src/nact/nact-main-window.c
+++ b/src/nact/nact-main-window.c
@@ -426,13 +426,41 @@ instance_finalize( GObject *window )
  * Returns a newly allocated NactMainWindow object.
  */
 NactMainWindow *
-nact_main_window_new( GObject *application )
+nact_main_window_new( BaseApplication *application )
 {
 	g_assert( NACT_IS_APPLICATION( application ));
 
 	return( g_object_new( NACT_MAIN_WINDOW_TYPE, PROP_WINDOW_APPLICATION_STR, application, NULL ));
 }
 
+/**
+ * Returns the current list of actions
+ */
+GSList *
+nact_main_window_get_actions( const NactMainWindow *window )
+{
+	return( window->private->actions );
+}
+
+/**
+ * The specified action does already exist in the list ?
+ */
+gboolean
+nact_main_window_action_exists( const NactMainWindow *window, const gchar *uuid )
+{
+	GSList *ia;
+	for( ia = window->private->actions ; ia ; ia = ia->next ){
+		NAAction *action = NA_ACTION( ia->data );
+		gchar *action_uuid = na_action_get_uuid( action );
+		gboolean ok = ( g_ascii_strcasecmp( action_uuid, uuid ) == 0 );
+		g_free( action_uuid );
+		if( ok ){
+			return( TRUE );
+		}
+	}
+	return( FALSE );
+}
+
 static gchar *
 get_iprefs_window_id( NactWindow *window )
 {
@@ -493,6 +521,7 @@ on_initial_load_toplevel( BaseWindow *window )
 
 	g_assert( NACT_IS_IACTIONS_LIST( window ));
 	nact_iactions_list_initial_load( NACT_WINDOW( window ));
+	nact_iactions_list_set_edition_mode( NACT_WINDOW( window ), TRUE );
 	nact_iactions_list_set_multiple_selection( NACT_WINDOW( window ), FALSE );
 	nact_iactions_list_set_send_selection_changed_on_fill_list( NACT_WINDOW( window ), FALSE );
 
diff --git a/src/nact/nact-main-window.h b/src/nact/nact-main-window.h
index 1a8f8ae..fa2c923 100644
--- a/src/nact/nact-main-window.h
+++ b/src/nact/nact-main-window.h
@@ -66,7 +66,10 @@ typedef struct {
 
 GType           nact_main_window_get_type( void );
 
-NactMainWindow *nact_main_window_new( GObject *application );
+NactMainWindow *nact_main_window_new( BaseApplication *application );
+
+GSList         *nact_main_window_get_actions( const NactMainWindow *window );
+gboolean        nact_main_window_action_exists( const NactMainWindow *window, const gchar *uuid );
 
 G_END_DECLS
 



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