[nautilus-actions] Create import/export assistants
- From: Pierre Wieser <pwieser src gnome org>
- To: svn-commits-list gnome org
- Subject: [nautilus-actions] Create import/export assistants
- Date: Tue, 14 Jul 2009 18:49:51 +0000 (UTC)
commit 05f872662aebed4251a2cd599cac3fe3972edbd3
Author: Pierre Wieser <pwieser trychlos org>
Date: Tue Jul 14 20:24:20 2009 +0200
Create import/export assistants
ChangeLog | 52 ++
src/common/na-action-profile.c | 54 ++-
src/common/na-action-profile.h | 10 +
src/common/na-action.c | 52 ++-
src/common/na-action.h | 5 +-
src/common/na-gconf-keys.h | 2 +-
src/common/na-utils.c | 45 +-
src/common/na-utils.h | 3 +
src/nact/Makefile.am | 15 +-
src/nact/base-application.c | 34 +-
src/nact/base-application.h | 1 +
src/nact/base-window.c | 93 ++-
src/nact/nact-assist-export.c | 695 ++++++++++++++++
src/nact/nact-assist-export.h | 71 ++
src/nact/nact-assist-import.c | 523 ++++++++++++
src/nact/nact-assist-import.h | 71 ++
src/nact/nact-assistant.c | 394 +++++++++
src/nact/nact-assistant.h | 81 ++
.../{nact-gconf-schema.h => nact-gconf-keys.h} | 63 +-
src/nact/nact-gconf-reader.c | 872 ++++++++++++++++++++
src/nact/nact-gconf-reader.h | 77 ++
src/nact/nact-gconf-schema-writer.h | 74 --
src/nact/nact-gconf-schema.c | 144 ----
...t-gconf-schema-writer.c => nact-gconf-writer.c} | 168 +++--
src/nact/nact-gconf-writer.h | 77 ++
src/nact/nact-iactions-list.c | 17 +-
src/nact/nact-iactions-list.h | 2 +-
src/nact/nact-iprefs.c | 4 +-
src/nact/nact-main-window.c | 200 +----
src/nact/nact-window.c | 35 +-
src/nact/nact-window.h | 4 +-
src/nact/nautilus-actions-config.ui | 283 ++++---
32 files changed, 3542 insertions(+), 679 deletions(-)
---
diff --git a/ChangeLog b/ChangeLog
index 2f0a03f..684fd11 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,55 @@
+2009-07-14 Pierre Wieser <pwieser trychlos org>
+
+ Implement import assistant with new object hierarchy.
+
+ * src/common/na-action.c:
+ * src/common/na-action.h (na_action_get_profile):
+ Now returns a NAObject.
+
+ * src/common/na-action.c:
+ * src/common/na-action.h
+ (na_action_set_uuid, na_action_set_version,
+ na_action_add_profile): New functions.
+
+ * src/common/na-action-profile.c:
+ * src/common/na-action-profile.h
+ (na_action_profile_set_label, na_action_profile_set_isfile,
+ na_action_profile_set_isdir, na_action_profile_set_schemes):
+ New functions.
+
+ * src/common/na-action-profile.h:
+ Define ACTION_PROFILE_PREFIX as a way of identifying a profile.
+
+ * src/common/na-utils.c:
+ * src/common/na-utils.h (na_utils_dump_string_list,
+ na_utils_schema_to_gslist, na_utils_schema_to_boolean):
+ New functions.
+
+ * src/nact/nact-assistant.c:
+ * src/nact/nact-assistant.h:
+ * src/nact/nact-assist-export.c:
+ * src/nact/nact-assist-export.h:
+ * src/nact/nact-assist-import.c:
+ * src/nact/nact-gconf-keys.h:
+ * src/nact/nact-gconf-reader.c:
+ * src/nact/nact-gconf-reader.h:
+ * src/nact/nact-gconf-writer.c:
+ * src/nact/nact-gconf-writer.c: New files.
+
+ * src/nact/nact-gconf-schema.c:
+ * src/nact/nact-gconf-schema.h:
+ * src/nact/nact-gconf-schema-writer.c:
+ * src/nact/nact-gconf-schema-writer.h: Removed files.
+
+ * src/nact/Makefile.am: Updated accordingly.
+
+ * src/nact/base-application.c:
+ * src/nact/base-application.h
+ (base_application_search_for_widget): New function.
+
+ * src/nact/base-window.c:
+ Call gtk_main/gtk_main_quit when we are running an assistant.
+
2009-07-08 Pierre Wieser <pwieser trychlos org>
* src/nact/nact-main-window.c:
diff --git a/src/common/na-action-profile.c b/src/common/na-action-profile.c
index 0a75ff5..a931a9d 100644
--- a/src/common/na-action-profile.c
+++ b/src/common/na-action-profile.c
@@ -256,8 +256,8 @@ instance_init( GTypeInstance *instance, gpointer klass )
self->private->dispose_has_run = FALSE;
/* initialize suitable default values
- * i18n: default label for the default profile
*/
+ /* i18n: default label for the default profile */
self->private->label = g_strdup( _( "Default profile" ));
self->private->path = g_strdup( "" );
self->private->parameters = g_strdup( "" );
@@ -855,6 +855,19 @@ validate_schemes( GSList* schemes2test, NautilusFileInfo* file )
}
/**
+ * Set the label for this profile.
+ *
+ * @profile: this NAActionProfile object.
+ *
+ * @label: label to be set.
+ */
+void
+na_action_profile_set_label( NAActionProfile *profile, const gchar *label )
+{
+ g_object_set( G_OBJECT( profile ), PROP_PROFILE_LABEL_STR, label, NULL );
+}
+
+/**
* Set the path of the command for this profile.
*
* @profile: this NAActionProfile object.
@@ -921,6 +934,32 @@ na_action_profile_set_mimetypes( NAActionProfile *profile, GSList *mimetypes )
}
/**
+ * Set the 'isfile' flag on which this profile applies.
+ *
+ * @profile: this NAActionProfile object.
+ *
+ * @isfile: the profile applies only to files.
+ */
+void
+na_action_profile_set_isfile( NAActionProfile *profile, gboolean isfile )
+{
+ g_object_set( G_OBJECT( profile ), PROP_PROFILE_ISFILE_STR, isfile, NULL );
+}
+
+/**
+ * Set the 'isdir' flag on which this profile applies.
+ *
+ * @profile: this NAActionProfile object.
+ *
+ * @isdir: the profile applies only to folders.
+ */
+void
+na_action_profile_set_isdir( NAActionProfile *profile, gboolean isdir )
+{
+ g_object_set( G_OBJECT( profile ), PROP_PROFILE_ISDIR_STR, isdir, NULL );
+}
+
+/**
* Set the 'isfile' and 'isdir' flags on which this profile applies.
*
* @profile: this NAActionProfile object.
@@ -974,6 +1013,19 @@ na_action_profile_set_scheme( NAActionProfile *profile, const gchar *scheme, gbo
}
/**
+ * Set the schemes on which this profile applies.
+ *
+ * @profile: this NAActionProfile object.
+ *
+ * @schemes: list of schemes which apply.
+ */
+void
+na_action_profile_set_schemes( NAActionProfile *profile, GSList *schemes )
+{
+ g_object_set( G_OBJECT( profile ), PROP_PROFILE_SCHEMES_STR, schemes, NULL );
+}
+
+/**
* Determines if the given profile is candidate to be displayed in the
* Nautilus context menu, regarding the list of currently selected
* items.
diff --git a/src/common/na-action-profile.h b/src/common/na-action-profile.h
index b489530..407ee2c 100644
--- a/src/common/na-action-profile.h
+++ b/src/common/na-action-profile.h
@@ -83,6 +83,12 @@ typedef struct {
#define PROP_PROFILE_MIMETYPES_STR "profile-mimetypes"
#define PROP_PROFILE_SCHEMES_STR "profile-schemes"
+/* internal identifier of profiles must begin with the following prefix
+ * this let us identify a profile key versus an action key
+ * corollarily, no action entry must begin with this same prefix
+ */
+#define ACTION_PROFILE_PREFIX "profile-"
+
GType na_action_profile_get_type( void );
NAActionProfile *na_action_profile_new( const NAObject *action, const gchar *name );
@@ -104,14 +110,18 @@ GSList *na_action_profile_get_schemes( const NAActionProfile *profile )
gboolean na_action_profile_are_equal( NAActionProfile *first, NAActionProfile *second );
+void na_action_profile_set_label( NAActionProfile *profile, const gchar *label );
void na_action_profile_set_path( NAActionProfile *profile, const gchar *path );
void na_action_profile_set_parameters( NAActionProfile *profile, const gchar *parameters );
void na_action_profile_set_basenames( NAActionProfile *profile, GSList *basenames );
void na_action_profile_set_matchcase( NAActionProfile *profile, gboolean matchcase );
void na_action_profile_set_mimetypes( NAActionProfile *profile, GSList *mimetypes );
+void na_action_profile_set_isfile( NAActionProfile *profile, gboolean isfile );
+void na_action_profile_set_isdir( NAActionProfile *profile, gboolean isdir );
void na_action_profile_set_isfiledir( NAActionProfile *profile, gboolean isfile, gboolean isdir );
void na_action_profile_set_multiple( NAActionProfile *profile, gboolean multiple );
void na_action_profile_set_scheme( NAActionProfile *profile, const gchar *scheme, gboolean selected );
+void na_action_profile_set_schemes( NAActionProfile *profile, GSList *schemes );
gboolean na_action_profile_is_candidate( const NAActionProfile *profile, GList *files );
gchar *na_action_profile_parse_parameters( const NAActionProfile *profile, GList *files );
diff --git a/src/common/na-action.c b/src/common/na-action.c
index ba69033..89fc892 100644
--- a/src/common/na-action.c
+++ b/src/common/na-action.c
@@ -393,7 +393,7 @@ na_action_new_with_profile( void )
{
NAAction *action = na_action_new( NULL );
- NAActionProfile *profile = na_action_profile_new( NA_OBJECT( action ), "default-profile" );
+ NAActionProfile *profile = na_action_profile_new( NA_OBJECT( action ), ACTION_PROFILE_PREFIX "zero" );
action->private->profiles = g_slist_prepend( action->private->profiles, profile );
@@ -650,6 +650,34 @@ na_action_set_new_uuid( NAAction *action )
}
/**
+ * Set a new uuid for the action.
+ *
+ * @action: action whose uuid is to be set.
+ *
+ * @uuid: new uuid.
+ */
+void
+na_action_set_uuid( NAAction *action, const gchar *uuid )
+{
+ g_assert( NA_IS_ACTION( action ));
+ g_object_set( G_OBJECT( action ), PROP_ACTION_UUID_STR, uuid, NULL );
+}
+
+/**
+ * Set a new version for the action.
+ *
+ * @action: action whose version is to be set.
+ *
+ * @version: new version.
+ */
+void
+na_action_set_version( NAAction *action, const gchar *version )
+{
+ g_assert( NA_IS_ACTION( action ));
+ g_object_set( G_OBJECT( action ), PROP_ACTION_VERSION_STR, version, NULL );
+}
+
+/**
* Set a new label for the action.
*
* @action: action whose label is to be set.
@@ -750,18 +778,18 @@ na_action_are_equal( NAAction *first, NAAction *second )
* The returned pointer is owned by the @action object ; the caller
* should not try to free or unref it.
*/
-GObject *
+NAObject *
na_action_get_profile( const NAAction *action, const gchar *name )
{
g_assert( NA_IS_ACTION( action ));
- GObject *found = NULL;
+ NAObject *found = NULL;
GSList *ip;
for( ip = action->private->profiles ; ip && !found ; ip = ip->next ){
NAActionProfile *iprofile = NA_ACTION_PROFILE( ip->data );
gchar *iname = na_action_profile_get_name( iprofile );
if( !g_ascii_strcasecmp( name, iname )){
- found = G_OBJECT( iprofile );
+ found = NA_OBJECT( iprofile );
}
g_free( iname );
}
@@ -770,6 +798,22 @@ na_action_get_profile( const NAAction *action, const gchar *name )
}
/**
+ * Add a profile at the end of the list of profiles.
+ *
+ * @action: the action.
+ *
+ * @profile: the added profile.
+ */
+void
+na_action_add_profile( NAAction *action, NAObject *profile )
+{
+ g_assert( NA_IS_ACTION( action ));
+ g_assert( NA_IS_ACTION_PROFILE( profile ));
+
+ action->private->profiles = g_slist_append( action->private->profiles, profile );
+}
+
+/**
* Returns the list of profiles of the actions as a GSList of
* NAActionProfile GObjects.
*
diff --git a/src/common/na-action.h b/src/common/na-action.h
index aa9abab..6a05c7b 100644
--- a/src/common/na-action.h
+++ b/src/common/na-action.h
@@ -100,14 +100,17 @@ gboolean na_action_is_readonly( const NAAction *action );
gpointer na_action_get_provider( const NAAction *action );
void na_action_set_new_uuid( NAAction *action );
+void na_action_set_uuid( NAAction *action, const gchar *uuid );
+void na_action_set_version( NAAction *action, const gchar *version );
void na_action_set_label( NAAction *action, const gchar *label );
void na_action_set_tooltip( NAAction *action, const gchar *tooltip );
void na_action_set_icon( NAAction *action, const gchar *icon_name );
gboolean na_action_are_equal( NAAction *first, NAAction *second );
-GObject *na_action_get_profile( const NAAction *action, const gchar *name );
+NAObject *na_action_get_profile( const NAAction *action, const gchar *name );
GSList *na_action_get_profiles( const NAAction *action );
+void na_action_add_profile( NAAction *action, NAObject *profile );
void na_action_set_profiles( NAAction *action, GSList *list );
void na_action_free_profiles( GSList *list );
diff --git a/src/common/na-gconf-keys.h b/src/common/na-gconf-keys.h
index b5d2d61..a1dbc4f 100644
--- a/src/common/na-gconf-keys.h
+++ b/src/common/na-gconf-keys.h
@@ -33,7 +33,7 @@
/* GConf general information
*/
-#define NA_GCONF_CONFIG_PATH NAUTILUS_ACTIONS_CONFIG_GCONF_BASEDIR "/configurations"
+#define NA_GCONF_CONFIG_PATH NAUTILUS_ACTIONS_CONFIG_GCONF_BASEDIR "/configurations"
/* GConf key names
*/
diff --git a/src/common/na-utils.c b/src/common/na-utils.c
index 2d4456d..5b3aa2d 100644
--- a/src/common/na-utils.c
+++ b/src/common/na-utils.c
@@ -170,7 +170,8 @@ na_utils_string_list_to_text( GSList *strlist )
}
/**
- * Extracts a list of strings from a semi-colon-separated text.
+ * Extracts a list of strings from a semi-colon-separated text
+ * (entry text).
*/
GSList *
na_utils_text_to_string_list( const gchar *text )
@@ -201,9 +202,23 @@ na_utils_text_to_string_list( const gchar *text )
return( strlist );
}
+void
+na_utils_dump_string_list( GSList *list )
+{
+ static const gchar *thisfn = "na_utils_dump_string_list";
+ GSList *i;
+ int c;
+
+ g_debug( "%s: list at %p has %d elements", thisfn, list, g_slist_length( list ));
+ for( i=list, c=0 ; i ; i=i->next, c++ ){
+ gchar *s = ( gchar * ) i->data;
+ g_debug( "%s: %2d - %s", thisfn, c, s );
+ }
+}
+
/**
* Converts a list of strings to a comma-separated list of strings,
- * enclosed by brackets.
+ * enclosed by brackets (GConf export format).
*/
gchar *
na_utils_gslist_to_schema( GSList *list )
@@ -231,6 +246,17 @@ na_utils_gslist_to_schema( GSList *list )
}
/**
+ * Converts a string representing a list of strings in a GConf format
+ * to a list of strings.
+ */
+GSList *
+na_utils_schema_to_gslist( const gchar *value )
+{
+ GSList *list = NULL;
+ return( list );
+}
+
+/**
* Converts a boolean to the suitable string for a GConf schema
*/
gchar *
@@ -241,6 +267,21 @@ na_utils_boolean_to_schema( gboolean b )
}
/**
+ * Converts a string to a boolean
+ */
+gboolean
+na_utils_schema_to_boolean( const gchar *value, gboolean default_value )
+{
+ if( !g_ascii_strncasecmp( value, "true", strlen( value ))){
+ return( TRUE );
+ }
+ if( !g_ascii_strncasecmp( value, "false", strlen( value ))){
+ return( FALSE );
+ }
+ return( default_value );
+}
+
+/**
* Concatenates a gchar **list of strings to a GString.
*/
gchar *
diff --git a/src/common/na-utils.h b/src/common/na-utils.h
index fe13916..ab08afe 100644
--- a/src/common/na-utils.h
+++ b/src/common/na-utils.h
@@ -45,9 +45,12 @@ GSList *na_utils_remove_ascii_from_string_list( GSList *list, const gchar *text
void na_utils_free_string_list( GSList *list );
gchar *na_utils_string_list_to_text( GSList *list );
GSList *na_utils_text_to_string_list( const gchar *text );
+void na_utils_dump_string_list( GSList *list );
gchar *na_utils_gslist_to_schema( GSList *list );
+GSList *na_utils_schema_to_gslist( const gchar *value );
gchar *na_utils_boolean_to_schema( gboolean b );
+gboolean na_utils_schema_to_boolean( const gchar *value, gboolean default_value );
/*
* Some functions for GString manipulations.
diff --git a/src/nact/Makefile.am b/src/nact/Makefile.am
index 4df13bb..754fc15 100644
--- a/src/nact/Makefile.am
+++ b/src/nact/Makefile.am
@@ -50,10 +50,17 @@ nautilus_actions_config_SOURCES = \
nact-action-profiles-editor.h \
nact-application.c \
nact-application.h \
- nact-gconf-schema.c \
- nact-gconf-schema.h \
- nact-gconf-schema-writer.c \
- nact-gconf-schema-writer.h \
+ nact-assistant.c \
+ nact-assistant.h \
+ nact-assist-export.c \
+ nact-assist-export.h \
+ nact-assist-import.c \
+ nact-assist-import.h \
+ nact-gconf-keys.h \
+ nact-gconf-reader.c \
+ nact-gconf-reader.h \
+ nact-gconf-writer.c \
+ nact-gconf-writer.h \
nact-iactions-list.c \
nact-iactions-list.h \
nact-imenu-item.c \
diff --git a/src/nact/base-application.c b/src/nact/base-application.c
index 57a8a3c..a8a9e80 100644
--- a/src/nact/base-application.c
+++ b/src/nact/base-application.c
@@ -543,7 +543,7 @@ base_application_get_dialog( BaseApplication *application, const gchar *name )
* @name: the name of the searched widget.
*
* Returns a pointer to the searched widget, or NULL.
- * This pointer is owned by GtkBuilder object, and moust not be freed
+ * This pointer is owned by GtkBuilder object, and must not be freed
* nor unreffed by the caller.
*/
GtkWidget *
@@ -552,14 +552,34 @@ base_application_get_widget( BaseApplication *application, BaseWindow *window, c
/*static const gchar *thisfn = "base_application_get_widget";
g_debug( "%s: application=%p, name=%s", thisfn, application, name );*/
- GtkWidget *widget = NULL;
GtkWindow *toplevel = base_window_get_toplevel_dialog( window );
- if( toplevel ){
- widget = recursive_search_for_child( application, toplevel, name );
- if( widget ){
- g_assert( GTK_IS_WIDGET( widget ));
- }
+ return( base_application_search_for_widget( application, toplevel, name ));
+}
+
+/**
+ * Returns a pointer to the named widget as a dialog's child.
+ *
+ * @application: this BaseApplication.
+ *
+ * @window: a GtkWindow toplevel dialog.
+ *
+ * @name: the name of the searched widget.
+ *
+ * Returns a pointer to the searched widget, or NULL.
+ * This pointer is owned by GtkBuilder object, and must not be freed
+ * nor unreffed by the caller.
+ */
+GtkWidget *
+base_application_search_for_widget( BaseApplication *application, GtkWindow *window, const gchar *name )
+{
+ /*static const gchar *thisfn = "base_application_get_widget";
+ g_debug( "%s: application=%p, name=%s", thisfn, application, name );*/
+
+ GtkWidget *widget = recursive_search_for_child( application, window, name );
+
+ if( widget ){
+ g_assert( GTK_IS_WIDGET( widget ));
}
return( widget );
diff --git a/src/nact/base-application.h b/src/nact/base-application.h
index 757f75a..b4a1599 100644
--- a/src/nact/base-application.h
+++ b/src/nact/base-application.h
@@ -109,6 +109,7 @@ GObject *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 );
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 );
diff --git a/src/nact/base-window.c b/src/nact/base-window.c
index 218090b..a512cf7 100644
--- a/src/nact/base-window.c
+++ b/src/nact/base-window.c
@@ -91,9 +91,9 @@ 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_toplevel_initialized( BaseWindow *window );
-static void set_toplevel_initialized( BaseWindow *window );
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 )
@@ -273,10 +273,17 @@ instance_dispose( GObject *window )
self->private->dispose_has_run = TRUE;
if( is_main_window( BASE_WINDOW( window ))){
+ g_debug( "%s: quitting main window", thisfn );
gtk_main_quit ();
gtk_widget_destroy( GTK_WIDGET( self->private->toplevel_dialog ));
+ } else if( GTK_IS_ASSISTANT( self->private->toplevel_dialog )){
+ g_debug( "%s: quitting assistant", thisfn );
+ gtk_main_quit();
+ gtk_widget_hide_all( GTK_WIDGET( self->private->toplevel_dialog ));
+
} else {
+ g_debug( "%s: quitting dialog", thisfn );
gtk_widget_hide_all( GTK_WIDGET( self->private->toplevel_dialog ));
}
@@ -312,9 +319,13 @@ instance_finalize( GObject *window )
* This is a one-time initialization just after the BaseWindow has been
* allocated. This should leave the BaseWindow object with a valid
* toplevel GtkWindow dialog. This is also time to make one-time
- * initialization on the toplevel dialog.
+ * initialization on this toplevel dialog.
*
* For an every-time initialization, see base_window_run.
+ *
+ * Note that the BaseWindow itself should be initialized each time
+ * the user opens the dialog, though the GtkWindow itself needs only
+ * be initialized the first time it is loaded.
*/
void
base_window_init( BaseWindow *window )
@@ -469,29 +480,30 @@ static void
do_init_window( BaseWindow *window )
{
static const gchar *thisfn = "base_window_do_init_window";
- g_debug( "%s: window=%p", thisfn, window );
-
g_assert( BASE_IS_WINDOW( window ));
- gchar *dialog_name = v_get_toplevel_name( window );
- g_assert( dialog_name && strlen( dialog_name ));
+ if( !window->private->initialized ){
+ g_debug( "%s: window=%p", thisfn, window );
+
+ gchar *dialog_name = v_get_toplevel_name( window );
+ g_assert( dialog_name && strlen( dialog_name ));
+
+ GtkWindow *toplevel = base_window_get_dialog( window, dialog_name );
+ window->private->toplevel_dialog = toplevel;
- GtkWindow *toplevel = base_window_get_dialog( window, dialog_name );
- window->private->toplevel_dialog = toplevel;
+ if( toplevel ){
+ g_assert( GTK_IS_WINDOW( toplevel ));
- if( toplevel ){
- g_assert( GTK_IS_WINDOW( toplevel ));
+ if( !is_toplevel_initialized( window, toplevel )){
- if( !is_toplevel_initialized( window )){
- v_initial_load_toplevel( window );
- set_toplevel_initialized( window );
+ v_initial_load_toplevel( window );
+ set_toplevel_initialized( window, toplevel, TRUE );
+ }
}
- v_runtime_init_toplevel( window );
+ g_free( dialog_name );
+ window->private->initialized = TRUE;
}
-
- g_free( dialog_name );
- window->private->initialized = TRUE;
}
static void
@@ -522,6 +534,8 @@ do_run_window( BaseWindow *window )
base_window_init( window );
}
+ v_runtime_init_toplevel( window );
+
static const gchar *thisfn = "base_window_do_run_window";
g_debug( "%s: window=%p", thisfn, window );
@@ -534,7 +548,12 @@ do_run_window( BaseWindow *window )
g_debug( "%s: starting gtk_main", thisfn );
gtk_main();
+ } else if( GTK_IS_ASSISTANT( this_dialog )){
+ g_debug( "%s: starting gtk_main", thisfn );
+ gtk_main();
+
} else {
+ g_assert( GTK_IS_DIALOG( this_dialog ));
g_debug( "%s: starting gtk_dialog_run", thisfn );
gint code;
do {
@@ -580,30 +599,6 @@ do_get_widget( BaseWindow *window, const gchar *name )
}
static gboolean
-is_toplevel_initialized( BaseWindow *window )
-{
- GtkWindow *toplevel = window->private->toplevel_dialog;
- g_assert( toplevel );
- g_assert( GTK_IS_WINDOW( toplevel ));
-
- gpointer data = g_object_get_data( G_OBJECT( toplevel ), "base-window-toplevel-initialized" );
- if( !data ){
- return( FALSE );
- }
- return(( gboolean ) data );
-}
-
-static void
-set_toplevel_initialized( BaseWindow *window )
-{
- GtkWindow *toplevel = window->private->toplevel_dialog;
- g_assert( toplevel );
- g_assert( GTK_IS_WINDOW( toplevel ));
-
- g_object_set_data( G_OBJECT( toplevel ), "base-window-toplevel-initialized", ( gpointer ) TRUE );
-}
-
-static gboolean
is_main_window( BaseWindow *window )
{
BaseApplication *appli = window->private->application;
@@ -617,6 +612,20 @@ is_main_window( BaseWindow *window )
return( main_dialog == this_dialog );
}
+static gboolean
+is_toplevel_initialized( BaseWindow *window, GtkWindow *toplevel )
+{
+ gboolean initialized;
+ initialized = GPOINTER_TO_UINT( g_object_get_data( G_OBJECT( toplevel ), "base-window-toplevel-initialized" ));
+ return( initialized );
+}
+
+static void
+set_toplevel_initialized( BaseWindow *window, GtkWindow *toplevel, gboolean initialized )
+{
+ g_object_set_data( G_OBJECT( toplevel ), "base-window-toplevel-initialized", GUINT_TO_POINTER( initialized ));
+}
+
void
base_window_error_dlg( BaseWindow *window, GtkMessageType type, const gchar *primary, const gchar *secondary )
{
diff --git a/src/nact/nact-assist-export.c b/src/nact/nact-assist-export.c
new file mode 100644
index 0000000..9fbae76
--- /dev/null
+++ b/src/nact/nact-assist-export.c
@@ -0,0 +1,695 @@
+/*
+ * Nautilus Actions
+ * A Nautilus extension which offers configurable context menu actions.
+ *
+ * Copyright (C) 2005 The GNOME Foundation
+ * Copyright (C) 2006, 2007, 2008 Frederic Ruaudel and others (see AUTHORS)
+ * Copyright (C) 2009 Pierre Wieser and others (see AUTHORS)
+ *
+ * This Program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this Library; see the file COPYING. If not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place,
+ * Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Authors:
+ * Frederic Ruaudel <grumz grumz net>
+ * Rodrigo Moya <rodrigo gnome-db org>
+ * Pierre Wieser <pwieser trychlos org>
+ * ... and many others (see AUTHORS)
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <glib/gi18n.h>
+#include <gtk/gtk.h>
+#include <string.h>
+
+#include <common/na-action.h>
+#include <common/na-utils.h>
+
+#include "base-application.h"
+#include "nact-assist-export.h"
+#include "nact-gconf-writer.h"
+#include "nact-iactions-list.h"
+#include "nact-iprefs.h"
+
+/* Export Assistant
+ *
+ * pos. type title
+ * --- ------- ------------------------------------
+ * 0 Intro Introduction
+ * 1 Content Selection of the actions
+ * 2 Content Selection of the target folder
+ * 3 Confirm Summary of the operations to be done
+ * 4 Summary Export is done: summary of the done operations
+ */
+
+enum {
+ ASSIST_PAGE_INTRO = 0,
+ ASSIST_PAGE_ACTIONS_SELECTION,
+ ASSIST_PAGE_FOLDER_SELECTION,
+ ASSIST_PAGE_CONFIRM,
+ ASSIST_PAGE_DONE
+};
+
+/* private class data
+ */
+struct NactAssistExportClassPrivate {
+};
+
+/* private instance data
+ */
+struct NactAssistExportPrivate {
+ gboolean dispose_has_run;
+ gchar *uri;
+ GSList *fnames;
+ gint errors;
+ gchar *reason;
+};
+
+static GObjectClass *st_parent_class = NULL;
+
+static GType register_type( void );
+static void class_init( NactAssistExportClass *klass );
+static void iactions_list_iface_init( NactIActionsListInterface *iface );
+static void instance_init( GTypeInstance *instance, gpointer klass );
+static void instance_dispose( GObject *application );
+static void instance_finalize( GObject *application );
+
+static NactAssistExport *assist_new( BaseApplication *application );
+
+static gchar *do_get_iprefs_window_id( NactWindow *window );
+static gchar *do_get_dialog_name( BaseWindow *dialog );
+static void on_initial_load_dialog( BaseWindow *dialog );
+static void on_runtime_init_dialog( BaseWindow *dialog );
+static void on_apply( NactAssistant *window, GtkAssistant *assistant );
+static void on_prepare( NactAssistant *window, GtkAssistant *assistant, GtkWidget *page );
+
+static void assist_initial_load_intro( NactAssistExport *window, GtkAssistant *assistant );
+static void assist_runtime_init_intro( NactAssistExport *window, GtkAssistant *assistant );
+static void assist_initial_load_actions_list( NactAssistExport *window, GtkAssistant *assistant );
+static void assist_runtime_init_actions_list( NactAssistExport *window, GtkAssistant *assistant );
+static void on_actions_list_selection_changed( GtkTreeSelection *selection, gpointer user_data );
+static void assist_initial_load_target_folder( NactAssistExport *window, GtkAssistant *assistant );
+static void assist_runtime_init_target_folder( NactAssistExport *window, GtkAssistant *assistant );
+static GtkFileChooser *get_folder_chooser( NactAssistExport *window );
+static void on_folder_selection_changed( GtkFileChooser *chooser, gpointer user_data );
+static gboolean is_writable_dir( const gchar *uri );
+static void assist_initial_load_confirm( NactAssistExport *window, GtkAssistant *assistant );
+static void assist_runtime_init_confirm( NactAssistExport *window, GtkAssistant *assistant );
+static void assist_prepare_confirm( NactAssistExport *window, GtkAssistant *assistant, GtkWidget *page );
+static void assist_initial_load_exportdone( NactAssistExport *window, GtkAssistant *assistant );
+static void assist_runtime_init_exportdone( NactAssistExport *window, GtkAssistant *assistant );
+static void assist_prepare_exportdone( NactAssistExport *window, GtkAssistant *assistant, GtkWidget *page );
+static void do_export( NactAssistExport *window );
+
+#ifdef NACT_MAINTAINER_MODE
+static void dump( NactAssistExport *window );
+#endif
+
+GType
+nact_assist_export_get_type( void )
+{
+ static GType window_type = 0;
+
+ if( !window_type ){
+ window_type = register_type();
+ }
+
+ return( window_type );
+}
+
+static GType
+register_type( void )
+{
+ static const gchar *thisfn = "nact_assist_export_register_type";
+ g_debug( "%s", thisfn );
+
+ static GTypeInfo info = {
+ sizeof( NactAssistExportClass ),
+ ( GBaseInitFunc ) NULL,
+ ( GBaseFinalizeFunc ) NULL,
+ ( GClassInitFunc ) class_init,
+ NULL,
+ NULL,
+ sizeof( NactAssistExport ),
+ 0,
+ ( GInstanceInitFunc ) instance_init
+ };
+
+ GType type = g_type_register_static( NACT_ASSISTANT_TYPE, "NactAssistExport", &info, 0 );
+
+ /* implement IActionsList interface
+ */
+ static const GInterfaceInfo iactions_list_iface_info = {
+ ( GInterfaceInitFunc ) iactions_list_iface_init,
+ NULL,
+ NULL
+ };
+
+ g_type_add_interface_static( type, NACT_IACTIONS_LIST_TYPE, &iactions_list_iface_info );
+
+ return( type );
+}
+
+static void
+class_init( NactAssistExportClass *klass )
+{
+ static const gchar *thisfn = "nact_assist_export_class_init";
+ g_debug( "%s: klass=%p", thisfn, klass );
+
+ st_parent_class = g_type_class_peek_parent( klass );
+
+ GObjectClass *object_class = G_OBJECT_CLASS( klass );
+ object_class->dispose = instance_dispose;
+ object_class->finalize = instance_finalize;
+
+ klass->private = g_new0( NactAssistExportClassPrivate, 1 );
+
+ BaseWindowClass *base_class = BASE_WINDOW_CLASS( klass );
+ base_class->get_toplevel_name = do_get_dialog_name;
+ base_class->initial_load_toplevel = on_initial_load_dialog;
+ base_class->runtime_init_toplevel = on_runtime_init_dialog;
+
+ NactWindowClass *nact_class = NACT_WINDOW_CLASS( klass );
+ nact_class->get_iprefs_window_id = do_get_iprefs_window_id;
+
+ NactAssistantClass *assist_class = NACT_ASSISTANT_CLASS( klass );
+ assist_class->on_assistant_apply = on_apply;
+ assist_class->on_assistant_prepare = on_prepare;
+}
+
+static void
+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->on_selection_changed = on_actions_list_selection_changed;
+}
+
+static void
+instance_init( GTypeInstance *instance, gpointer klass )
+{
+ static const gchar *thisfn = "nact_assist_export_instance_init";
+ g_debug( "%s: instance=%p, klass=%p", thisfn, instance, klass );
+
+ g_assert( NACT_IS_ASSIST_EXPORT( instance ));
+ NactAssistExport *self = NACT_ASSIST_EXPORT( instance );
+
+ self->private = g_new0( NactAssistExportPrivate, 1 );
+
+ self->private->dispose_has_run = FALSE;
+ self->private->fnames = NULL;
+ self->private->errors = 0;
+}
+
+static void
+instance_dispose( GObject *window )
+{
+ static const gchar *thisfn = "nact_assist_export_instance_dispose";
+ g_debug( "%s: window=%p", thisfn, window );
+
+ g_assert( NACT_IS_ASSIST_EXPORT( window ));
+ NactAssistExport *self = NACT_ASSIST_EXPORT( window );
+
+ if( !self->private->dispose_has_run ){
+
+ self->private->dispose_has_run = TRUE;
+
+ /* chain up to the parent class */
+ G_OBJECT_CLASS( st_parent_class )->dispose( window );
+ }
+}
+
+static void
+instance_finalize( GObject *window )
+{
+ static const gchar *thisfn = "nact_assist_export_instance_finalize";
+ g_debug( "%s: window=%p", thisfn, window );
+
+ g_assert( NACT_IS_ASSIST_EXPORT( window ));
+ NactAssistExport *self = ( NactAssistExport * ) window;
+
+ g_free( self->private->uri );
+ na_utils_free_string_list( self->private->fnames );
+ g_free( self->private->reason );
+
+ g_free( self->private );
+
+ /* chain call to parent class */
+ if( st_parent_class->finalize ){
+ G_OBJECT_CLASS( st_parent_class )->finalize( window );
+ }
+}
+
+static NactAssistExport *
+assist_new( BaseApplication *application )
+{
+ return( g_object_new( NACT_ASSIST_EXPORT_TYPE, PROP_WINDOW_APPLICATION_STR, application, NULL ));
+}
+
+/**
+ * Run the assistant.
+ *
+ * @main: the main window of the application.
+ */
+void
+nact_assist_export_run( NactWindow *main )
+{
+ BaseApplication *appli = BASE_APPLICATION( base_window_get_application( BASE_WINDOW( main )));
+
+ NactAssistExport *assist = assist_new( appli );
+
+ base_window_run( BASE_WINDOW( assist ));
+}
+
+static gchar *
+do_get_iprefs_window_id( NactWindow *window )
+{
+ return( g_strdup( "export-assistant" ));
+}
+
+static gchar *
+do_get_dialog_name( BaseWindow *dialog )
+{
+ return( g_strdup( "ExportAssistant" ));
+}
+
+static void
+on_initial_load_dialog( BaseWindow *dialog )
+{
+ static const gchar *thisfn = "nact_assist_export_on_initial_load_dialog";
+
+ /* call parent class at the very beginning */
+ if( BASE_WINDOW_CLASS( st_parent_class )->initial_load_toplevel ){
+ BASE_WINDOW_CLASS( st_parent_class )->initial_load_toplevel( dialog );
+ }
+
+ g_debug( "%s: dialog=%p", thisfn, dialog );
+ g_assert( NACT_IS_ASSIST_EXPORT( dialog ));
+ NactAssistExport *window = NACT_ASSIST_EXPORT( dialog );
+
+ GtkAssistant *assistant = GTK_ASSISTANT( base_window_get_toplevel_dialog( dialog ));
+
+ assist_initial_load_intro( window, assistant );
+ assist_initial_load_actions_list( window, assistant );
+ assist_initial_load_target_folder( window, assistant );
+ assist_initial_load_confirm( window, assistant );
+ assist_initial_load_exportdone( window, assistant );
+}
+
+static void
+on_runtime_init_dialog( BaseWindow *dialog )
+{
+ static const gchar *thisfn = "nact_assist_export_on_runtime_init_dialog";
+
+ /* call parent class at the very beginning */
+ if( BASE_WINDOW_CLASS( st_parent_class )->runtime_init_toplevel ){
+ BASE_WINDOW_CLASS( st_parent_class )->runtime_init_toplevel( dialog );
+ }
+
+ g_debug( "%s: dialog=%p", thisfn, dialog );
+ g_assert( NACT_IS_ASSIST_EXPORT( dialog ));
+ NactAssistExport *window = NACT_ASSIST_EXPORT( dialog );
+
+ GtkAssistant *assistant = GTK_ASSISTANT( base_window_get_toplevel_dialog( dialog ));
+
+ assist_runtime_init_intro( window, assistant );
+ assist_runtime_init_actions_list( window, assistant );
+ assist_runtime_init_target_folder( window, assistant );
+ assist_runtime_init_confirm( window, assistant );
+ assist_runtime_init_exportdone( window, assistant );
+}
+
+/*
+ * As of 1.11, nact_gconf_writer doesn't return any error message.
+ * An error is simply indicated by returning a null filename.
+ * So we provide a general error message.
+ *
+ * apply signal is ran from the confirm page _after_ the prepare signal
+ * of the summary page ; it is so almost useless to do anything here if
+ * we want show the result on the summary...
+ */
+static void
+on_apply( NactAssistant *window, GtkAssistant *assistant )
+{
+ static const gchar *thisfn = "nact_assist_export_on_apply";
+ g_debug( "%s: window=%p, assistant=%p", thisfn, window, assistant );
+}
+
+static void
+on_prepare( NactAssistant *window, GtkAssistant *assistant, GtkWidget *page )
+{
+ /*static const gchar *thisfn = "nact_assist_export_on_prepare";
+ g_debug( "%s: window=%p, assistant=%p, page=%p", thisfn, window, assistant, page );*/
+
+ GtkAssistantPageType type = gtk_assistant_get_page_type( assistant, page );
+
+ switch( type ){
+ case GTK_ASSISTANT_PAGE_CONFIRM:
+ assist_prepare_confirm( NACT_ASSIST_EXPORT( window ), assistant, page );
+ break;
+
+ case GTK_ASSISTANT_PAGE_SUMMARY:
+ assist_prepare_exportdone( NACT_ASSIST_EXPORT( window ), assistant, page );
+ break;
+
+ default:
+ break;
+ }
+}
+
+static void
+assist_initial_load_intro( NactAssistExport *window, GtkAssistant *assistant )
+{
+}
+
+static void
+assist_runtime_init_intro( NactAssistExport *window, GtkAssistant *assistant )
+{
+ static const gchar *thisfn = "nact_assist_export_runtime_init_intro";
+ g_debug( "%s: window=%p, assistant=%p", thisfn, window, assistant );
+
+ GtkWidget *content = gtk_assistant_get_nth_page( assistant, ASSIST_PAGE_INTRO );
+ gtk_assistant_set_page_complete( assistant, content, TRUE );
+}
+
+static void
+assist_initial_load_actions_list( NactAssistExport *window, GtkAssistant *assistant )
+{
+ g_assert( NACT_IS_IACTIONS_LIST( window ));
+ nact_iactions_list_initial_load( NACT_WINDOW( window ));
+ nact_iactions_list_set_multiple_selection( NACT_WINDOW( window ), TRUE );
+ nact_iactions_list_set_send_selection_changed_on_fill_list( NACT_WINDOW( window ), FALSE );
+}
+
+static void
+assist_runtime_init_actions_list( NactAssistExport *window, GtkAssistant *assistant )
+{
+ nact_iactions_list_runtime_init( NACT_WINDOW( window ));
+
+ GtkWidget *content = gtk_assistant_get_nth_page( assistant, ASSIST_PAGE_ACTIONS_SELECTION );
+ gtk_assistant_set_page_complete( assistant, content, FALSE );
+}
+
+static void
+on_actions_list_selection_changed( GtkTreeSelection *selection, gpointer user_data )
+{
+ /*static const gchar *thisfn = "nact_assist_export_on_actions_list_selection_changed";
+ g_debug( "%s: selection=%p, user_data=%p", thisfn, selection, user_data );*/
+
+ g_assert( NACT_IS_ASSIST_EXPORT( user_data ));
+ GtkAssistant *assistant = GTK_ASSISTANT( base_window_get_toplevel_dialog( BASE_WINDOW( user_data )));
+ gint pos = gtk_assistant_get_current_page( assistant );
+ if( pos == ASSIST_PAGE_ACTIONS_SELECTION ){
+
+ gboolean enabled = ( gtk_tree_selection_count_selected_rows( selection ) > 0 );
+
+ GtkWidget *content = gtk_assistant_get_nth_page( assistant, pos );
+ gtk_assistant_set_page_complete( assistant, content, enabled );
+ gtk_assistant_update_buttons_state( assistant );
+ }
+}
+
+static void
+assist_initial_load_target_folder( NactAssistExport *window, GtkAssistant *assistant )
+{
+ GtkFileChooser *chooser = get_folder_chooser( window );
+ gtk_file_chooser_set_action( GTK_FILE_CHOOSER( chooser ), GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER );
+ gtk_file_chooser_set_select_multiple( GTK_FILE_CHOOSER( chooser ), FALSE );
+}
+
+static void
+assist_runtime_init_target_folder( NactAssistExport *window, GtkAssistant *assistant )
+{
+ GtkFileChooser *chooser = get_folder_chooser( window );
+ gtk_file_chooser_unselect_all( chooser );
+
+ gchar *uri = nact_iprefs_get_export_folder_uri( NACT_WINDOW( window ));
+ if( uri && strlen( uri )){
+ gtk_file_chooser_set_uri( GTK_FILE_CHOOSER( chooser ), uri );
+ }
+ g_free( uri );
+
+ nact_window_signal_connect( NACT_WINDOW( window ), G_OBJECT( chooser ), "selection-changed", G_CALLBACK( on_folder_selection_changed ));
+
+ GtkWidget *content = gtk_assistant_get_nth_page( assistant, ASSIST_PAGE_FOLDER_SELECTION );
+ gtk_assistant_set_page_complete( assistant, content, FALSE );
+}
+
+static GtkFileChooser *
+get_folder_chooser( NactAssistExport *window )
+{
+ return( GTK_FILE_CHOOSER( base_window_get_widget( BASE_WINDOW( window ), "ExportFolderChooser" )));
+}
+
+/*
+ * we check the selected uri for writability
+ * this is always subject to become invalid before actually writing
+ * but this is better than nothing, doesn't ?
+ */
+static void
+on_folder_selection_changed( GtkFileChooser *chooser, gpointer user_data )
+{
+ static const gchar *thisfn = "nact_assist_export_on_folder_selection_changed";
+ g_debug( "%s: chooser=%p, user_data=%p", thisfn, chooser, user_data );
+
+ g_assert( NACT_IS_ASSIST_EXPORT( user_data ));
+ GtkAssistant *assistant = GTK_ASSISTANT( base_window_get_toplevel_dialog( BASE_WINDOW( user_data )));
+ gint pos = gtk_assistant_get_current_page( assistant );
+ if( pos == ASSIST_PAGE_FOLDER_SELECTION ){
+
+ gchar *uri = gtk_file_chooser_get_uri( chooser );
+ g_debug( "%s: uri=%s", thisfn, uri );
+ gboolean enabled = ( uri && strlen( uri ) && is_writable_dir( uri ));
+
+ if( enabled ){
+ NactAssistExport *assist = NACT_ASSIST_EXPORT( user_data );
+ g_free( assist->private->uri );
+ assist->private->uri = g_strdup( uri );
+ nact_iprefs_save_export_folder_uri( NACT_WINDOW( user_data ), uri );
+ }
+
+ g_free( uri );
+
+ GtkWidget *content = gtk_assistant_get_nth_page( assistant, pos );
+ gtk_assistant_set_page_complete( assistant, content, enabled );
+ gtk_assistant_update_buttons_state( assistant );
+ }
+}
+
+static gboolean
+is_writable_dir( const gchar *uri )
+{
+ static const gchar *thisfn = "nact_assist_export_is_writable_dir";
+
+ if( !uri || !strlen( uri )){
+ return( FALSE );
+ }
+
+ GFile *file = g_file_new_for_uri( uri );
+ GError *error = NULL;
+ GFileInfo *info = g_file_query_info( file,
+ G_FILE_ATTRIBUTE_ACCESS_CAN_WRITE "," G_FILE_ATTRIBUTE_STANDARD_TYPE,
+ G_FILE_QUERY_INFO_NONE, NULL, &error );
+
+ if( error ){
+ g_warning( "%s: g_file_query_info error: %s", thisfn, error->message );
+ g_error_free( error );
+ g_object_unref( file );
+ return( FALSE );
+ }
+
+ GFileType type = g_file_info_get_file_type( info );
+ if( type != G_FILE_TYPE_DIRECTORY ){
+ g_warning( "%s: %s is not a directory", thisfn, uri );
+ g_object_unref( info );
+ return( FALSE );
+ }
+
+ gboolean writable = g_file_info_get_attribute_boolean( info, G_FILE_ATTRIBUTE_ACCESS_CAN_WRITE );
+ if( !writable ){
+ g_warning( "%s: %s is not writable", thisfn, uri );
+ }
+ g_object_unref( info );
+
+ return( writable );
+}
+
+static void
+assist_initial_load_confirm( NactAssistExport *window, GtkAssistant *assistant )
+{
+}
+
+static void
+assist_runtime_init_confirm( NactAssistExport *window, GtkAssistant *assistant )
+{
+}
+
+static void
+assist_prepare_confirm( NactAssistExport *window, GtkAssistant *assistant, GtkWidget *page )
+{
+ static const gchar *thisfn = "nact_assist_export_prepare_confirm";
+ g_debug( "%s: window=%p, assistant=%p, page=%p", thisfn, window, assistant, page );
+
+#ifdef NACT_MAINTAINER_MODE
+ dump( window );
+#endif
+
+ gchar *text = g_strdup( _( "<b>About to export selected actions :</b>\n\n" ));
+
+ GSList *actions = nact_iactions_list_get_selected_actions( NACT_WINDOW( window ));
+ GSList *ia;
+ gchar *tmp;
+
+ for( ia = actions ; ia ; ia = ia->next ){
+ tmp = g_strdup_printf( "%s\t%s\n", text, na_action_get_label( NA_ACTION( ia->data )));
+ g_free( text );
+ text = tmp;
+ }
+
+ g_assert( window->private->uri && strlen( window->private->uri ));
+
+ tmp = g_strdup_printf( _( "%s\n\n<b>Into the destination folder :</b>\n\n\t%s" ), text, window->private->uri );
+ g_free( text );
+ text = tmp;
+
+ gtk_label_set_markup( GTK_LABEL( page ), text );
+ g_free( text );
+
+ gtk_assistant_set_page_complete( assistant, page, TRUE );
+}
+
+static void
+assist_initial_load_exportdone( NactAssistExport *window, GtkAssistant *assistant )
+{
+}
+
+static void
+assist_runtime_init_exportdone( NactAssistExport *window, GtkAssistant *assistant )
+{
+}
+
+static void
+assist_prepare_exportdone( NactAssistExport *window, GtkAssistant *assistant, GtkWidget *page )
+{
+ static const gchar *thisfn = "nact_assist_export_prepare_exportdone";
+ g_debug( "%s: window=%p, assistant=%p, page=%p", thisfn, window, assistant, page );
+
+ do_export( window );
+
+#ifdef NACT_MAINTAINER_MODE
+ dump( window );
+#endif
+
+ gchar *text, *tmp;
+
+ if( window->private->errors ){
+ text = g_strdup_printf(
+ _( "<b>One or more errors have been detected when exporting actions.</b>\n\n%s" ),
+ window->private->reason );
+
+ } else {
+ text = g_strdup( _( "<b>Selected actions have been successfully exported...</b>\n\n" ));
+
+ tmp = g_strdup_printf( _( "%s<b>...in folder :</b>\n\n\t%s/\n\n" ), text, window->private->uri );
+ g_free( text );
+ text = tmp;
+
+ tmp = g_strdup_printf( _( "%s<b>...as files :</b>\n\n" ), text );
+ g_free( text );
+ text = tmp;
+
+ GSList *ifn;
+ for( ifn = window->private->fnames ; ifn ; ifn = ifn->next ){
+ GFile *file = g_file_new_for_uri(( gchar * ) ifn->data );
+ gchar *bname = g_file_get_basename( file );
+ tmp = g_strdup_printf( "%s\t%s\n", text, bname );
+ g_free( bname );
+ g_object_unref( file );
+ g_free( text );
+ text = tmp;
+ }
+ }
+
+ gtk_label_set_markup( GTK_LABEL( page ), text );
+ g_free( text );
+
+ gtk_assistant_set_page_complete( assistant, page, TRUE );
+ nact_assistant_set_warn_on_cancel( NACT_ASSISTANT( window ), FALSE );
+}
+
+static void
+do_export( NactAssistExport *window )
+{
+ static const gchar *thisfn = "nact_assist_export_do_export";
+ g_debug( "%s: window=%p", thisfn, window );
+
+ GSList *actions = nact_iactions_list_get_selected_actions( NACT_WINDOW( window ));
+ GSList *ia;
+ gchar *msg = NULL;
+ gchar *reason = NULL;
+ gchar *tmp;
+
+ g_assert( window->private->uri && strlen( window->private->uri ));
+
+ for( ia = actions ; ia ; ia = ia->next ){
+ NAAction *action = NA_ACTION( ia->data );
+ gchar *fname = nact_gconf_writer_export( action, window->private->uri, &msg );
+
+ if( fname && strlen( fname )){
+ window->private->fnames = g_slist_prepend( window->private->fnames, fname );
+ g_debug( "%s: fname=%s", thisfn, fname );
+
+ } else {
+ window->private->errors += 1;
+ if( msg ){
+ if( reason ){
+ tmp = g_strdup_printf( "%s\n", reason );
+ g_free( reason );
+ reason = tmp;
+ }
+ tmp = g_strdup_printf( "%s%s", reason, msg );
+ g_free( reason );
+ reason = tmp;
+ g_free( msg );
+ }
+ }
+ }
+
+ if( window->private->errors ){
+ if( !reason ){
+ reason = g_strdup( _( "You may not have writing permissions on selected folder." ));
+ }
+ window->private->reason = reason;
+ }
+
+ g_slist_free( actions );
+}
+
+#ifdef NACT_MAINTAINER_MODE
+static void
+dump( NactAssistExport *window )
+{
+ static const gchar *thisfn = "nact_assist_export_dump";
+ g_debug( "%s: window=%p", thisfn, window );
+ g_debug( "%s: private=%p", thisfn, window->private );
+ g_debug( "%s: dispose_has_run=%s", thisfn, window->private->dispose_has_run ? "True":"False" );
+ g_debug( "%s: uri=%s", thisfn, window->private->uri );
+ g_debug( "%s: errors=%d", thisfn, window->private->errors );
+ na_utils_dump_string_list( window->private->fnames );
+}
+#endif
diff --git a/src/nact/nact-assist-export.h b/src/nact/nact-assist-export.h
new file mode 100644
index 0000000..f61f001
--- /dev/null
+++ b/src/nact/nact-assist-export.h
@@ -0,0 +1,71 @@
+/*
+ * Nautilus Actions
+ * A Nautilus extension which offers configurable context menu actions.
+ *
+ * Copyright (C) 2005 The GNOME Foundation
+ * Copyright (C) 2006, 2007, 2008 Frederic Ruaudel and others (see AUTHORS)
+ * Copyright (C) 2009 Pierre Wieser and others (see AUTHORS)
+ *
+ * This Program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this Library; see the file COPYING. If not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place,
+ * Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Authors:
+ * Frederic Ruaudel <grumz grumz net>
+ * Rodrigo Moya <rodrigo gnome-db org>
+ * Pierre Wieser <pwieser trychlos org>
+ * ... and many others (see AUTHORS)
+ */
+
+#ifndef __NACT_ASSIST_EXPORT_H__
+#define __NACT_ASSIST_EXPORT_H__
+
+/*
+ * NactAssistExport class definition.
+ */
+
+#include "nact-assistant.h"
+
+G_BEGIN_DECLS
+
+#define NACT_ASSIST_EXPORT_TYPE ( nact_assist_export_get_type())
+#define NACT_ASSIST_EXPORT( object ) ( G_TYPE_CHECK_INSTANCE_CAST( object, NACT_ASSIST_EXPORT_TYPE, NactAssistExport ))
+#define NACT_ASSIST_EXPORT_CLASS( klass ) ( G_TYPE_CHECK_CLASS_CAST( klass, NACT_ASSIST_EXPORT_TYPE, NactAssistExportClass ))
+#define NACT_IS_ASSIST_EXPORT( object ) ( G_TYPE_CHECK_INSTANCE_TYPE( object, NACT_ASSIST_EXPORT_TYPE ))
+#define NACT_IS_ASSIST_EXPORT_CLASS( klass ) ( G_TYPE_CHECK_CLASS_TYPE(( klass ), NACT_ASSIST_EXPORT_TYPE ))
+#define NACT_ASSIST_EXPORT_GET_CLASS( object ) ( G_TYPE_INSTANCE_GET_CLASS(( object ), NACT_ASSIST_EXPORT_TYPE, NactAssistExportClass ))
+
+typedef struct NactAssistExportPrivate NactAssistExportPrivate;
+
+typedef struct {
+ NactAssistant parent;
+ NactAssistExportPrivate *private;
+}
+ NactAssistExport;
+
+typedef struct NactAssistExportClassPrivate NactAssistExportClassPrivate;
+
+typedef struct {
+ NactAssistantClass parent;
+ NactAssistExportClassPrivate *private;
+}
+ NactAssistExportClass;
+
+GType nact_assist_export_get_type( void );
+
+void nact_assist_export_run( NactWindow *main );
+
+G_END_DECLS
+
+#endif /* __NACT_ASSIST_EXPORT_H__ */
diff --git a/src/nact/nact-assist-import.c b/src/nact/nact-assist-import.c
new file mode 100644
index 0000000..64c1726
--- /dev/null
+++ b/src/nact/nact-assist-import.c
@@ -0,0 +1,523 @@
+/*
+ * Nautilus Actions
+ * A Nautilus extension which offers configurable context menu actions.
+ *
+ * Copyright (C) 2005 The GNOME Foundation
+ * Copyright (C) 2006, 2007, 2008 Frederic Ruaudel and others (see AUTHORS)
+ * Copyright (C) 2009 Pierre Wieser and others (see AUTHORS)
+ *
+ * This Program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this Library; see the file COPYING. If not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place,
+ * Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Authors:
+ * Frederic Ruaudel <grumz grumz net>
+ * Rodrigo Moya <rodrigo gnome-db org>
+ * Pierre Wieser <pwieser trychlos org>
+ * ... and many others (see AUTHORS)
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <glib/gi18n.h>
+#include <gtk/gtk.h>
+#include <string.h>
+
+#include <common/na-action.h>
+#include <common/na-utils.h>
+
+#include "base-application.h"
+#include "nact-assist-import.h"
+#include "nact-gconf-reader.h"
+#include "nact-iprefs.h"
+
+/* Import Assistant
+ *
+ * pos. type title
+ * --- ------- ------------------------------------
+ * 0 Intro Introduction
+ * 1 Content Selection of the files
+ * 2 Confirm Display the selected files before import
+ * 3 Summary Import is done: summary of the done operations
+ */
+
+enum {
+ ASSIST_PAGE_INTRO = 0,
+ ASSIST_PAGE_FILES_SELECTION,
+ ASSIST_PAGE_CONFIRM,
+ ASSIST_PAGE_DONE
+};
+
+typedef struct {
+ gchar *uri;
+ NAAction *action;
+ GSList *msg;
+}
+ ImportUriStruct;
+
+/* private class data
+ */
+struct NactAssistImportClassPrivate {
+};
+
+/* private instance data
+ */
+struct NactAssistImportPrivate {
+ gboolean dispose_has_run;
+ GSList *results;
+};
+
+static GObjectClass *st_parent_class = NULL;
+
+static GType register_type( void );
+static void class_init( NactAssistImportClass *klass );
+static void instance_init( GTypeInstance *instance, gpointer klass );
+static void instance_dispose( GObject *application );
+static void instance_finalize( GObject *application );
+
+static NactAssistImport *assist_new( BaseApplication *application );
+
+static gchar *do_get_iprefs_window_id( NactWindow *window );
+static gchar *do_get_dialog_name( BaseWindow *dialog );
+static void on_runtime_init_dialog( BaseWindow *dialog );
+static void runtime_init_intro( NactAssistImport *window, GtkAssistant *assistant );
+static void runtime_init_file_selector( NactAssistImport *window, GtkAssistant *assistant );
+static void on_file_selection_changed( GtkFileChooser *chooser, gpointer user_data );
+static gboolean has_readable_files( GSList *uris );
+static void on_prepare( NactAssistant *window, GtkAssistant *assistant, GtkWidget *page );
+static void prepare_confirm( NactAssistImport *window, GtkAssistant *assistant, GtkWidget *page );
+static void prepare_importdone( NactAssistImport *window, GtkAssistant *assistant, GtkWidget *page );
+static void do_import( NactAssistImport *window, GtkAssistant *assistant );
+static void free_results( GSList *list );
+
+GType
+nact_assist_import_get_type( void )
+{
+ static GType window_type = 0;
+
+ if( !window_type ){
+ window_type = register_type();
+ }
+
+ return( window_type );
+}
+
+static GType
+register_type( void )
+{
+ static const gchar *thisfn = "nact_assist_import_register_type";
+ g_debug( "%s", thisfn );
+
+ static GTypeInfo info = {
+ sizeof( NactAssistImportClass ),
+ ( GBaseInitFunc ) NULL,
+ ( GBaseFinalizeFunc ) NULL,
+ ( GClassInitFunc ) class_init,
+ NULL,
+ NULL,
+ sizeof( NactAssistImport ),
+ 0,
+ ( GInstanceInitFunc ) instance_init
+ };
+
+ GType type = g_type_register_static( NACT_ASSISTANT_TYPE, "NactAssistImport", &info, 0 );
+
+ return( type );
+}
+
+static void
+class_init( NactAssistImportClass *klass )
+{
+ static const gchar *thisfn = "nact_assist_import_class_init";
+ g_debug( "%s: klass=%p", thisfn, klass );
+
+ st_parent_class = g_type_class_peek_parent( klass );
+
+ GObjectClass *object_class = G_OBJECT_CLASS( klass );
+ object_class->dispose = instance_dispose;
+ object_class->finalize = instance_finalize;
+
+ klass->private = g_new0( NactAssistImportClassPrivate, 1 );
+
+ BaseWindowClass *base_class = BASE_WINDOW_CLASS( klass );
+ base_class->get_toplevel_name = do_get_dialog_name;
+ base_class->runtime_init_toplevel = on_runtime_init_dialog;
+
+ NactWindowClass *nact_class = NACT_WINDOW_CLASS( klass );
+ nact_class->get_iprefs_window_id = do_get_iprefs_window_id;
+
+ NactAssistantClass *assist_class = NACT_ASSISTANT_CLASS( klass );
+ assist_class->on_assistant_prepare = on_prepare;
+}
+
+static void
+instance_init( GTypeInstance *instance, gpointer klass )
+{
+ static const gchar *thisfn = "nact_assist_import_instance_init";
+ g_debug( "%s: instance=%p, klass=%p", thisfn, instance, klass );
+
+ g_assert( NACT_IS_ASSIST_IMPORT( instance ));
+ NactAssistImport *self = NACT_ASSIST_IMPORT( instance );
+
+ self->private = g_new0( NactAssistImportPrivate, 1 );
+
+ self->private->dispose_has_run = FALSE;
+ self->private->results = NULL;
+}
+
+static void
+instance_dispose( GObject *window )
+{
+ static const gchar *thisfn = "nact_assist_import_instance_dispose";
+ g_debug( "%s: window=%p", thisfn, window );
+
+ g_assert( NACT_IS_ASSIST_IMPORT( window ));
+ NactAssistImport *self = NACT_ASSIST_IMPORT( window );
+
+ if( !self->private->dispose_has_run ){
+
+ self->private->dispose_has_run = TRUE;
+
+ /* chain up to the parent class */
+ G_OBJECT_CLASS( st_parent_class )->dispose( window );
+ }
+}
+
+static void
+instance_finalize( GObject *window )
+{
+ static const gchar *thisfn = "nact_assist_import_instance_finalize";
+ g_debug( "%s: window=%p", thisfn, window );
+
+ g_assert( NACT_IS_ASSIST_IMPORT( window ));
+ NactAssistImport *self = ( NactAssistImport * ) window;
+
+ free_results( self->private->results );
+
+ g_free( self->private );
+
+ /* chain call to parent class */
+ if( st_parent_class->finalize ){
+ G_OBJECT_CLASS( st_parent_class )->finalize( window );
+ }
+}
+
+static NactAssistImport *
+assist_new( BaseApplication *application )
+{
+ return( g_object_new( NACT_ASSIST_IMPORT_TYPE, PROP_WINDOW_APPLICATION_STR, application, NULL ));
+}
+
+/**
+ * Run the assistant.
+ *
+ * @main: the main window of the application.
+ */
+void
+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 ));
+}
+
+static gchar *
+do_get_iprefs_window_id( NactWindow *window )
+{
+ return( g_strdup( "import-assistant" ));
+}
+
+static gchar *
+do_get_dialog_name( BaseWindow *dialog )
+{
+ return( g_strdup( "ImportAssistant" ));
+}
+
+static void
+on_runtime_init_dialog( BaseWindow *dialog )
+{
+ static const gchar *thisfn = "nact_assist_import_on_runtime_init_dialog";
+
+ /* call parent class at the very beginning */
+ if( BASE_WINDOW_CLASS( st_parent_class )->runtime_init_toplevel ){
+ BASE_WINDOW_CLASS( st_parent_class )->runtime_init_toplevel( dialog );
+ }
+
+ g_debug( "%s: dialog=%p", thisfn, dialog );
+ g_assert( NACT_IS_ASSIST_IMPORT( dialog ));
+ NactAssistImport *window = NACT_ASSIST_IMPORT( dialog );
+
+ GtkAssistant *assistant = GTK_ASSISTANT( base_window_get_toplevel_dialog( dialog ));
+
+ runtime_init_intro( window, assistant );
+ runtime_init_file_selector( window, assistant );
+}
+
+static void
+runtime_init_intro( NactAssistImport *window, GtkAssistant *assistant )
+{
+ static const gchar *thisfn = "nact_assist_import_runtime_init_intro";
+
+ GtkWidget *content = gtk_assistant_get_nth_page( assistant, ASSIST_PAGE_INTRO );
+
+ g_debug( "%s: window=%p, assistant=%p, content=%p", thisfn, window, assistant, content );
+
+ gtk_assistant_set_page_complete( assistant, content, TRUE );
+}
+
+static void
+runtime_init_file_selector( NactAssistImport *window, GtkAssistant *assistant )
+{
+ static const gchar *thisfn = "nact_assist_import_runtime_init_file_selector";
+
+ GtkWidget *chooser = gtk_assistant_get_nth_page( assistant, ASSIST_PAGE_FILES_SELECTION );
+
+ g_debug( "%s: window=%p, assistant=%p, chooser=%p", thisfn, window, assistant, chooser );
+
+ gchar *uri = nact_iprefs_get_import_folder_uri( NACT_WINDOW( window ));
+ if( uri && strlen( uri )){
+ gtk_file_chooser_set_current_folder_uri( GTK_FILE_CHOOSER( chooser ), uri );
+ }
+ g_free( uri );
+
+ nact_window_signal_connect( NACT_WINDOW( window ), G_OBJECT( chooser ), "selection-changed", G_CALLBACK( on_file_selection_changed ));
+
+ gtk_assistant_set_page_complete( assistant, chooser, FALSE );
+}
+
+static void
+on_file_selection_changed( GtkFileChooser *chooser, gpointer user_data )
+{
+ /*static const gchar *thisfn = "nact_assist_import_on_file_selection_changed";
+ g_debug( "%s: chooser=%p, user_data=%p", thisfn, chooser, user_data );*/
+
+ g_assert( NACT_IS_ASSIST_IMPORT( user_data ));
+ GtkAssistant *assistant = GTK_ASSISTANT( base_window_get_toplevel_dialog( BASE_WINDOW( user_data )));
+ gint pos = gtk_assistant_get_current_page( assistant );
+ if( pos == ASSIST_PAGE_FILES_SELECTION ){
+
+ GSList *uris = gtk_file_chooser_get_uris( chooser );
+ gboolean enabled = has_readable_files( uris );
+
+ if( enabled ){
+ gchar *folder = gtk_file_chooser_get_current_folder_uri( GTK_FILE_CHOOSER( chooser ));
+ nact_iprefs_save_import_folder_uri( NACT_WINDOW( user_data ), folder );
+ g_free( folder );
+ }
+
+ na_utils_free_string_list( uris );
+
+ GtkWidget *content = gtk_assistant_get_nth_page( assistant, pos );
+ gtk_assistant_set_page_complete( assistant, content, enabled );
+ gtk_assistant_update_buttons_state( assistant );
+ }
+}
+
+static gboolean
+has_readable_files( GSList *uris )
+{
+ static const gchar *thisfn = "nact_assist_import_has_readable_files";
+
+ GSList *iuri;
+ int readables = 0;
+
+ for( iuri = uris ; iuri ; iuri = iuri->next ){
+
+ gchar *uri = ( gchar * ) iuri->data;
+ if( !strlen( uri )){
+ continue;
+ }
+
+ GFile *file = g_file_new_for_uri( uri );
+ GError *error = NULL;
+ GFileInfo *info = g_file_query_info( file,
+ G_FILE_ATTRIBUTE_ACCESS_CAN_READ "," G_FILE_ATTRIBUTE_STANDARD_TYPE,
+ G_FILE_QUERY_INFO_NONE, NULL, &error );
+
+ if( error ){
+ g_warning( "%s: g_file_query_info error: %s", thisfn, error->message );
+ g_error_free( error );
+ g_object_unref( file );
+ continue;
+ }
+
+ GFileType type = g_file_info_get_file_type( info );
+ if( type != G_FILE_TYPE_REGULAR ){
+ g_warning( "%s: %s is not a file", thisfn, uri );
+ g_object_unref( info );
+ continue;
+ }
+
+ gboolean readable = g_file_info_get_attribute_boolean( info, G_FILE_ATTRIBUTE_ACCESS_CAN_READ );
+ if( !readable ){
+ g_warning( "%s: %s is not readable", thisfn, uri );
+ g_object_unref( info );
+ continue;
+ }
+
+ readables += 1;
+ g_object_unref( info );
+ }
+
+ return( readables > 0 );
+}
+
+static void
+on_prepare( NactAssistant *window, GtkAssistant *assistant, GtkWidget *page )
+{
+ static const gchar *thisfn = "nact_assist_import_on_prepare";
+ g_debug( "%s: window=%p, assistant=%p, page=%p", thisfn, window, assistant, page );
+
+ GtkAssistantPageType type = gtk_assistant_get_page_type( assistant, page );
+
+ switch( type ){
+ case GTK_ASSISTANT_PAGE_CONFIRM:
+ prepare_confirm( NACT_ASSIST_IMPORT( window ), assistant, page );
+ break;
+
+ case GTK_ASSISTANT_PAGE_SUMMARY:
+ prepare_importdone( NACT_ASSIST_IMPORT( window ), assistant, page );
+ break;
+
+ default:
+ break;
+ }
+}
+
+static void
+prepare_confirm( NactAssistImport *window, GtkAssistant *assistant, GtkWidget *page )
+{
+ static const gchar *thisfn = "nact_assist_import_prepare_confirm";
+ g_debug( "%s: window=%p, assistant=%p, page=%p", thisfn, window, assistant, page );
+
+ gchar *text = g_strdup( _( "<b>About to import selected files :</b>\n\n" ));
+ gchar *tmp;
+
+ 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;
+
+ for( is = uris ; is ; is = is->next ){
+ tmp = g_strdup_printf( "%s\t%s\n", text, ( gchar * ) is->data );
+ g_free( text );
+ text = tmp;
+ }
+
+ gtk_label_set_markup( GTK_LABEL( page ), text );
+ g_free( text );
+
+ gtk_assistant_set_page_complete( assistant, page, TRUE );
+}
+
+static void
+prepare_importdone( NactAssistImport *window, GtkAssistant *assistant, GtkWidget *page )
+{
+ static const gchar *thisfn = "nact_assist_import_prepare_importdone";
+ g_debug( "%s: window=%p, assistant=%p, page=%p", thisfn, window, assistant, page );
+
+ do_import( window, assistant );
+
+ gchar *text, *tmp;
+ GSList *is;
+
+ text = g_strdup( _( "<b>Selected files have been imported :</b>\n\n" ));
+
+ for( is = window->private->results ; is ; is = is->next ){
+
+ ImportUriStruct *str = ( ImportUriStruct * ) is->data;
+
+ GFile *file = g_file_new_for_uri( str->uri );
+ gchar *bname = g_file_get_basename( file );
+ g_object_unref( file );
+ tmp = g_strdup_printf( _( "%s\t%s\n\n" ), text, bname );
+ g_free( text );
+ text = tmp;
+ g_free( bname );
+
+ if( str->action ){
+ gchar *uuid = na_action_get_uuid( str->action );
+ gchar *label = na_action_get_label( str->action );
+ tmp = g_strdup_printf( _( "%s\t\tUUID: %s\t%s\n\n" ), text, uuid, label );
+ g_free( label );
+ g_free( uuid );
+ } else {
+ tmp = g_strdup_printf( "%s\t\t NOT OK\n\n", text );
+ }
+ g_free( text );
+ text = tmp;
+
+ GSList *im;
+ for( im = str->msg ; im ; im = im->next ){
+ tmp = g_strdup_printf( "%s\t\t%s\n", text, ( const char * ) im->data );
+ g_free( text );
+ text = tmp;
+ }
+
+ tmp = g_strdup_printf( "%s\n", text );
+ g_free( text );
+ text = tmp;
+ }
+
+ gtk_label_set_markup( GTK_LABEL( page ), text );
+ g_free( text );
+
+ gtk_assistant_set_page_complete( assistant, page, TRUE );
+ nact_assistant_set_warn_on_cancel( NACT_ASSISTANT( window ), FALSE );
+}
+
+static void
+do_import( NactAssistImport *window, GtkAssistant *assistant )
+{
+ static const gchar *thisfn = "nact_assist_import_do_import";
+ g_debug( "%s: window=%p", thisfn, 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 ;
+
+ for( is = uris ; is ; is = is->next ){
+
+ msg = NULL;
+ NAAction *action = nact_gconf_reader_import( G_OBJECT( window ), ( const gchar * ) is->data, &msg );
+ g_debug( "%s: msg has %d lines", thisfn, g_slist_length( msg ));
+
+ ImportUriStruct *str = g_new0( ImportUriStruct, 1 );
+ str->uri = g_strdup(( const gchar * ) is->data );
+ str->action = action;
+ str->msg = na_utils_duplicate_string_list( msg );
+
+ window->private->results = g_slist_prepend( window->private->results, str );
+
+ na_utils_free_string_list( msg );
+ }
+
+ na_utils_free_string_list( uris );
+}
+
+static void
+free_results( GSList *list )
+{
+ GSList *is;
+ for( is = list ; is ; is = is->next ){
+ ImportUriStruct *str = ( ImportUriStruct * ) is->data;
+ g_free( str->uri );
+ na_utils_free_string_list( str->msg );
+ }
+
+ g_slist_free( list );
+}
diff --git a/src/nact/nact-assist-import.h b/src/nact/nact-assist-import.h
new file mode 100644
index 0000000..93bea85
--- /dev/null
+++ b/src/nact/nact-assist-import.h
@@ -0,0 +1,71 @@
+/*
+ * Nautilus Actions
+ * A Nautilus extension which offers configurable context menu actions.
+ *
+ * Copyright (C) 2005 The GNOME Foundation
+ * Copyright (C) 2006, 2007, 2008 Frederic Ruaudel and others (see AUTHORS)
+ * Copyright (C) 2009 Pierre Wieser and others (see AUTHORS)
+ *
+ * This Program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this Library; see the file COPYING. If not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place,
+ * Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Authors:
+ * Frederic Ruaudel <grumz grumz net>
+ * Rodrigo Moya <rodrigo gnome-db org>
+ * Pierre Wieser <pwieser trychlos org>
+ * ... and many others (see AUTHORS)
+ */
+
+#ifndef __NACT_ASSIST_IMPORT_H__
+#define __NACT_ASSIST_IMPORT_H__
+
+/*
+ * NactAssistImport class definition.
+ */
+
+#include "nact-assistant.h"
+
+G_BEGIN_DECLS
+
+#define NACT_ASSIST_IMPORT_TYPE ( nact_assist_import_get_type())
+#define NACT_ASSIST_IMPORT( object ) ( G_TYPE_CHECK_INSTANCE_CAST( object, NACT_ASSIST_IMPORT_TYPE, NactAssistImport ))
+#define NACT_ASSIST_IMPORT_CLASS( klass ) ( G_TYPE_CHECK_CLASS_CAST( klass, NACT_ASSIST_IMPORT_TYPE, NactAssistImportClass ))
+#define NACT_IS_ASSIST_IMPORT( object ) ( G_TYPE_CHECK_INSTANCE_TYPE( object, NACT_ASSIST_IMPORT_TYPE ))
+#define NACT_IS_ASSIST_IMPORT_CLASS( klass ) ( G_TYPE_CHECK_CLASS_TYPE(( klass ), NACT_ASSIST_IMPORT_TYPE ))
+#define NACT_ASSIST_IMPORT_GET_CLASS( object ) ( G_TYPE_INSTANCE_GET_CLASS(( object ), NACT_ASSIST_IMPORT_TYPE, NactAssistImportClass ))
+
+typedef struct NactAssistImportPrivate NactAssistImportPrivate;
+
+typedef struct {
+ NactAssistant parent;
+ NactAssistImportPrivate *private;
+}
+ NactAssistImport;
+
+typedef struct NactAssistImportClassPrivate NactAssistImportClassPrivate;
+
+typedef struct {
+ NactAssistantClass parent;
+ NactAssistImportClassPrivate *private;
+}
+ NactAssistImportClass;
+
+GType nact_assist_import_get_type( void );
+
+void nact_assist_import_run( NactWindow *main );
+
+G_END_DECLS
+
+#endif /* __NACT_ASSIST_IMPORT_H__ */
diff --git a/src/nact/nact-assistant.c b/src/nact/nact-assistant.c
new file mode 100644
index 0000000..1befe39
--- /dev/null
+++ b/src/nact/nact-assistant.c
@@ -0,0 +1,394 @@
+/*
+ * Nautilus Actions
+ * A Nautilus extension which offers configurable context menu actions.
+ *
+ * Copyright (C) 2005 The GNOME Foundation
+ * Copyright (C) 2006, 2007, 2008 Frederic Ruaudel and others (see AUTHORS)
+ * Copyright (C) 2009 Pierre Wieser and others (see AUTHORS)
+ *
+ * This Program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this Library; see the file COPYING. If not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place,
+ * Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Authors:
+ * Frederic Ruaudel <grumz grumz net>
+ * Rodrigo Moya <rodrigo gnome-db org>
+ * Pierre Wieser <pwieser trychlos org>
+ * ... and many others (see AUTHORS)
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <gdk/gdkkeysyms.h>
+#include <glib.h>
+#include <glib/gi18n.h>
+
+#include "nact-assistant.h"
+
+/* private class data
+ */
+struct NactAssistantClassPrivate {
+};
+
+/* private instance data
+ */
+struct NactAssistantPrivate {
+ gboolean dispose_has_run;
+ gboolean warn_on_cancel;
+};
+
+/* instance properties
+ */
+enum {
+ PROP_ASSIST_WARN_ON_CANCEL = 1
+};
+
+#define PROP_ASSIST_WARN_ON_CANCEL_STR "nact-assist-warn-on-cancel"
+
+static GObjectClass *st_parent_class = NULL;
+
+static GType register_type( void );
+static void class_init( NactAssistantClass *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 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 );
+static void v_assistant_prepare( GtkAssistant *assistant, GtkWidget *page, gpointer user_data );
+
+static void on_runtime_init_toplevel( BaseWindow *window );
+static gboolean on_key_pressed_event( GtkWidget *widget, GdkEventKey *event, gpointer user_data );
+static gboolean on_escape_key_pressed( GtkWidget *widget, GdkEventKey *event, gpointer user_data );
+static void do_assistant_apply( NactAssistant *window, GtkAssistant *assistant );
+static void do_assistant_cancel( NactAssistant *window, GtkAssistant *assistant );
+static void do_assistant_close( NactAssistant *window, GtkAssistant *assistant );
+static void do_assistant_prepare( NactAssistant *window, GtkAssistant *assistant, GtkWidget *page );
+
+GType
+nact_assistant_get_type( void )
+{
+ static GType window_type = 0;
+
+ if( !window_type ){
+ window_type = register_type();
+ }
+
+ return( window_type );
+}
+
+static GType
+register_type( void )
+{
+ static const gchar *thisfn = "nact_assistant_register_type";
+ g_debug( "%s", thisfn );
+
+ g_type_init();
+
+ static GTypeInfo info = {
+ sizeof( NactAssistantClass ),
+ ( GBaseInitFunc ) NULL,
+ ( GBaseFinalizeFunc ) NULL,
+ ( GClassInitFunc ) class_init,
+ NULL,
+ NULL,
+ sizeof( NactAssistant ),
+ 0,
+ ( GInstanceInitFunc ) instance_init
+ };
+
+ GType type = g_type_register_static( NACT_WINDOW_TYPE, "NactAssistant", &info, 0 );
+
+ return( type );
+}
+
+static void
+class_init( NactAssistantClass *klass )
+{
+ static const gchar *thisfn = "nact_assistant_class_init";
+ g_debug( "%s: klass=%p", thisfn, klass );
+
+ st_parent_class = g_type_class_peek_parent( klass );
+
+ GObjectClass *object_class = G_OBJECT_CLASS( klass );
+ object_class->dispose = instance_dispose;
+ object_class->finalize = instance_finalize;
+ object_class->get_property = instance_get_property;
+ object_class->set_property = instance_set_property;
+
+ GParamSpec *spec;
+ spec = g_param_spec_boolean(
+ PROP_ASSIST_WARN_ON_CANCEL_STR,
+ PROP_ASSIST_WARN_ON_CANCEL_STR,
+ "Does the user should confirm when exiting the assistant ?", FALSE,
+ G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE );
+ g_object_class_install_property( object_class, PROP_ASSIST_WARN_ON_CANCEL, spec );
+
+ klass->private = g_new0( NactAssistantClassPrivate, 1 );
+
+ BaseWindowClass *base_class = BASE_WINDOW_CLASS( klass );
+ base_class->runtime_init_toplevel = on_runtime_init_toplevel;
+
+ klass->on_escape_key_pressed = on_escape_key_pressed;
+ klass->on_assistant_apply = do_assistant_apply;
+ klass->on_assistant_close = do_assistant_close;
+ klass->on_assistant_cancel = do_assistant_cancel;
+ klass->on_assistant_prepare = do_assistant_prepare;
+}
+
+static void
+instance_init( GTypeInstance *instance, gpointer klass )
+{
+ static const gchar *thisfn = "nact_assistant_instance_init";
+ g_debug( "%s: instance=%p, klass=%p", thisfn, instance, klass );
+
+ g_assert( NACT_IS_ASSISTANT( instance ));
+ NactAssistant *self = NACT_ASSISTANT( instance );
+
+ self->private = g_new0( NactAssistantPrivate, 1 );
+
+ self->private->dispose_has_run = FALSE;
+}
+
+static void
+instance_get_property( GObject *object, guint property_id, GValue *value, GParamSpec *spec )
+{
+ g_assert( NACT_IS_ASSISTANT( object ));
+ NactAssistant *self = NACT_ASSISTANT( object );
+
+ switch( property_id ){
+ case PROP_ASSIST_WARN_ON_CANCEL:
+ g_value_set_boolean( value, self->private->warn_on_cancel );
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID( object, property_id, spec );
+ break;
+ }
+}
+
+static void
+instance_set_property( GObject *object, guint property_id, const GValue *value, GParamSpec *spec )
+{
+ g_assert( NACT_IS_ASSISTANT( object ));
+ NactAssistant *self = NACT_ASSISTANT( object );
+
+ switch( property_id ){
+ case PROP_ASSIST_WARN_ON_CANCEL:
+ self->private->warn_on_cancel = g_value_get_boolean( value );
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID( object, property_id, spec );
+ break;
+ }
+}
+
+static void
+instance_dispose( GObject *window )
+{
+ static const gchar *thisfn = "nact_assistant_instance_dispose";
+ g_debug( "%s: window=%p", thisfn, window );
+
+ g_assert( NACT_IS_ASSISTANT( window ));
+ NactAssistant *self = NACT_ASSISTANT( window );
+
+ if( !self->private->dispose_has_run ){
+
+ self->private->dispose_has_run = TRUE;
+
+ /* chain up to the parent class */
+ G_OBJECT_CLASS( st_parent_class )->dispose( window );
+ }
+}
+
+static void
+instance_finalize( GObject *window )
+{
+ static const gchar *thisfn = "nact_assistant_instance_finalize";
+ g_debug( "%s: window=%p", thisfn, window );
+
+ g_assert( NACT_IS_ASSISTANT( window ));
+ NactAssistant *self = ( NactAssistant * ) window;
+
+ g_free( self->private );
+
+ /* chain call to parent class */
+ if( st_parent_class->finalize ){
+ G_OBJECT_CLASS( st_parent_class )->finalize( window );
+ }
+}
+
+/**
+ * Set 'warn on close' property.
+ */
+
+void
+nact_assistant_set_warn_on_cancel( NactAssistant *window, gboolean warn )
+{
+ g_assert( NACT_IS_ASSISTANT( window ));
+ g_object_set( G_OBJECT( window ), PROP_ASSIST_WARN_ON_CANCEL_STR, warn, NULL );
+}
+
+static void
+v_assistant_apply( GtkAssistant *assistant, gpointer user_data )
+{
+ g_assert( NACT_IS_ASSISTANT( user_data ));
+
+ if( NACT_ASSISTANT_GET_CLASS( user_data )->on_assistant_apply ){
+ NACT_ASSISTANT_GET_CLASS( user_data )->on_assistant_apply( NACT_ASSISTANT( user_data ), assistant );
+ } else {
+ do_assistant_apply( NACT_ASSISTANT( user_data ), assistant );
+ }
+}
+
+static void
+v_assistant_cancel( GtkAssistant *assistant, gpointer user_data )
+{
+ g_assert( NACT_IS_ASSISTANT( user_data ));
+
+ if( NACT_ASSISTANT_GET_CLASS( user_data )->on_assistant_cancel ){
+ NACT_ASSISTANT_GET_CLASS( user_data )->on_assistant_cancel( NACT_ASSISTANT( user_data ), assistant );
+ } else {
+ do_assistant_cancel( NACT_ASSISTANT( user_data ), assistant );
+ }
+}
+
+static void
+v_assistant_close( GtkAssistant *assistant, gpointer user_data )
+{
+ g_assert( NACT_IS_ASSISTANT( user_data ));
+
+ if( NACT_ASSISTANT_GET_CLASS( user_data )->on_assistant_close ){
+ NACT_ASSISTANT_GET_CLASS( user_data )->on_assistant_close( NACT_ASSISTANT( user_data ), assistant );
+ } else {
+ do_assistant_close( NACT_ASSISTANT( user_data ), assistant );
+ }
+}
+
+static void
+v_assistant_prepare( GtkAssistant *assistant, GtkWidget *page, gpointer user_data )
+{
+ g_assert( NACT_IS_ASSISTANT( user_data ));
+
+ if( NACT_ASSISTANT_GET_CLASS( user_data )->on_assistant_prepare ){
+ NACT_ASSISTANT_GET_CLASS( user_data )->on_assistant_prepare( NACT_ASSISTANT( user_data ), assistant, page );
+ } else {
+ do_assistant_prepare( NACT_ASSISTANT( user_data ), assistant, page );
+ }
+}
+
+static void
+on_runtime_init_toplevel( BaseWindow *window )
+{
+ static const gchar *thisfn = "nact_assistant_on_runtime_init_toplevel";
+
+ /* call parent class at the very beginning */
+ if( BASE_WINDOW_CLASS( st_parent_class )->runtime_init_toplevel ){
+ BASE_WINDOW_CLASS( st_parent_class )->runtime_init_toplevel( window );
+ }
+
+ g_debug( "%s: window=%p", thisfn, window );
+ g_assert( NACT_IS_ASSISTANT( window ));
+
+ GtkWindow *toplevel = base_window_get_toplevel_dialog( window );
+ g_assert( GTK_IS_ASSISTANT( toplevel ));
+
+ nact_window_signal_connect( NACT_WINDOW( window ), G_OBJECT( toplevel ), "key-press-event", G_CALLBACK( on_key_pressed_event ));
+ nact_window_signal_connect( NACT_WINDOW( window ), G_OBJECT( toplevel ), "cancel", G_CALLBACK( v_assistant_cancel ));
+ nact_window_signal_connect( NACT_WINDOW( window ), G_OBJECT( toplevel ), "close", G_CALLBACK( v_assistant_close ));
+ nact_window_signal_connect( NACT_WINDOW( window ), G_OBJECT( toplevel ), "prepare", G_CALLBACK( v_assistant_prepare ));
+ nact_window_signal_connect( NACT_WINDOW( window ), G_OBJECT( toplevel ), "apply", G_CALLBACK( v_assistant_apply ));
+
+ nact_assistant_set_warn_on_cancel( NACT_ASSISTANT( window ), TRUE );
+}
+
+static gboolean
+on_key_pressed_event( GtkWidget *widget, GdkEventKey *event, gpointer user_data )
+{
+ /*static const gchar *thisfn = "nact_assistant_on_key_pressed_event";
+ g_debug( "%s: widget=%p, event=%p, user_data=%p", thisfn, widget, event, user_data );*/
+
+ gboolean stop = FALSE;
+
+ if( event->keyval == GDK_Escape ){
+ if( NACT_ASSISTANT_GET_CLASS( user_data )->on_escape_key_pressed ){
+ stop = NACT_ASSISTANT_GET_CLASS( user_data )->on_escape_key_pressed( widget, event, user_data );
+ }
+ }
+
+ return( stop );
+}
+
+static gboolean
+on_escape_key_pressed( GtkWidget *widget, GdkEventKey *event, gpointer user_data )
+{
+ static const gchar *thisfn = "nact_assistant_on_escape_key_pressed";
+ g_debug( "%s: widget=%p, event=%p, user_data=%p", thisfn, widget, event, user_data );
+
+ GtkWindow *toplevel = base_window_get_toplevel_dialog( BASE_WINDOW( user_data ));
+ v_assistant_cancel( GTK_ASSISTANT( toplevel ), user_data );
+
+ return( TRUE );
+}
+
+static void
+do_assistant_apply( NactAssistant *window, GtkAssistant *assistant )
+{
+ static const gchar *thisfn = "nact_assistant_do_assistant_apply";
+ g_debug( "%s: window=%p, assistant=%p", thisfn, window, assistant );
+}
+
+/*
+ * the 'Cancel' button is clicked
+ */
+static void
+do_assistant_cancel( NactAssistant *window, GtkAssistant *assistant )
+{
+ static const gchar *thisfn = "nact_assistant_do_assistant_cancel";
+ g_debug( "%s: window=%p, assistant=%p", thisfn, window, assistant );
+
+ gboolean ok = TRUE;
+
+ if( window->private->warn_on_cancel ){
+ gchar *first = g_strdup( _( "Are you sure you want to quit this assistant ?" ));
+ ok = base_window_yesno_dlg( BASE_WINDOW( window ), GTK_MESSAGE_QUESTION, first, NULL );
+ g_free( first );
+ }
+
+ if( ok ){
+ do_assistant_close( window, assistant );
+ }
+}
+
+static void
+do_assistant_close( NactAssistant *window, GtkAssistant *assistant )
+{
+ static const gchar *thisfn = "nact_assistant_do_assistant_close";
+ g_debug( "%s: window=%p, assistant=%p", thisfn, window, assistant );
+
+ g_object_unref( window );
+}
+
+static void
+do_assistant_prepare( NactAssistant *window, GtkAssistant *assistant, GtkWidget *page )
+{
+ static const gchar *thisfn = "nact_assistant_do_assistant_prepare";
+ g_debug( "%s: window=%p, assistant=%p, page=%p", thisfn, window, assistant, page );
+}
diff --git a/src/nact/nact-assistant.h b/src/nact/nact-assistant.h
new file mode 100644
index 0000000..ccdc312
--- /dev/null
+++ b/src/nact/nact-assistant.h
@@ -0,0 +1,81 @@
+/*
+ * Nautilus Actions
+ * A Nautilus extension which offers configurable context menu actions.
+ *
+ * Copyright (C) 2005 The GNOME Foundation
+ * Copyright (C) 2006, 2007, 2008 Frederic Ruaudel and others (see AUTHORS)
+ * Copyright (C) 2009 Pierre Wieser and others (see AUTHORS)
+ *
+ * This Program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this Library; see the file COPYING. If not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place,
+ * Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Authors:
+ * Frederic Ruaudel <grumz grumz net>
+ * Rodrigo Moya <rodrigo gnome-db org>
+ * Pierre Wieser <pwieser trychlos org>
+ * ... and many others (see AUTHORS)
+ */
+
+#ifndef __NACT_ASSISTANT_H__
+#define __NACT_ASSISTANT_H__
+
+/*
+ * NactAssistant class definition.
+ *
+ * This class is derived from NactWindow class, and serves as a base
+ * class for all Nautilus Actions assistants.
+ */
+
+#include "nact-window.h"
+
+G_BEGIN_DECLS
+
+#define NACT_ASSISTANT_TYPE ( nact_assistant_get_type())
+#define NACT_ASSISTANT( object ) ( G_TYPE_CHECK_INSTANCE_CAST( object, NACT_ASSISTANT_TYPE, NactAssistant ))
+#define NACT_ASSISTANT_CLASS( klass ) ( G_TYPE_CHECK_CLASS_CAST( klass, NACT_ASSISTANT_TYPE, NactAssistantClass ))
+#define NACT_IS_ASSISTANT( object ) ( G_TYPE_CHECK_INSTANCE_TYPE( object, NACT_ASSISTANT_TYPE ))
+#define NACT_IS_ASSISTANT_CLASS( klass ) ( G_TYPE_CHECK_CLASS_TYPE(( klass ), NACT_ASSISTANT_TYPE ))
+#define NACT_ASSISTANT_GET_CLASS( object ) ( G_TYPE_INSTANCE_GET_CLASS(( object ), NACT_ASSISTANT_TYPE, NactAssistantClass ))
+
+typedef struct NactAssistantPrivate NactAssistantPrivate;
+
+typedef struct {
+ NactWindow parent;
+ NactAssistantPrivate *private;
+}
+ NactAssistant;
+
+typedef struct NactAssistantClassPrivate NactAssistantClassPrivate;
+
+typedef struct {
+ NactWindowClass parent;
+ NactAssistantClassPrivate *private;
+
+ /* api */
+ gboolean ( *on_escape_key_pressed )( GtkWidget *widget, GdkEventKey *event, gpointer data );
+ void ( *on_assistant_apply ) ( NactAssistant *window, GtkAssistant *assistant );
+ void ( *on_assistant_cancel ) ( NactAssistant *window, GtkAssistant *assistant );
+ void ( *on_assistant_close ) ( NactAssistant *window, GtkAssistant *assistant );
+ void ( *on_assistant_prepare ) ( NactAssistant *window, GtkAssistant *assistant, GtkWidget *page );
+}
+ NactAssistantClass;
+
+GType nact_assistant_get_type( void );
+
+void nact_assistant_set_warn_on_cancel( NactAssistant *window, gboolean warn );
+
+G_END_DECLS
+
+#endif /* __NACT_ASSISTANT_H__ */
diff --git a/src/nact/nact-gconf-schema.h b/src/nact/nact-gconf-keys.h
similarity index 54%
rename from src/nact/nact-gconf-schema.h
rename to src/nact/nact-gconf-keys.h
index 3cac6db..af74b86 100644
--- a/src/nact/nact-gconf-schema.h
+++ b/src/nact/nact-gconf-keys.h
@@ -28,64 +28,41 @@
* ... and many others (see AUTHORS)
*/
-#ifndef __NACT_GCONF_SCHEMA_H__
-#define __NACT_GCONF_SCHEMA_H__
-
-/*
- * NactGConfSchema class definition.
- *
- * This is the base class for importing into and exporting from GConf
- * storage subsystem.
- */
+#ifndef __NACT_GCONF_KEYS_H__
+#define __NACT_GCONF_KEYS_H__
#include <glib-object.h>
-#include <common/na-action.h>
-#include <common/na-action-profile.h>
-#include <common/na-gconf-keys.h>
-#include <common/na-utils.h>
-
G_BEGIN_DECLS
-#define NACT_GCONF_SCHEMA_TYPE ( nact_gconf_schema_get_type())
-#define NACT_GCONF_SCHEMA( object ) ( G_TYPE_CHECK_INSTANCE_CAST( object, NACT_GCONF_SCHEMA_TYPE, NactGConfSchema ))
-#define NACT_GCONF_SCHEMA_CLASS( klass ) ( G_TYPE_CHECK_CLASS_CAST( klass, NACT_GCONF_SCHEMA_TYPE, NactGConfSchemaClass ))
-#define NACT_IS_GCONF_SCHEMA( object ) ( G_TYPE_CHECK_INSTANCE_TYPE( object, NACT_GCONF_SCHEMA_TYPE ))
-#define NACT_IS_GCONF_SCHEMA_CLASS( klass ) ( G_TYPE_CHECK_CLASS_TYPE(( klass ), NACT_GCONF_SCHEMA_TYPE ))
-#define NACT_GCONF_SCHEMA_GET_CLASS( object ) ( G_TYPE_INSTANCE_GET_CLASS(( object ), NACT_GCONF_SCHEMA_TYPE, NactGConfSchemaClass ))
-
-typedef struct NactGConfSchemaPrivate NactGConfSchemaPrivate;
-
-typedef struct {
- GObject parent;
- NactGConfSchemaPrivate *private;
-}
- NactGConfSchema;
-
-typedef struct NactGConfSchemaClassPrivate NactGConfSchemaClassPrivate;
-
-typedef struct {
- GObjectClass parent;
- NactGConfSchemaClassPrivate *private;
-}
- NactGConfSchemaClass;
-
-/* GConf XML element names
+/* XML element names (GConf style)
*/
#define NACT_GCONF_XML_ROOT "gconfschemafile"
#define NACT_GCONF_XML_SCHEMA_LIST "schemalist"
#define NACT_GCONF_XML_SCHEMA_ENTRY "schema"
-#define NACT_GCONF_XML_SCHEMA_KEY "key"
#define NACT_GCONF_XML_SCHEMA_APPLYTO "applyto"
-#define NACT_GCONF_XML_SCHEMA_TYPE "type"
#define NACT_GCONF_XML_SCHEMA_LOCALE "locale"
#define NACT_GCONF_XML_SCHEMA_DFT "default"
+
+/* Previous used keys
+ *
+ * Up to v 1.10, export used to contain a full schema description,
+ * while import only checked for applyto keys (along with locale
+ * and default)
+ *
+ * Starting with 1.11, export only contains required keys (applyto,
+ * default and locale) ; import of course accept all previous keys
+ * without warning
+ */
+#define NACT_GCONF_XML_SCHEMA_KEY "key"
+#define NACT_GCONF_XML_SCHEMA_OWNER "owner"
+#define NACT_GCONF_XML_SCHEMA_TYPE "type"
#define NACT_GCONF_XML_SCHEMA_LIST_TYPE "list_type"
+#define NACT_GCONF_XML_SCHEMA_SHORT "short"
+#define NACT_GCONF_XML_SCHEMA_LONG "long"
#define NACT_GCONF_SCHEMA_PREFIX "/schemas"
-GType nact_gconf_schema_get_type( void );
-
G_END_DECLS
-#endif /* __NACT_GCONF_SCHEMA_H__ */
+#endif /* __NACT_GCONF_KEYS_H__ */
diff --git a/src/nact/nact-gconf-reader.c b/src/nact/nact-gconf-reader.c
new file mode 100644
index 0000000..4219053
--- /dev/null
+++ b/src/nact/nact-gconf-reader.c
@@ -0,0 +1,872 @@
+/*
+ * Nautilus Actions
+ * A Nautilus extension which offers configurable context menu actions.
+ *
+ * Copyright (C) 2005 The GNOME Foundation
+ * Copyright (C) 2006, 2007, 2008 Frederic Ruaudel and others (see AUTHORS)
+ * Copyright (C) 2009 Pierre Wieser and others (see AUTHORS)
+ *
+ * This Program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this Library; see the file COPYING. If not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place,
+ * Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Authors:
+ * Frederic Ruaudel <grumz grumz net>
+ * Rodrigo Moya <rodrigo gnome-db org>
+ * Pierre Wieser <pwieser trychlos org>
+ * ... and many others (see AUTHORS)
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <glib/gi18n.h>
+#include <libxml/tree.h>
+#include <stdarg.h>
+#include <string.h>
+#include <uuid/uuid.h>
+
+#include <common/na-gconf-keys.h>
+#include <common/na-pivot.h>
+#include <common/na-utils.h>
+
+#include "nact-gconf-keys.h"
+#include "nact-gconf-reader.h"
+#include "nact-assistant.h"
+
+/* private class data
+ */
+struct NactGConfReaderClassPrivate {
+};
+
+/* private instance data
+ * we allocate one instance for each imported file, and each imported
+ * file should contain one and only one action
+ * follow here the import flow
+ */
+struct NactGConfReaderPrivate {
+ gboolean dispose_has_run;
+ NAPivot *pivot;
+ NAAction *action; /* the action that we will return, or NULL */
+ GSList *messages;
+ gboolean uuid_set; /* set at first uuid, then checked against */
+
+ /* followinf values are reset at each schema node
+ */
+ NAActionProfile *profile; /* profile */
+ gboolean locale_waited; /* does this require a locale ? */
+ gboolean profile_waited; /* does this entry apply to a profile ? */
+ gchar *entry;
+ gchar *value; /* found value */
+};
+
+typedef struct {
+ char *entry;
+ gboolean entry_found;
+ gboolean locale_waited;
+ gboolean profile_waited;
+}
+ GConfReaderStruct;
+
+static GConfReaderStruct reader_str[] = {
+ { ACTION_VERSION_ENTRY , FALSE, FALSE, FALSE },
+ { ACTION_LABEL_ENTRY , FALSE, TRUE, FALSE },
+ { ACTION_TOOLTIP_ENTRY , FALSE, TRUE, FALSE },
+ { ACTION_ICON_ENTRY , FALSE, FALSE, FALSE },
+ { ACTION_PROFILE_LABEL_ENTRY, FALSE, TRUE, TRUE },
+ { ACTION_PATH_ENTRY , FALSE, FALSE, TRUE },
+ { ACTION_PARAMETERS_ENTRY , FALSE, FALSE, TRUE },
+ { ACTION_BASENAMES_ENTRY , FALSE, FALSE, TRUE },
+ { ACTION_MATCHCASE_ENTRY , FALSE, FALSE, TRUE },
+ { ACTION_ISFILE_ENTRY , FALSE, FALSE, TRUE },
+ { ACTION_ISDIR_ENTRY , FALSE, FALSE, TRUE },
+ { ACTION_MULTIPLE_ENTRY , FALSE, FALSE, TRUE },
+ { ACTION_MIMETYPES_ENTRY , FALSE, FALSE, TRUE },
+ { ACTION_SCHEMES_ENTRY , FALSE, FALSE, TRUE },
+ { NULL, FALSE, FALSE, TRUE },
+};
+
+#define ERR_UNABLE_PARSE_XML_FILE _( "Unable to parse XML file: %s." )
+#define ERR_ROOT_ELEMENT _( "Invalid XML root element: waited for '%s', found '%s' at line %d." )
+#define ERR_WAITED_IGNORED_NODE _( "Waited for '%s' node, found (ignored) '%s' at line %d." )
+#define ERR_IGNORED_NODE _( "Unexpected (ignored) '%s' node found at line %d." )
+#define ERR_IGNORED_SCHEMA _( "Schema is ignored at line %d." )
+#define ERR_UNEXPECTED_NODE _( "Unexpected '%s' node found at line %d." )
+#define ERR_UNEXPECTED_ENTRY _( "Unexpected '%s' entry found at line %d." )
+#define ERR_NODE_NOT_FOUND _( "Mandatory node '%s' not found." )
+#define ERR_NO_VALUE_FOUND _( "No value found." )
+#define ERR_INVALID_UUID _( "Invalid UUID: waited for %s, found %s at line %d." )
+#define ERR_INVALID_KEY_PREFIX _( "Invalid content: waited for %s prefix, found %s at line %d." )
+#define ERR_NOT_AN_UUID _( "Invalid UUID %s found at line %d." )
+#define ERR_UUID_ALREADY_EXISTS _( "Already existing UUID %s at line %d." )
+#define ERR_VALUE_ALREADY_SET _( "Value '%s' already set: new value ignored at line %d." )
+
+static GObjectClass *st_parent_class = NULL;
+
+static GType register_type( void );
+static void class_init( NactGConfReaderClass *klass );
+static void instance_init( GTypeInstance *instance, gpointer klass );
+static void instance_dispose( GObject *object );
+static void instance_finalize( GObject *object );
+
+static NactGConfReader *gconf_reader_new( void );
+static void gconf_reader_parse_schemalist( NactGConfReader *reader, xmlNode *schemalist );
+static gboolean gconf_reader_parse_schema( NactGConfReader *reader, xmlNode *schema );
+static gboolean gconf_reader_parse_applyto( NactGConfReader *reader, xmlNode *node );
+static gboolean gconf_reader_check_for_entry( NactGConfReader *reader, xmlNode *node, const char *entry );
+static gboolean gconf_reader_parse_locale( NactGConfReader *reader, xmlNode *node );
+static void gconf_reader_parse_default( NactGConfReader *reader, xmlNode *node );
+static void apply_schema_value( NactGConfReader *reader );
+static void add_message( NactGConfReader *reader, const gchar *format, ... );
+static int strxcmp( const xmlChar *a, const char *b );
+static gchar *get_uuid_from_key( NactGConfReader *reader, const gchar *key, guint line );
+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 );
+
+GType
+nact_gconf_reader_get_type( void )
+{
+ static GType object_type = 0;
+
+ if( !object_type ){
+ object_type = register_type();
+ }
+
+ return( object_type );
+}
+
+static GType
+register_type( void )
+{
+ static GTypeInfo info = {
+ sizeof( NactGConfReaderClass ),
+ NULL,
+ NULL,
+ ( GClassInitFunc ) class_init,
+ NULL,
+ NULL,
+ sizeof( NactGConfReader ),
+ 0,
+ ( GInstanceInitFunc ) instance_init
+ };
+
+ GType type = g_type_register_static( G_TYPE_OBJECT, "NactGConfReader", &info, 0 );
+
+ return( type );
+}
+
+static void
+class_init( NactGConfReaderClass *klass )
+{
+ static const gchar *thisfn = "nact_gconf_reader_class_init";
+ g_debug( "%s: klass=%p", thisfn, klass );
+
+ st_parent_class = g_type_class_peek_parent( klass );
+
+ GObjectClass *object_class = G_OBJECT_CLASS( klass );
+ object_class->dispose = instance_dispose;
+ object_class->finalize = instance_finalize;
+
+ klass->private = g_new0( NactGConfReaderClassPrivate, 1 );
+}
+
+static void
+instance_init( GTypeInstance *instance, gpointer klass )
+{
+ static const gchar *thisfn = "nact_gconf_reader_instance_init";
+ g_debug( "%s: instance=%p, klass=%p", thisfn, instance, klass );
+
+ g_assert( NACT_IS_GCONF_READER( instance ));
+ NactGConfReader *self = NACT_GCONF_READER( instance );
+
+ self->private = g_new0( NactGConfReaderPrivate, 1 );
+
+ self->private->dispose_has_run = FALSE;
+ self->private->action = NULL;
+ self->private->messages = NULL;
+ self->private->uuid_set = FALSE;
+ self->private->profile = NULL;
+ self->private->locale_waited = FALSE;
+ self->private->entry = NULL;
+ self->private->value = NULL;
+}
+
+static void
+instance_dispose( GObject *object )
+{
+ g_assert( NACT_IS_GCONF_READER( object ));
+ NactGConfReader *self = NACT_GCONF_READER( object );
+
+ if( !self->private->dispose_has_run ){
+
+ self->private->dispose_has_run = TRUE;
+
+ if( self->private->action ){
+ g_assert( NA_IS_ACTION( self->private->action ));
+ g_object_unref( self->private->action );
+ }
+
+ /* chain up to the parent class */
+ G_OBJECT_CLASS( st_parent_class )->dispose( object );
+ }
+}
+
+static void
+instance_finalize( GObject *object )
+{
+ g_assert( NACT_IS_GCONF_READER( object ));
+ NactGConfReader *self = NACT_GCONF_READER( object );
+
+ na_utils_free_string_list( self->private->messages );
+ free_schema_value( self );
+
+ g_free( self->private );
+
+ /* chain call to parent class */
+ if( st_parent_class->finalize ){
+ G_OBJECT_CLASS( st_parent_class )->finalize( object );
+ }
+}
+
+static NactGConfReader *
+gconf_reader_new( void )
+{
+ return( g_object_new( NACT_GCONF_READER_TYPE, NULL ));
+}
+
+/**
+ * Import the specified file as an NAAction XML description.
+ */
+NAAction *
+nact_gconf_reader_import( GObject *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 );
+
+ NAAction *action = NULL;
+ gboolean found = FALSE;
+
+ NactGConfReader *reader = gconf_reader_new();
+
+ g_assert( NACT_IS_ASSISTANT( window ));
+ reader->private->pivot = NA_PIVOT( nact_window_get_pivot( NACT_WINDOW( window )));
+
+ xmlDoc *doc = xmlParseFile( uri );
+ xmlNode *iter;
+
+ if( !doc ){
+ xmlErrorPtr error = xmlGetLastError();
+ add_message( reader,
+ ERR_UNABLE_PARSE_XML_FILE, error->message );
+ xmlResetError( error );
+
+ } else {
+ xmlNode *root_node = xmlDocGetRootElement( doc );
+
+ if( strxcmp( root_node->name, NACT_GCONF_XML_ROOT )){
+ add_message( reader,
+ ERR_ROOT_ELEMENT,
+ NACT_GCONF_XML_ROOT, ( const char * ) root_node->name, root_node->line );
+
+ } else {
+ for( iter = root_node->children ; iter ; iter = iter->next ){
+
+ if( iter->type != XML_ELEMENT_NODE ){
+ continue;
+ }
+
+ if( strxcmp( iter->name, NACT_GCONF_XML_SCHEMA_LIST )){
+ add_message( reader,
+ ERR_WAITED_IGNORED_NODE,
+ NACT_GCONF_XML_SCHEMA_LIST, ( const char * ) iter->name, iter->line );
+ continue;
+ }
+
+ if( found ){
+ add_message( reader, ERR_IGNORED_NODE, ( const char * ) iter->name, iter->line );
+ continue;
+ }
+
+ found = TRUE;
+ gconf_reader_parse_schemalist( reader, iter );
+ }
+ }
+
+ xmlFreeDoc (doc);
+ }
+
+ xmlCleanupParser();
+
+ g_debug( "%s: messages has %d lines", thisfn, g_slist_length( reader->private->messages ));
+ *msg = na_utils_duplicate_string_list( reader->private->messages );
+ g_debug( "%s: after", thisfn );
+
+ if( reader->private->action ){
+ g_assert( NA_IS_ACTION( reader->private->action ));
+ action = g_object_ref( reader->private->action );
+ }
+ g_object_unref( reader );
+
+ return( action );
+}
+
+/*
+ * iter points to the 'schemalist' node (already checked)
+ * children should only be 'schema' nodes ; other nodes are warned,
+ * but not fatal
+ */
+static void
+gconf_reader_parse_schemalist( NactGConfReader *reader, xmlNode *schema )
+{
+ static const gchar *thisfn = "gconf_reader_parse_schemalist";
+ g_debug( "%s: reader=%p, schema=%p", thisfn, reader, schema );
+
+ xmlNode *iter;
+
+ reader->private->action = na_action_new( NULL );
+ reader->private->uuid_set = FALSE;
+
+ for( iter = schema->children ; iter ; iter = iter->next ){
+
+ if( iter->type != XML_ELEMENT_NODE ){
+ continue;
+ }
+
+ if( strxcmp( iter->name, NACT_GCONF_XML_SCHEMA_ENTRY )){
+ add_message( reader,
+ ERR_WAITED_IGNORED_NODE,
+ NACT_GCONF_XML_SCHEMA_ENTRY, ( const char * ) iter->name, iter->line );
+ continue;
+ }
+
+ if( !gconf_reader_parse_schema( reader, iter )){
+ add_message( reader, ERR_IGNORED_SCHEMA, iter->line );
+ }
+ }
+
+ gboolean ok = FALSE;
+
+ if( reader->private->uuid_set ){
+ gchar *label = na_action_get_label( reader->private->action );
+ ok = ( label && strlen( label ));
+ g_debug( "%s: action=%p, label=%s, ok=%s", thisfn, reader->private->action, label, ok ? "True":"False" );
+ g_free( label );
+ }
+
+ if( !ok ){
+ g_object_unref( reader->private->action );
+ reader->private->action = NULL;
+ }
+}
+
+/*
+ * iter points to a 'schema' node (already checked)
+ *
+ * we can have
+ * - schema
+ * +- locale
+ * +- default
+ * or
+ * - schema
+ * +- default
+ * depending of the key's entry.
+ *
+ * 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
+ * for it outside
+ *
+ * Returns TRUE if the node has been successfully parsed, FALSE else.
+ */
+static gboolean
+gconf_reader_parse_schema( NactGConfReader *reader, xmlNode *schema )
+{
+ static const gchar *thisfn = "gconf_reader_parse_schema";
+ g_debug( "%s: reader=%p, schema=%p", thisfn, reader, schema );
+
+ xmlNode *iter;
+ gboolean ret = TRUE;
+ gboolean applyto = FALSE;
+ gboolean pre_v1_11 = FALSE;
+
+ free_schema_value( reader );
+
+ /* check for the children of the 'schema' node
+ * we must only found known keys
+ */
+ for( iter = schema->children ; iter ; iter = iter->next ){
+
+ if( iter->type != XML_ELEMENT_NODE ){
+ continue;
+ }
+
+ if( strxcmp( iter->name, NACT_GCONF_XML_SCHEMA_KEY ) &&
+ strxcmp( iter->name, NACT_GCONF_XML_SCHEMA_APPLYTO ) &&
+ strxcmp( iter->name, NACT_GCONF_XML_SCHEMA_OWNER ) &&
+ strxcmp( iter->name, NACT_GCONF_XML_SCHEMA_TYPE ) &&
+ strxcmp( iter->name, NACT_GCONF_XML_SCHEMA_LIST_TYPE ) &&
+ strxcmp( iter->name, NACT_GCONF_XML_SCHEMA_LOCALE ) &&
+ strxcmp( iter->name, NACT_GCONF_XML_SCHEMA_DFT )){
+
+ add_message( reader, ERR_UNEXPECTED_NODE, ( const char * ) iter->name, iter->line );
+ ret = FALSE;
+ continue;
+ }
+
+ if( !strxcmp( iter->name, NACT_GCONF_XML_SCHEMA_KEY ) ||
+ !strxcmp( iter->name, NACT_GCONF_XML_SCHEMA_OWNER ) ||
+ !strxcmp( iter->name, NACT_GCONF_XML_SCHEMA_TYPE ) ||
+ !strxcmp( iter->name, NACT_GCONF_XML_SCHEMA_LIST_TYPE )){
+
+ pre_v1_11 = TRUE;
+ continue;
+ }
+ }
+
+ if( !ret ){
+ return( ret );
+ }
+
+ g_debug( "%s: pre_v1_11=%s", thisfn, pre_v1_11 ? "True":"False" );
+
+ /* check for an 'applyto' node
+ * is mandatory
+ * will determine if we are waiting for locale+default or only default
+ */
+ reader->private->locale_waited = FALSE;
+
+ for( iter = schema->children ; iter ; iter = iter->next ){
+
+ if( iter->type != XML_ELEMENT_NODE ){
+ continue;
+ }
+
+ if( !strxcmp( iter->name, NACT_GCONF_XML_SCHEMA_APPLYTO )){
+
+ if( applyto ){
+ add_message( reader, ERR_UNEXPECTED_NODE, ( const char * ) iter->name, iter->line );
+ ret = FALSE;
+ }
+
+ applyto = TRUE;
+ ret = gconf_reader_parse_applyto( reader, iter );
+ }
+ }
+
+ if( !applyto ){
+ g_assert( ret );
+ add_message( reader, ERR_NODE_NOT_FOUND, NACT_GCONF_XML_SCHEMA_APPLYTO );
+ ret = FALSE;
+ }
+
+ if( !ret ){
+ return( ret );
+ }
+
+ /* check for and parse locale+default or locale depending of the
+ * previously found 'applyto' node
+ */
+ gboolean locale_found = FALSE;
+ gboolean default_found = FALSE;
+
+ for( iter = schema->children ; iter ; iter = iter->next ){
+
+ if( iter->type != XML_ELEMENT_NODE ){
+ continue;
+ }
+
+ if( !strxcmp( iter->name, NACT_GCONF_XML_SCHEMA_LOCALE )){
+
+ if( locale_found ){
+ add_message( reader, ERR_UNEXPECTED_NODE, ( const char * ) iter->name, iter->line );
+ ret = FALSE;
+
+ } else {
+ locale_found = TRUE;
+ if( reader->private->locale_waited ){
+ ret = gconf_reader_parse_locale( reader, iter );
+ }
+ }
+
+ } else if( !strxcmp( iter->name, NACT_GCONF_XML_SCHEMA_DFT )){
+
+ if( default_found ){
+ add_message( reader, ERR_UNEXPECTED_NODE, ( const char * ) iter->name, iter->line );
+ ret = FALSE;
+
+ } else {
+ default_found = TRUE;
+ if( !reader->private->locale_waited ||
+ ( pre_v1_11 && !strcmp( reader->private->entry, ACTION_PROFILE_LABEL_ENTRY ))){
+ gconf_reader_parse_default( reader, iter );
+ }
+ }
+ }
+ }
+
+ if( !reader->private->value ){
+ g_assert( ret );
+ add_message( reader, ERR_NO_VALUE_FOUND );
+ ret = FALSE;
+ }
+
+ if( ret ){
+ apply_schema_value( reader );
+ }
+
+ return( ret );
+}
+
+static gboolean
+gconf_reader_parse_applyto( NactGConfReader *reader, xmlNode *node )
+{
+ static const gchar *thisfn = "gconf_reader_parse_applyto";
+ g_debug( "%s: reader=%p, node=%p", thisfn, reader, node );
+
+ gboolean ret = TRUE;
+
+ xmlChar *text = xmlNodeGetContent( node );
+ gchar *uuid = get_uuid_from_key( reader, ( const gchar * ) text, node->line );
+ gchar *profile = NULL;
+ gchar *entry = NULL;
+
+ if( !uuid ){
+ ret = FALSE;
+ }
+
+ if( ret ){
+ if( !reader->private->uuid_set ){
+
+ GObject *object = na_pivot_get_action( reader->private->pivot, uuid );
+ if( object ){
+ add_message( reader, ERR_UUID_ALREADY_EXISTS, uuid );
+ ret = FALSE;
+
+ } else {
+ na_action_set_uuid( reader->private->action, uuid );
+ reader->private->uuid_set = TRUE;
+ }
+
+ } else {
+ gchar *ref = na_action_get_uuid( reader->private->action );
+ if( strcmp(( const char * ) uuid, ( const char * ) ref )){
+ add_message( reader, ERR_INVALID_UUID, ref, uuid, node->line );
+ ret = FALSE;
+ }
+ g_free( ref );
+ }
+ }
+
+ if( ret ){
+ profile = get_profile_name_from_key(( const gchar * ) text, uuid );
+
+ if( profile ){
+ reader->private->profile = NA_ACTION_PROFILE( na_action_get_profile( reader->private->action, profile ));
+
+ if( !reader->private->profile ){
+ reader->private->profile = na_action_profile_new( NA_OBJECT( reader->private->action ), profile );
+ na_action_add_profile( reader->private->action, NA_OBJECT( reader->private->profile ));
+ }
+ }
+
+ entry = get_entry_from_key(( const gchar * ) text );
+ g_assert( entry && strlen( entry ));
+
+ ret = gconf_reader_check_for_entry( reader, node, entry );
+ }
+
+ g_free( entry );
+ g_free( profile );
+ g_free( uuid );
+ xmlFree( text );
+
+ return( ret );
+}
+
+static gboolean
+gconf_reader_check_for_entry( NactGConfReader *reader, xmlNode *node, const char *entry )
+{
+ static const gchar *thisfn = "gconf_reader_check_for_entry";
+ g_debug( "%s: reader=%p, node=%p, entry=%s", thisfn, reader, node, entry );
+
+ gboolean ret = TRUE;
+ gboolean found = FALSE;
+ int i;
+
+ for( i=0 ; reader_str[i].entry ; ++i ){
+ if( !strcmp( reader_str[i].entry, entry )){
+ found = TRUE;
+
+ if( reader_str[i].entry_found ){
+ add_message( reader, ERR_UNEXPECTED_ENTRY, entry, node->line );
+ ret = FALSE;
+
+ } else {
+ reader_str[i].entry_found = TRUE;
+ reader->private->entry = g_strdup( reader_str[i].entry );
+ reader->private->locale_waited = reader_str[i].locale_waited;
+ reader->private->profile_waited = reader_str[i].profile_waited;
+ }
+ }
+ }
+
+ if( !found ){
+ g_assert( ret );
+ add_message( reader, ERR_UNEXPECTED_ENTRY, entry, node->line );
+ ret = FALSE;
+ }
+
+ return( ret );
+}
+
+/*
+ * we only parse 'locale' when we are waiting for a value inside of
+ * this node
+ */
+static gboolean
+gconf_reader_parse_locale( NactGConfReader *reader, xmlNode *locale )
+{
+ static const gchar *thisfn = "gconf_reader_parse_locale";
+ g_debug( "%s: reader=%p, locale=%p", thisfn, reader, locale );
+
+ gboolean ret = TRUE;
+ xmlNode *iter;
+ gboolean default_found = FALSE;
+
+ for( iter = locale->children ; iter ; iter = iter->next ){
+
+ if( iter->type != XML_ELEMENT_NODE ){
+ continue;
+ }
+
+ if( strxcmp( iter->name, NACT_GCONF_XML_SCHEMA_SHORT ) &&
+ strxcmp( iter->name, NACT_GCONF_XML_SCHEMA_LONG ) &&
+ strxcmp( iter->name, NACT_GCONF_XML_SCHEMA_DFT )){
+
+ add_message( reader, ERR_UNEXPECTED_NODE, ( const char * ) iter->name, iter->line );
+ ret = FALSE;
+ continue;
+ }
+
+ if( !strxcmp( iter->name, NACT_GCONF_XML_SCHEMA_SHORT ) ||
+ !strxcmp( iter->name, NACT_GCONF_XML_SCHEMA_LONG )){
+ continue;
+ }
+
+ if( default_found ){
+ add_message( reader, ERR_UNEXPECTED_NODE, ( const char * ) iter->name, iter->line );
+ ret = FALSE;
+ continue;
+ }
+
+ g_assert( ret );
+ default_found = TRUE;
+ gconf_reader_parse_default( reader, iter );
+ }
+
+ return( ret );
+}
+
+static void
+gconf_reader_parse_default( NactGConfReader *reader, xmlNode *node )
+{
+ if( reader->private->value ){
+ add_message( reader, ERR_VALUE_ALREADY_SET, reader->private->value, node->line );
+ return;
+ }
+
+ xmlChar *text = xmlNodeGetContent( node );
+ reader->private->value = g_strdup(( const gchar * ) text );
+ xmlFree( text );
+ /*g_debug( "gconf_reader_parse_default: set value=%s", reader->private->value );*/
+}
+
+static void
+apply_schema_value( NactGConfReader *reader )
+{
+ static const gchar *thisfn = "gconf_reader_apply_schema_value";
+ g_debug( "%s: reader=%p, entry=%s, value=%s", thisfn, reader, reader->private->entry, reader->private->value );
+
+ GSList *list;
+
+ if( reader->private->entry && strlen( reader->private->entry )){
+ if( !strcmp( reader->private->entry, ACTION_VERSION_ENTRY )){
+ na_action_set_version( reader->private->action, reader->private->value );
+
+ } else if( !strcmp( reader->private->entry, ACTION_LABEL_ENTRY )){
+ na_action_set_label( reader->private->action, reader->private->value );
+
+ } else if( !strcmp( reader->private->entry, ACTION_TOOLTIP_ENTRY )){
+ na_action_set_tooltip( reader->private->action, reader->private->value );
+
+ } else if( !strcmp( reader->private->entry, ACTION_ICON_ENTRY )){
+ na_action_set_icon( reader->private->action, reader->private->value );
+
+ } else if( !strcmp( reader->private->entry, ACTION_PROFILE_LABEL_ENTRY )){
+ na_action_profile_set_label( reader->private->profile, reader->private->value );
+
+ } else if( !strcmp( reader->private->entry, ACTION_PATH_ENTRY )){
+ na_action_profile_set_path( reader->private->profile, reader->private->value );
+
+ } else if( !strcmp( reader->private->entry, ACTION_PARAMETERS_ENTRY )){
+ na_action_profile_set_parameters( reader->private->profile, reader->private->value );
+
+ } else if( !strcmp( reader->private->entry, ACTION_BASENAMES_ENTRY )){
+ list = na_utils_schema_to_gslist( reader->private->entry );
+ na_action_profile_set_basenames( reader->private->profile, list );
+ na_utils_free_string_list( list );
+
+ } else if( !strcmp( reader->private->entry, ACTION_MATCHCASE_ENTRY )){
+ na_action_profile_set_matchcase( reader->private->profile, na_utils_schema_to_boolean( reader->private->entry, TRUE ));
+
+ } else if( !strcmp( reader->private->entry, ACTION_MULTIPLE_ENTRY )){
+ na_action_profile_set_multiple( reader->private->profile, na_utils_schema_to_boolean( reader->private->entry, FALSE ));
+
+ } else if( !strcmp( reader->private->entry, ACTION_ISFILE_ENTRY )){
+ na_action_profile_set_isfile( reader->private->profile, na_utils_schema_to_boolean( reader->private->entry, TRUE ));
+
+ } else if( !strcmp( reader->private->entry, ACTION_ISDIR_ENTRY )){
+ na_action_profile_set_isdir( reader->private->profile, na_utils_schema_to_boolean( reader->private->entry, FALSE ));
+
+ } else if( !strcmp( reader->private->entry, ACTION_MIMETYPES_ENTRY )){
+ list = na_utils_schema_to_gslist( reader->private->entry );
+ na_action_profile_set_mimetypes( reader->private->profile, list );
+ na_utils_free_string_list( list );
+
+ } else if( !strcmp( reader->private->entry, ACTION_SCHEMES_ENTRY )){
+ list = na_utils_schema_to_gslist( reader->private->entry );
+ na_action_profile_set_schemes( reader->private->profile, list );
+ na_utils_free_string_list( list );
+
+ } else {
+ g_assert_not_reached();
+ }
+ }
+}
+
+static void
+add_message( NactGConfReader *reader, const gchar *format, ... )
+{
+ g_debug( "nact_gconf_reader_add_message: format=%s", format );
+
+ va_list va;
+ va_start( va, format );
+ gchar *tmp = g_strdup_vprintf( format, va );
+ va_end( va );
+ reader->private->messages = g_slist_append( reader->private->messages, tmp );
+}
+
+/*
+ * note that up to v 1.10 included, key check was made via a call to
+ * g_ascii_strncasecmp, which was doubly wrong:
+ * - because XML is case sensitive by definition
+ * - because this did not detect a key longer that the reference.
+ */
+static int
+strxcmp( const xmlChar *a, const char *b )
+{
+ xmlChar *xb = xmlCharStrdup( b );
+ int ret = xmlStrcmp( a, xb );
+ xmlFree( xb );
+ return( ret );
+}
+
+static gchar *
+get_uuid_from_key( NactGConfReader *reader, const gchar *key, guint line )
+{
+ if( !g_str_has_prefix( key, NA_GCONF_CONFIG_PATH )){
+ add_message( reader,
+ ERR_INVALID_KEY_PREFIX, NA_GCONF_CONFIG_PATH, key, line );
+ return( NULL );
+ }
+
+ gchar *uuid = g_strdup( key + strlen( NA_GCONF_CONFIG_PATH "/" ));
+ gchar *pos = g_strstr_len( uuid, strlen( uuid ), "/" );
+ if( pos != NULL ){
+ *pos = '\0';
+ }
+
+ if( !is_uuid_valid( uuid )){
+ add_message( reader, ERR_NOT_AN_UUID, uuid, line );
+ g_free( uuid );
+ uuid = NULL;
+ }
+
+ return( uuid );
+}
+
+static gboolean
+is_uuid_valid( const gchar *uuid )
+{
+ uuid_t uu;
+ return( uuid_parse( uuid, uu ) == 0 );
+}
+
+/*
+ * prefix was already been checked when extracting the uuid
+ */
+static gchar *
+get_profile_name_from_key( const gchar *key, const gchar *uuid )
+{
+ gchar *prefix = g_strdup_printf( "%s/%s/%s", NA_GCONF_CONFIG_PATH, uuid, ACTION_PROFILE_PREFIX );
+ gchar *profile_name = NULL;
+
+ if( g_str_has_prefix( key, prefix )){
+ profile_name = g_strdup( key + strlen( prefix ));
+ gchar *pos = g_strrstr( profile_name, "/" );
+ if( pos != NULL ){
+ *pos = '\0';
+ }
+ }
+
+ g_free( prefix );
+ return( profile_name );
+}
+
+static gchar *
+get_entry_from_key( const gchar *key )
+{
+ gchar *pos = g_strrstr( key, "/" );
+ g_assert( pos );
+ gchar *entry = g_strdup( pos+1 );
+ return( entry );
+}
+
+static void
+free_schema_value( NactGConfReader *reader )
+{
+ int i;
+
+ reader->private->profile = NULL;
+ reader->private->locale_waited = FALSE;
+
+ g_free( reader->private->entry );
+ reader->private->entry = NULL;
+
+ g_free( reader->private->value );
+ reader->private->value = NULL;
+
+ for( i=0 ; reader_str[i].entry ; ++i ){
+ reader_str[i].entry_found = FALSE;
+ }
+}
diff --git a/src/nact/nact-gconf-reader.h b/src/nact/nact-gconf-reader.h
new file mode 100644
index 0000000..fff9993
--- /dev/null
+++ b/src/nact/nact-gconf-reader.h
@@ -0,0 +1,77 @@
+/*
+ * Nautilus Actions
+ * A Nautilus extension which offers configurable context menu actions.
+ *
+ * Copyright (C) 2005 The GNOME Foundation
+ * Copyright (C) 2006, 2007, 2008 Frederic Ruaudel and others (see AUTHORS)
+ * Copyright (C) 2009 Pierre Wieser and others (see AUTHORS)
+ *
+ * This Program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this Library; see the file COPYING. If not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place,
+ * Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Authors:
+ * Frederic Ruaudel <grumz grumz net>
+ * Rodrigo Moya <rodrigo gnome-db org>
+ * Pierre Wieser <pwieser trychlos org>
+ * ... and many others (see AUTHORS)
+ */
+
+#ifndef __NACT_GCONF_READER_H__
+#define __NACT_GCONF_READER_H__
+
+/*
+ * NactGConfReader class definition.
+ *
+ * This is the base class for importing into and exporting from GConf
+ * storage subsystem.
+ */
+
+#include <glib-object.h>
+
+#include <common/na-action.h>
+#include <common/na-action-profile.h>
+
+G_BEGIN_DECLS
+
+#define NACT_GCONF_READER_TYPE ( nact_gconf_reader_get_type())
+#define NACT_GCONF_READER( object ) ( G_TYPE_CHECK_INSTANCE_CAST( object, NACT_GCONF_READER_TYPE, NactGConfReader ))
+#define NACT_GCONF_READER_CLASS( klass ) ( G_TYPE_CHECK_CLASS_CAST( klass, NACT_GCONF_READER_TYPE, NactGConfReaderClass ))
+#define NACT_IS_GCONF_READER( object ) ( G_TYPE_CHECK_INSTANCE_TYPE( object, NACT_GCONF_READER_TYPE ))
+#define NACT_IS_GCONF_READER_CLASS( klass ) ( G_TYPE_CHECK_CLASS_TYPE(( klass ), NACT_GCONF_READER_TYPE ))
+#define NACT_GCONF_READER_GET_CLASS( object ) ( G_TYPE_INSTANCE_GET_CLASS(( object ), NACT_GCONF_READER_TYPE, NactGConfReaderClass ))
+
+typedef struct NactGConfReaderPrivate NactGConfReaderPrivate;
+
+typedef struct {
+ GObject parent;
+ NactGConfReaderPrivate *private;
+}
+ NactGConfReader;
+
+typedef struct NactGConfReaderClassPrivate NactGConfReaderClassPrivate;
+
+typedef struct {
+ GObjectClass parent;
+ NactGConfReaderClassPrivate *private;
+}
+ NactGConfReaderClass;
+
+GType nact_gconf_reader_get_type( void );
+
+NAAction *nact_gconf_reader_import( GObject *window, const gchar *uri, GSList **msg );
+
+G_END_DECLS
+
+#endif /* __NACT_GCONF_READER_H__ */
diff --git a/src/nact/nact-gconf-schema-writer.c b/src/nact/nact-gconf-writer.c
similarity index 67%
rename from src/nact/nact-gconf-schema-writer.c
rename to src/nact/nact-gconf-writer.c
index 944c70d..9ffd256 100644
--- a/src/nact/nact-gconf-schema-writer.c
+++ b/src/nact/nact-gconf-writer.c
@@ -34,32 +34,46 @@
#include <libxml/tree.h>
-#include "nact-gconf-schema-writer.h"
+#include <common/na-gconf-keys.h>
+#include <common/na-utils.h>
+
+#include "nact-gconf-keys.h"
+#include "nact-gconf-writer.h"
/* private class data
*/
-struct NactGConfSchemaWriterClassPrivate {
+struct NactGConfWriterClassPrivate {
};
/* private instance data
*/
-struct NactGConfSchemaWriterPrivate {
+struct NactGConfWriterPrivate {
gboolean dispose_has_run;
gchar *uuid;
};
-static GObjectClass *st_parent_class = NULL;
+/* instance properties
+ */
+enum {
+ PROP_GCONF_WRITER_UUID = 1
+};
-static GType register_type( void );
-static void class_init( NactGConfSchemaWriterClass *klass );
-static void instance_init( GTypeInstance *instance, gpointer klass );
-static void instance_dispose( GObject *object );
-static void instance_finalize( GObject *object );
+#define PROP_GCONF_WRITER_UUID_STR "gconf-writer-uuid"
-static NactGConfSchemaWriter *gconf_schema_writer_new( void );
-static xmlDocPtr create_xml( NactGConfSchemaWriter *writer, NAAction *action );
-static void create_schema_entry(
- NactGConfSchemaWriter *writer,
+static GObjectClass *st_parent_class = NULL;
+
+static GType register_type( void );
+static void class_init( NactGConfWriterClass *klass );
+static void instance_init( GTypeInstance *instance, gpointer klass );
+static void instance_get_property( GObject *object, guint property_id, GValue *value, GParamSpec *spec );
+static void instance_set_property( GObject *object, guint property_id, const GValue *value, GParamSpec *spec );
+static void instance_dispose( GObject *object );
+static void instance_finalize( GObject *object );
+
+static NactGConfWriter *gconf_writer_new( const gchar *uuid );
+static xmlDocPtr create_xml( NactGConfWriter *writer, NAAction *action );
+static void create_schema_entry(
+ NactGConfWriter *writer,
const gchar *profile_name,
const gchar *key,
const gchar *value,
@@ -69,7 +83,7 @@ static void create_schema_entry(
gboolean is_l10n_value );
GType
-nact_gconf_schema_writer_get_type( void )
+nact_gconf_writer_get_type( void )
{
static GType object_type = 0;
@@ -84,26 +98,26 @@ static GType
register_type( void )
{
static GTypeInfo info = {
- sizeof( NactGConfSchemaWriterClass ),
+ sizeof( NactGConfWriterClass ),
NULL,
NULL,
( GClassInitFunc ) class_init,
NULL,
NULL,
- sizeof( NactGConfSchemaWriter ),
+ sizeof( NactGConfWriter ),
0,
( GInstanceInitFunc ) instance_init
};
- GType type = g_type_register_static( G_TYPE_OBJECT, "NactGConfSchemaWriter", &info, 0 );
+ GType type = g_type_register_static( G_TYPE_OBJECT, "NactGConfWriter", &info, 0 );
return( type );
}
static void
-class_init( NactGConfSchemaWriterClass *klass )
+class_init( NactGConfWriterClass *klass )
{
- static const gchar *thisfn = "nact_gconf_schema_writer_class_init";
+ static const gchar *thisfn = "nact_gconf_writer_class_init";
g_debug( "%s: klass=%p", thisfn, klass );
st_parent_class = g_type_class_peek_parent( klass );
@@ -111,29 +125,74 @@ class_init( NactGConfSchemaWriterClass *klass )
GObjectClass *object_class = G_OBJECT_CLASS( klass );
object_class->dispose = instance_dispose;
object_class->finalize = instance_finalize;
-
- klass->private = g_new0( NactGConfSchemaWriterClassPrivate, 1 );
+ object_class->get_property = instance_get_property;
+ object_class->set_property = instance_set_property;
+
+ GParamSpec *spec;
+ spec = g_param_spec_string(
+ PROP_GCONF_WRITER_UUID_STR,
+ PROP_GCONF_WRITER_UUID_STR,
+ "UUID of the action", "",
+ G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE );
+ g_object_class_install_property( object_class, PROP_GCONF_WRITER_UUID, spec );
+
+ klass->private = g_new0( NactGConfWriterClassPrivate, 1 );
}
static void
instance_init( GTypeInstance *instance, gpointer klass )
{
- static const gchar *thisfn = "nact_gconf_schema_writer_instance_init";
+ static const gchar *thisfn = "nact_gconf_writer_instance_init";
g_debug( "%s: instance=%p, klass=%p", thisfn, instance, klass );
- g_assert( NACT_IS_GCONF_SCHEMA_WRITER( instance ));
- NactGConfSchemaWriter *self = NACT_GCONF_SCHEMA_WRITER( instance );
+ g_assert( NACT_IS_GCONF_WRITER( instance ));
+ NactGConfWriter *self = NACT_GCONF_WRITER( instance );
- self->private = g_new0( NactGConfSchemaWriterPrivate, 1 );
+ self->private = g_new0( NactGConfWriterPrivate, 1 );
self->private->dispose_has_run = FALSE;
}
static void
+instance_get_property( GObject *object, guint property_id, GValue *value, GParamSpec *spec )
+{
+ g_assert( NACT_IS_GCONF_WRITER( object ));
+ NactGConfWriter *self = NACT_GCONF_WRITER( object );
+
+ switch( property_id ){
+ case PROP_GCONF_WRITER_UUID:
+ g_value_set_string( value, self->private->uuid );
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID( object, property_id, spec );
+ break;
+ }
+}
+
+static void
+instance_set_property( GObject *object, guint property_id, const GValue *value, GParamSpec *spec )
+{
+ g_assert( NACT_IS_GCONF_WRITER( object ));
+ NactGConfWriter *self = NACT_GCONF_WRITER( object );
+
+ switch( property_id ){
+ case PROP_GCONF_WRITER_UUID:
+ g_free( self->private->uuid );
+ self->private->uuid = g_value_dup_string( value );
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID( object, property_id, spec );
+ break;
+ }
+}
+
+static void
instance_dispose( GObject *object )
{
- g_assert( NACT_IS_GCONF_SCHEMA_WRITER( object ));
- NactGConfSchemaWriter *self = NACT_GCONF_SCHEMA_WRITER( object );
+ g_assert( NACT_IS_GCONF_WRITER( object ));
+ NactGConfWriter *self = NACT_GCONF_WRITER( object );
if( !self->private->dispose_has_run ){
@@ -147,8 +206,8 @@ instance_dispose( GObject *object )
static void
instance_finalize( GObject *object )
{
- g_assert( NACT_IS_GCONF_SCHEMA_WRITER( object ));
- NactGConfSchemaWriter *self = NACT_GCONF_SCHEMA_WRITER( object );
+ g_assert( NACT_IS_GCONF_WRITER( object ));
+ NactGConfWriter *self = NACT_GCONF_WRITER( object );
g_free( self->private->uuid );
@@ -160,44 +219,43 @@ instance_finalize( GObject *object )
}
}
-static NactGConfSchemaWriter *
-gconf_schema_writer_new( void )
-{
- return( g_object_new( NACT_GCONF_SCHEMA_WRITER_TYPE, NULL ));
-}
-
-static void
-gconf_schema_writer_set_uuid( NactGConfSchemaWriter *writer, const gchar *uuid )
+static NactGConfWriter *
+gconf_writer_new( const gchar *uuid )
{
- g_free( writer->private->uuid );
- writer->private->uuid = g_strdup( uuid );
+ return( g_object_new( NACT_GCONF_WRITER_TYPE, PROP_GCONF_WRITER_UUID_STR, uuid, NULL ));
}
/**
* Export the specified action as a GConf schema.
+ *
+ * Returns the written filename.
*/
-void
-nact_gconf_schema_writer_export( NAAction *action, const gchar *folder, gchar **msg )
+gchar *
+nact_gconf_writer_export( NAAction *action, const gchar *folder, gchar **msg )
{
- NactGConfSchemaWriter *writer = gconf_schema_writer_new();
-
gchar *uuid = na_action_get_uuid( action );
- gconf_schema_writer_set_uuid( writer, uuid );
+ NactGConfWriter *writer = gconf_writer_new( uuid );
g_free( uuid );
xmlDocPtr doc = create_xml( writer, action );
- /* generate the filename name and save the schema into it */
- gchar *filename = g_strdup_printf( "%s/%s.schema", folder, writer->private->uuid );
- xmlSaveFormatFileEnc( filename, doc, "UTF-8", 1 );
- g_free( filename );
+ /* generate the filename name and save the xml document into it */
+ gchar *filename = g_strdup_printf( "%s/action-%s.xml", folder, writer->private->uuid );
+ if( xmlSaveFormatFileEnc( filename, doc, "UTF-8", 1 ) == -1 ){
+ g_free( filename );
+ filename = NULL;
+ }
xmlFreeDoc (doc);
xmlCleanupParser();
+
+ g_object_unref( writer );
+
+ return( filename );
}
static xmlDocPtr
-create_xml( NactGConfSchemaWriter *writer, NAAction *action )
+create_xml( NactGConfWriter *writer, NAAction *action )
{
xmlDocPtr doc = xmlNewDoc( BAD_CAST( "1.0" ));
xmlNodePtr root_node = xmlNewNode( NULL, BAD_CAST( NACT_GCONF_XML_ROOT ));
@@ -299,7 +357,7 @@ create_xml( NactGConfSchemaWriter *writer, NAAction *action )
}
static void
-create_schema_entry( NactGConfSchemaWriter *writer,
+create_schema_entry( NactGConfWriter *writer,
const gchar *profile_name, const gchar *key, const gchar *value,
xmlDocPtr doc, xmlNodePtr list_node, const gchar *type, gboolean is_l10n_value )
{
@@ -312,17 +370,17 @@ create_schema_entry( NactGConfSchemaWriter *writer,
xmlNodePtr schema_node = xmlNewChild( list_node, NULL, BAD_CAST( NACT_GCONF_XML_SCHEMA_ENTRY ), NULL );
- xmlChar *content = BAD_CAST( g_build_path( "/", NACT_GCONF_SCHEMA_PREFIX, path, NULL ));
+ /*xmlChar *content = BAD_CAST( g_build_path( "/", NACT_GCONF_SCHEMA_PREFIX, path, NULL ));
xmlNewChild( schema_node, NULL, BAD_CAST( NACT_GCONF_XML_SCHEMA_KEY ), content );
- xmlFree( content );
+ xmlFree( content );*/
xmlNewChild( schema_node, NULL, BAD_CAST( NACT_GCONF_XML_SCHEMA_APPLYTO ), BAD_CAST( path ));
- xmlNewChild( schema_node, NULL, BAD_CAST( NACT_GCONF_XML_SCHEMA_TYPE ), BAD_CAST( type ));
+ /*xmlNewChild( schema_node, NULL, BAD_CAST( NACT_GCONF_XML_SCHEMA_TYPE ), BAD_CAST( type ));*/
- if( !g_ascii_strcasecmp( type, "list" )){
+ /*if( !g_ascii_strcasecmp( type, "list" )){
xmlNewChild( schema_node, NULL, BAD_CAST( NACT_GCONF_XML_SCHEMA_LIST_TYPE ), BAD_CAST( "string" ));
- }
+ }*/
/* if the default value must be localized, put it in the <locale> element
*/
diff --git a/src/nact/nact-gconf-writer.h b/src/nact/nact-gconf-writer.h
new file mode 100644
index 0000000..26e10bf
--- /dev/null
+++ b/src/nact/nact-gconf-writer.h
@@ -0,0 +1,77 @@
+/*
+ * Nautilus Actions
+ * A Nautilus extension which offers configurable context menu actions.
+ *
+ * Copyright (C) 2005 The GNOME Foundation
+ * Copyright (C) 2006, 2007, 2008 Frederic Ruaudel and others (see AUTHORS)
+ * Copyright (C) 2009 Pierre Wieser and others (see AUTHORS)
+ *
+ * This Program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this Library; see the file COPYING. If not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place,
+ * Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Authors:
+ * Frederic Ruaudel <grumz grumz net>
+ * Rodrigo Moya <rodrigo gnome-db org>
+ * Pierre Wieser <pwieser trychlos org>
+ * ... and many others (see AUTHORS)
+ */
+
+#ifndef __NACT_GCONF_WRITER_H__
+#define __NACT_GCONF_WRITER_H__
+
+/*
+ * NactGConfWriter class definition.
+ *
+ * This is the base class for importing into and exporting from GConf
+ * storage subsystem.
+ */
+
+#include <glib-object.h>
+
+#include <common/na-action.h>
+#include <common/na-action-profile.h>
+
+G_BEGIN_DECLS
+
+#define NACT_GCONF_WRITER_TYPE ( nact_gconf_writer_get_type())
+#define NACT_GCONF_WRITER( object ) ( G_TYPE_CHECK_INSTANCE_CAST( object, NACT_GCONF_WRITER_TYPE, NactGConfWriter ))
+#define NACT_GCONF_WRITER_CLASS( klass ) ( G_TYPE_CHECK_CLASS_CAST( klass, NACT_GCONF_WRITER_TYPE, NactGConfWriterClass ))
+#define NACT_IS_GCONF_WRITER( object ) ( G_TYPE_CHECK_INSTANCE_TYPE( object, NACT_GCONF_WRITER_TYPE ))
+#define NACT_IS_GCONF_WRITER_CLASS( klass ) ( G_TYPE_CHECK_CLASS_TYPE(( klass ), NACT_GCONF_WRITER_TYPE ))
+#define NACT_GCONF_WRITER_GET_CLASS( object ) ( G_TYPE_INSTANCE_GET_CLASS(( object ), NACT_GCONF_WRITER_TYPE, NactGConfWriterClass ))
+
+typedef struct NactGConfWriterPrivate NactGConfWriterPrivate;
+
+typedef struct {
+ GObject parent;
+ NactGConfWriterPrivate *private;
+}
+ NactGConfWriter;
+
+typedef struct NactGConfWriterClassPrivate NactGConfWriterClassPrivate;
+
+typedef struct {
+ GObjectClass parent;
+ NactGConfWriterClassPrivate *private;
+}
+ NactGConfWriterClass;
+
+GType nact_gconf_writer_get_type( void );
+
+gchar *nact_gconf_writer_export( NAAction *action, const gchar *folder, gchar **msg );
+
+G_END_DECLS
+
+#endif /* __NACT_GCONF_WRITER_H__ */
diff --git a/src/nact/nact-iactions-list.c b/src/nact/nact-iactions-list.c
index 797db99..3cbcfab 100644
--- a/src/nact/nact-iactions-list.c
+++ b/src/nact/nact-iactions-list.c
@@ -66,7 +66,7 @@ static void interface_base_finalize( NactIActionsListInterface *klass );
static void v_on_selection_changed( GtkTreeSelection *selection, gpointer user_data );
static gboolean v_on_button_press_event( GtkWidget *widget, GdkEventButton *event, gpointer data );
-static gboolean v_on_key_press_event( GtkWidget *widget, GdkEventKey *event, gpointer data );
+static gboolean v_on_key_pressed_event( GtkWidget *widget, GdkEventKey *event, gpointer data );
static void do_initial_load_widget( NactWindow *window );
static void do_runtime_init_widget( NactWindow *window );
@@ -388,19 +388,20 @@ v_on_button_press_event( GtkWidget *widget, GdkEventButton *event, gpointer user
}
static gboolean
-v_on_key_press_event( GtkWidget *widget, GdkEventKey *event, gpointer user_data )
+v_on_key_pressed_event( GtkWidget *widget, GdkEventKey *event, gpointer user_data )
{
- /*static const gchar *thisfn = "nact_iactions_list_v_on_key_pres_event";
+ /*static const gchar *thisfn = "nact_iactions_list_v_on_key_pressed_event";
g_debug( "%s: widget=%p, event=%p, user_data=%p", thisfn, widget, event, user_data );*/
g_assert( NACT_IS_IACTIONS_LIST( user_data ));
g_assert( NACT_IS_WINDOW( user_data ));
+ g_assert( event->type == GDK_KEY_PRESS );
gboolean stop = FALSE;
NactIActionsList *instance = NACT_IACTIONS_LIST( user_data );
- if( NACT_IACTIONS_LIST_GET_INTERFACE( instance )->on_key_press_event ){
- stop = NACT_IACTIONS_LIST_GET_INTERFACE( instance )->on_key_press_event( widget, event, user_data );
+ if( NACT_IACTIONS_LIST_GET_INTERFACE( instance )->on_key_pressed_event ){
+ stop = NACT_IACTIONS_LIST_GET_INTERFACE( instance )->on_key_pressed_event( widget, event, user_data );
}
if( !stop ){
@@ -465,7 +466,7 @@ do_runtime_init_widget( NactWindow *window )
window,
G_OBJECT( widget ),
"key-press-event",
- G_CALLBACK( v_on_key_press_event ));
+ G_CALLBACK( v_on_key_pressed_event ));
/* catch double-click */
nact_window_signal_connect(
@@ -473,6 +474,10 @@ do_runtime_init_widget( NactWindow *window )
G_OBJECT( widget ),
"button-press-event",
G_CALLBACK( v_on_button_press_event ));
+
+ /* clear the selection */
+ GtkTreeSelection *selection = gtk_tree_view_get_selection( GTK_TREE_VIEW( widget ));
+ gtk_tree_selection_unselect_all( selection );
}
static void
diff --git a/src/nact/nact-iactions-list.h b/src/nact/nact-iactions-list.h
index 57a7ee4..a399249 100644
--- a/src/nact/nact-iactions-list.h
+++ b/src/nact/nact-iactions-list.h
@@ -64,7 +64,7 @@ typedef struct {
void ( *fill_actions_list ) ( NactWindow *window );
void ( *on_selection_changed ) ( GtkTreeSelection *selection, gpointer user_data );
gboolean ( *on_button_press_event )( GtkWidget *widget, GdkEventButton *event, gpointer data );
- gboolean ( *on_key_press_event ) ( GtkWidget *widget, GdkEventKey *event, gpointer data );
+ gboolean ( *on_key_pressed_event ) ( GtkWidget *widget, GdkEventKey *event, gpointer data );
gboolean ( *on_double_click ) ( GtkWidget *widget, GdkEventButton *event, gpointer data );
gboolean ( *on_enter_key_pressed ) ( GtkWidget *widget, GdkEventKey *event, gpointer data );
}
diff --git a/src/nact/nact-iprefs.c b/src/nact/nact-iprefs.c
index 3a7d719..fbe690a 100644
--- a/src/nact/nact-iprefs.c
+++ b/src/nact/nact-iprefs.c
@@ -51,8 +51,8 @@ struct NactIPrefsInterfacePrivate {
/* key to read/write the last visited folder when browsing for a file
*/
#define IPREFS_IPROFILE_CONDITION_FOLDER_URI "iprofile-conditions-folder-uri"
-#define IPREFS_IMPORT_ACTIONS_FOLDER_URI "main-window-import-folder-uri"
-#define IPREFS_EXPORT_ACTIONS_FOLDER_URI "main-window-export-folder-uri"
+#define IPREFS_IMPORT_ACTIONS_FOLDER_URI "import-folder-uri"
+#define IPREFS_EXPORT_ACTIONS_FOLDER_URI "export-folder-uri"
static GType register_type( void );
static void interface_base_init( NactIPrefsInterface *klass );
diff --git a/src/nact/nact-main-window.c b/src/nact/nact-main-window.c
index a87828a..545174d 100644
--- a/src/nact/nact-main-window.c
+++ b/src/nact/nact-main-window.c
@@ -46,8 +46,8 @@
#include "nact-application.h"
#include "nact-action-conditions-editor.h"
#include "nact-action-profiles-editor.h"
-#include "nact-action-profiles-editor.h"
-#include "nact-gconf-schema-writer.h"
+#include "nact-assist-export.h"
+#include "nact-assist-import.h"
#include "nact-iactions-list.h"
#include "nact-iprefs.h"
#include "nact-main-window.h"
@@ -61,7 +61,6 @@ struct NactMainWindowClassPrivate {
*/
struct NactMainWindowPrivate {
gboolean dispose_has_run;
- gboolean export_mode;
gchar *current_uuid;
gchar *current_label;
};
@@ -69,7 +68,6 @@ struct NactMainWindowPrivate {
/* the GConf key used to read/write size and position of auxiliary dialogs
*/
#define IPREFS_IMPORT_ACTIONS "main-window-import-actions"
-#define IPREFS_EXPORT_ACTIONS "main-window-export-actions"
static GObjectClass *st_parent_class = NULL;
@@ -97,19 +95,11 @@ static void on_duplicate_button_clicked( GtkButton *button, gpointer user_da
static void on_delete_button_clicked( GtkButton *button, gpointer user_data );
static void on_import_button_clicked( GtkButton *button, gpointer user_data );
static void on_export_button_clicked( GtkButton *button, gpointer user_data );
-static void on_saveas_button_clicked( GtkButton *button, gpointer user_data );
static gboolean on_dialog_response( GtkDialog *dialog, gint response_id, BaseWindow *window );
static void on_actions_changed( NAIPivotContainer *instance, gpointer user_data );
-
static void set_current_action( NactMainWindow *window, const NAAction *action );
static void do_set_current_action( NactWindow *window, const gchar *uuid, const gchar *label );
-static void set_export_mode( NactWindow *window, gboolean mode );
-static void setup_buttons( NactWindow *window );
-static void do_import_actions( NactMainWindow *window, const gchar *filename );
-static void do_export_actions( NactMainWindow *window, const gchar *folder );
-
-/*static gint count_actions( BaseWindow *window );*/
GType
nact_main_window_get_type( void )
@@ -240,9 +230,6 @@ instance_dispose( GObject *window )
self->private->dispose_has_run = TRUE;
- g_free( self->private->current_uuid );
- g_free( self->private->current_label );
-
/* chain up to the parent class */
G_OBJECT_CLASS( st_parent_class )->dispose( window );
}
@@ -257,6 +244,9 @@ instance_finalize( GObject *window )
g_assert( NACT_IS_MAIN_WINDOW( window ));
NactMainWindow *self = ( NactMainWindow * ) window;
+ g_free( self->private->current_uuid );
+ g_free( self->private->current_label );
+
g_free( self->private );
/* chain call to parent class */
@@ -331,9 +321,6 @@ on_runtime_init_toplevel( BaseWindow *window )
nact_window_signal_connect_by_name( NACT_WINDOW( window ), "DeleteActionButton", "clicked", G_CALLBACK( on_delete_button_clicked ));
nact_window_signal_connect_by_name( NACT_WINDOW( window ), "ImportButton", "clicked", G_CALLBACK( on_import_button_clicked ));
nact_window_signal_connect_by_name( NACT_WINDOW( window ), "ExportButton", "clicked", G_CALLBACK( on_export_button_clicked ));
- nact_window_signal_connect_by_name( NACT_WINDOW( window ), "SaveAsButton", "clicked", G_CALLBACK( on_saveas_button_clicked ));
-
- setup_buttons( NACT_WINDOW( window ));
}
static void
@@ -345,21 +332,18 @@ on_actions_list_selection_changed( GtkTreeSelection *selection, gpointer user_da
g_assert( NACT_IS_MAIN_WINDOW( user_data ));
BaseWindow *window = BASE_WINDOW( user_data );
- if( !NACT_MAIN_WINDOW( window )->private->export_mode ){
-
- GtkWidget *edit_button = base_window_get_widget( window, "EditActionButton" );
- GtkWidget *delete_button = base_window_get_widget( window, "DeleteActionButton" );
- GtkWidget *duplicate_button = base_window_get_widget( window, "DuplicateActionButton" );
+ GtkWidget *edit_button = base_window_get_widget( window, "EditActionButton" );
+ GtkWidget *delete_button = base_window_get_widget( window, "DeleteActionButton" );
+ GtkWidget *duplicate_button = base_window_get_widget( window, "DuplicateActionButton" );
- gboolean enabled = ( gtk_tree_selection_count_selected_rows( selection ) > 0 );
+ gboolean enabled = ( gtk_tree_selection_count_selected_rows( selection ) > 0 );
- gtk_widget_set_sensitive( edit_button, enabled );
- gtk_widget_set_sensitive( delete_button, enabled );
- gtk_widget_set_sensitive( duplicate_button, enabled );
+ gtk_widget_set_sensitive( edit_button, enabled );
+ gtk_widget_set_sensitive( delete_button, enabled );
+ gtk_widget_set_sensitive( duplicate_button, enabled );
- NAAction *action = NA_ACTION( nact_iactions_list_get_selected_action( NACT_WINDOW( window )));
- set_current_action( NACT_MAIN_WINDOW( window ), action );
- }
+ NAAction *action = NA_ACTION( nact_iactions_list_get_selected_action( NACT_WINDOW( window )));
+ set_current_action( NACT_MAIN_WINDOW( window ), action );
}
static gboolean
@@ -367,9 +351,7 @@ on_actions_list_double_click( GtkWidget *widget, GdkEventButton *event, gpointer
{
g_assert( event->type == GDK_2BUTTON_PRESS );
- if( !NACT_MAIN_WINDOW( user_data )->private->export_mode ){
- on_edit_button_clicked( NULL, user_data );
- }
+ on_edit_button_clicked( NULL, user_data );
return( TRUE );
}
@@ -377,9 +359,7 @@ on_actions_list_double_click( GtkWidget *widget, GdkEventButton *event, gpointer
static gboolean
on_actions_list_enter_key_pressed( GtkWidget *widget, GdkEventKey *event, gpointer user_data )
{
- if( !NACT_MAIN_WINDOW( user_data )->private->export_mode ){
- on_edit_button_clicked( NULL, user_data );
- }
+ on_edit_button_clicked( NULL, user_data );
return( TRUE );
}
@@ -598,8 +578,14 @@ on_import_button_clicked( GtkButton *button, gpointer user_data )
static const gchar *thisfn = "nact_main_window_on_import_button_clicked";
g_debug( "%s: button=%p, user_data=%p", thisfn, button, user_data );
+ nact_assist_import_run( NACT_WINDOW( user_data ));
+
g_assert( NACT_IS_MAIN_WINDOW( user_data ));
NactWindow *wndmain = NACT_WINDOW( user_data );
+ nact_iactions_list_set_focus( wndmain );
+
+ /*g_assert( NACT_IS_MAIN_WINDOW( user_data ));
+ NactWindow *wndmain = NACT_WINDOW( user_data );
GtkWidget *dialog = gtk_file_chooser_dialog_new(
_( "Importing new actions" ),
@@ -629,7 +615,7 @@ on_import_button_clicked( GtkButton *button, gpointer user_data )
gtk_widget_destroy( dialog );
- nact_iactions_list_set_focus( wndmain );
+ nact_iactions_list_set_focus( wndmain );*/
}
/*
@@ -643,53 +629,13 @@ on_export_button_clicked( GtkButton *button, gpointer user_data )
static const gchar *thisfn = "nact_main_window_on_export_button_clicked";
g_debug( "%s: button=%p, user_data=%p", thisfn, button, user_data );
- gboolean export = gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON( button ));
- set_export_mode( NACT_WINDOW( user_data ), export );
+ nact_assist_export_run( NACT_WINDOW( user_data ));
g_assert( NACT_IS_MAIN_WINDOW( user_data ));
NactWindow *wndmain = NACT_WINDOW( user_data );
-
nact_iactions_list_set_focus( wndmain );
}
-static void
-on_saveas_button_clicked( GtkButton *button, gpointer user_data )
-{
- static const gchar *thisfn = "nact_main_window_on_saveas_button_clicked";
- g_debug( "%s: button=%p, user_data=%p", thisfn, button, user_data );
-
- g_assert( NACT_IS_MAIN_WINDOW( user_data ));
- NactWindow *wndmain = NACT_WINDOW( user_data );
-
- GtkWidget *dialog = gtk_file_chooser_dialog_new(
- _( "Selecting a folder in which selected actions are to be saved" ),
- NULL,
- GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER,
- GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
- GTK_STOCK_OK, GTK_RESPONSE_OK,
- NULL
- );
-
- nact_iprefs_position_named_window( wndmain, GTK_WINDOW( dialog ), IPREFS_EXPORT_ACTIONS );
- gchar *uri = nact_iprefs_get_export_folder_uri( wndmain );
- gtk_file_chooser_set_uri( GTK_FILE_CHOOSER( dialog ), uri );
- g_free( uri );
-
- if( gtk_dialog_run( GTK_DIALOG( dialog )) == GTK_RESPONSE_OK ){
- uri = gtk_file_chooser_get_uri( GTK_FILE_CHOOSER( dialog ));
- do_export_actions( NACT_MAIN_WINDOW( wndmain ), uri );
- }
-
- nact_iprefs_save_export_folder_uri( wndmain, uri );
- g_free( uri );
-
- nact_iprefs_save_named_window_position( wndmain, GTK_WINDOW( dialog ), IPREFS_EXPORT_ACTIONS );
- gtk_widget_destroy( dialog );
-
- GtkWidget *export_button = base_window_get_widget( BASE_WINDOW( user_data ), "ExportButton" );
- gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( export_button ), FALSE );
-}
-
static gboolean
on_dialog_response( GtkDialog *dialog, gint response_id, BaseWindow *window )
{
@@ -756,101 +702,3 @@ do_set_current_action( NactWindow *window, const gchar *uuid, const gchar *label
NACT_MAIN_WINDOW( window )->private->current_uuid = g_strdup( uuid );
NACT_MAIN_WINDOW( window )->private->current_label = g_strdup( label );
}
-
-static void
-set_export_mode( NactWindow *window, gboolean mode )
-{
- g_assert( NACT_IS_MAIN_WINDOW( window ));
- NactMainWindow *self = NACT_MAIN_WINDOW( window );
-
- nact_iactions_list_set_multiple_selection( window, mode );
- self->private->export_mode = mode;
- setup_buttons( window );
-}
-
-static void
-setup_buttons( NactWindow *window )
-{
- g_assert( NACT_IS_MAIN_WINDOW( window ));
- NactMainWindow *self = NACT_MAIN_WINDOW( window );
-
- GtkWidget *new_button = base_window_get_widget( BASE_WINDOW( window ), "NewActionButton" );
- GtkWidget *edit_button = base_window_get_widget( BASE_WINDOW( window ), "EditActionButton" );
- GtkWidget *duplicate_button = base_window_get_widget( BASE_WINDOW( window ), "DuplicateActionButton" );
- GtkWidget *delete_button = base_window_get_widget( BASE_WINDOW( window ), "DeleteActionButton" );
- GtkWidget *import_button = base_window_get_widget( BASE_WINDOW( window ), "ImportButton" );
- GtkWidget *saveas_button = base_window_get_widget( BASE_WINDOW( window ), "SaveAsButton" );
- GtkWidget *close_button = base_window_get_widget( BASE_WINDOW( window ), "CloseButton" );
-
- gtk_widget_set_sensitive( new_button, !self->private->export_mode );
- gtk_widget_set_sensitive( edit_button, !self->private->export_mode );
- gtk_widget_set_sensitive( delete_button, !self->private->export_mode );
- gtk_widget_set_sensitive( duplicate_button, !self->private->export_mode );
- gtk_widget_set_sensitive( import_button, !self->private->export_mode );
- gtk_widget_set_sensitive( close_button, !self->private->export_mode );
-
- gtk_widget_set_sensitive( saveas_button, self->private->export_mode );
-
- GtkWidget *label = base_window_get_widget( BASE_WINDOW( window ), "ExportModeLabel" );
- gchar *text = g_strdup( "" );
- if( self->private->export_mode ){
- g_free( text );
- text = g_strdup( _( "Export mode toggled.\n"
- "Please, select actions to be exported (multiple selection is authorized).\n" ));
- }
- gtk_label_set_label( GTK_LABEL( label ), text );
- g_free( text );
-}
-
-static void
-do_import_actions( NactMainWindow *window, const gchar *filename )
-{
- static const gchar *thisfn = "nact_main_window_do_import_actions";
- g_debug( "%s: window=%p, filename=%p", thisfn, window, filename );
-}
-
-static void
-do_export_actions( NactMainWindow *window, const gchar *folder )
-{
- static const gchar *thisfn = "nact_main_window_do_export_actions";
- g_debug( "%s: window=%p, folder=%p", thisfn, window, folder );
-
- GSList *actions = nact_iactions_list_get_selected_actions( NACT_WINDOW( window ));
- GSList *ia;
- gchar *msg = NULL;
- gchar *reason = NULL;
- gchar *tmp;
-
- for( ia = actions ; ia ; ia = ia->next ){
- NAAction *action = NA_ACTION( ia->data );
- nact_gconf_schema_writer_export( action, folder, &msg );
- if( msg ){
- if( reason ){
- tmp = g_strdup_printf( "%s\n", reason );
- g_free( reason );
- reason = tmp;
- }
- tmp = g_strdup_printf( "%s%s", reason, msg );
- g_free( reason );
- reason = tmp;
- }
- g_free( msg );
- }
-
- if( reason ){
- base_window_error_dlg( BASE_WINDOW( window ), GTK_MESSAGE_WARNING,
- _( "One or more errors have been detected when exporting actions." ), reason );
- g_free( reason );
- }
-
- g_slist_free( actions );
-}
-
-/*static gint
-count_actions( BaseWindow *window )
-{
- NactApplication *appli = NACT_APPLICATION( base_window_get_application( window ));
- NAPivot *pivot = NA_PIVOT( nact_application_get_pivot( appli ));
- GSList *actions = na_pivot_get_actions( pivot );
- return( g_slist_length( actions ));
-}*/
diff --git a/src/nact/nact-window.c b/src/nact/nact-window.c
index 7566257..83df734 100644
--- a/src/nact/nact-window.c
+++ b/src/nact/nact-window.c
@@ -63,18 +63,19 @@ typedef struct {
NactWindowRecordedSignal;
static GObjectClass *st_parent_class = NULL;
+static gboolean st_debug_signal_connect = FALSE;
-static GType register_type( void );
-static void class_init( NactWindowClass *klass );
-static void iprefs_iface_init( NactIPrefsInterface *iface );
-static void instance_init( GTypeInstance *instance, gpointer klass );
-static void instance_dispose( GObject *application );
-static void instance_finalize( GObject *application );
+static GType register_type( void );
+static void class_init( NactWindowClass *klass );
+static void iprefs_iface_init( NactIPrefsInterface *iface );
+static void instance_init( GTypeInstance *instance, gpointer klass );
+static void instance_dispose( GObject *application );
+static void instance_finalize( GObject *application );
-static gchar *v_get_iprefs_window_id( NactWindow *window );
+static gchar *v_get_iprefs_window_id( NactWindow *window );
-static void on_runtime_init_toplevel( BaseWindow *window );
-static void on_all_widgets_showed( BaseWindow *dialog );
+static void on_runtime_init_toplevel( BaseWindow *window );
+static void on_all_widgets_showed( BaseWindow *dialog );
GType
nact_window_get_type( void )
@@ -137,11 +138,11 @@ class_init( NactWindowClass *klass )
klass->private = g_new0( NactWindowClassPrivate, 1 );
- klass->get_iprefs_window_id = v_get_iprefs_window_id;
-
BaseWindowClass *base_class = BASE_WINDOW_CLASS( klass );
base_class->runtime_init_toplevel = on_runtime_init_toplevel;
base_class->all_widgets_showed = on_all_widgets_showed;
+
+ klass->get_iprefs_window_id = v_get_iprefs_window_id;
}
static void
@@ -187,7 +188,9 @@ instance_dispose( GObject *window )
for( is = self->private->signals ; is ; is = is->next ){
NactWindowRecordedSignal *str = ( NactWindowRecordedSignal * ) is->data;
g_signal_handler_disconnect( str->instance, str->handler_id );
- /*g_debug( "%s: disconnecting signal handler %p:%lu", thisfn, str->instance, str->handler_id );*/
+ if( st_debug_signal_connect ){
+ g_debug( "%s: disconnecting signal handler %p:%lu", thisfn, str->instance, str->handler_id );
+ }
g_free( str );
}
g_slist_free( self->private->signals );
@@ -305,7 +308,7 @@ nact_window_warn_action_modified( NactWindow *window, const NAAction *action )
if( label && strlen( label )){
first = g_strdup_printf( _( "The action \"%s\" has been modified." ), label );
} else {
- first = g_strdup( _( "The newly created action has been modified" ));
+ first = g_strdup( _( "The newly created action has been modified." ));
}
gchar *second = g_strdup( _( "Are you sure you want to quit without saving it ?" ));
@@ -337,7 +340,7 @@ nact_window_get_actions( NactWindow *window )
void
nact_window_signal_connect( NactWindow *window, GObject *instance, const gchar *signal, GCallback fn )
{
- /*static const gchar *thisfn = "nact_window_signal_connect";*/
+ static const gchar *thisfn = "nact_window_signal_connect";
gulong handler_id = g_signal_connect( instance, signal, fn, window );
@@ -346,7 +349,9 @@ nact_window_signal_connect( NactWindow *window, GObject *instance, const gchar *
str->handler_id = handler_id;
window->private->signals = g_slist_prepend( window->private->signals, str );
- /*g_debug( "%s: connecting signal handler %p:%lu", thisfn, instance, handler_id );*/
+ if( st_debug_signal_connect ){
+ g_debug( "%s: connecting signal handler %p:%lu", thisfn, instance, handler_id );
+ }
}
void
diff --git a/src/nact/nact-window.h b/src/nact/nact-window.h
index 1542730..400368b 100644
--- a/src/nact/nact-window.h
+++ b/src/nact/nact-window.h
@@ -66,8 +66,8 @@ typedef struct {
NactWindowClassPrivate *private;
/* api */
- gchar * ( *get_iprefs_window_id )( NactWindow *window );
- void ( *set_current_action ) ( NactWindow *window, const gchar *uuid, const gchar *label );
+ gchar * ( *get_iprefs_window_id )( NactWindow *window );
+ void ( *set_current_action ) ( NactWindow *window, const gchar *uuid, const gchar *label );
}
NactWindowClass;
diff --git a/src/nact/nautilus-actions-config.ui b/src/nact/nautilus-actions-config.ui
index 84fc077..e09c352 100644
--- a/src/nact/nautilus-actions-config.ui
+++ b/src/nact/nautilus-actions-config.ui
@@ -38,12 +38,8 @@
</packing>
</child>
<child>
- <object class="GtkTable" id="table1">
+ <object class="GtkVButtonBox" id="vbuttonbox1">
<property name="visible">True</property>
- <property name="n_rows">4</property>
- <property name="n_columns">2</property>
- <property name="column_spacing">4</property>
- <property name="row_spacing">4</property>
<property name="homogeneous">True</property>
<child>
<object class="GtkButton" id="NewActionButton">
@@ -55,8 +51,9 @@
<property name="use_stock">True</property>
</object>
<packing>
- <property name="x_options"></property>
- <property name="y_options"></property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
</packing>
</child>
<child>
@@ -70,10 +67,24 @@
<property name="use_stock">True</property>
</object>
<packing>
- <property name="top_attach">1</property>
- <property name="bottom_attach">2</property>
- <property name="x_options"></property>
- <property name="y_options"></property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="DuplicateActionButton">
+ <property name="label" translatable="yes">D_uplicate</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="image">DuplicateButtonImage</property>
+ <property name="use_underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">2</property>
</packing>
</child>
<child>
@@ -87,10 +98,9 @@
<property name="use_stock">True</property>
</object>
<packing>
- <property name="top_attach">3</property>
- <property name="bottom_attach">4</property>
- <property name="x_options"></property>
- <property name="y_options"></property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">3</property>
</packing>
</child>
<child>
@@ -103,15 +113,14 @@
<property name="use_underline">True</property>
</object>
<packing>
- <property name="left_attach">1</property>
- <property name="right_attach">2</property>
- <property name="x_options"></property>
- <property name="y_options"></property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">4</property>
</packing>
</child>
<child>
- <object class="GtkToggleButton" id="ExportButton">
- <property name="label" translatable="yes">E_xport mode</property>
+ <object class="GtkButton" id="ExportButton">
+ <property name="label" translatable="yes">E_xport...</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
@@ -119,50 +128,11 @@
<property name="use_underline">True</property>
</object>
<packing>
- <property name="left_attach">1</property>
- <property name="right_attach">2</property>
- <property name="top_attach">2</property>
- <property name="bottom_attach">3</property>
- <property name="x_options"></property>
- <property name="y_options"></property>
- </packing>
- </child>
- <child>
- <object class="GtkButton" id="SaveAsButton">
- <property name="label" translatable="yes">gtk-save-as</property>
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="receives_default">True</property>
- <property name="use_stock">True</property>
- </object>
- <packing>
- <property name="left_attach">1</property>
- <property name="right_attach">2</property>
- <property name="top_attach">3</property>
- <property name="bottom_attach">4</property>
- <property name="x_options"></property>
- <property name="y_options"></property>
- </packing>
- </child>
- <child>
- <object class="GtkButton" id="DuplicateActionButton">
- <property name="label" translatable="yes">D_uplicate</property>
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="receives_default">True</property>
- <property name="image">DuplicateButtonImage</property>
- <property name="use_underline">True</property>
- </object>
- <packing>
- <property name="top_attach">2</property>
- <property name="bottom_attach">3</property>
- <property name="x_options"></property>
- <property name="y_options"></property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">5</property>
</packing>
</child>
- <child>
- <placeholder/>
- </child>
</object>
<packing>
<property name="expand">False</property>
@@ -172,21 +142,10 @@
</child>
</object>
<packing>
- <property name="padding">6</property>
- <property name="position">2</property>
- </packing>
- </child>
- <child>
- <object class="GtkLabel" id="ExportModeLabel">
- <property name="visible">True</property>
- <property name="xalign">0</property>
- <property name="yalign">0</property>
- <property name="xpad">10</property>
- </object>
- <packing>
<property name="expand">False</property>
<property name="fill">False</property>
- <property name="position">3</property>
+ <property name="padding">6</property>
+ <property name="position">0</property>
</packing>
</child>
<child internal-child="action_area">
@@ -227,7 +186,7 @@
<packing>
<property name="expand">False</property>
<property name="pack_type">end</property>
- <property name="position">0</property>
+ <property name="position">1</property>
</packing>
</child>
</object>
@@ -1501,45 +1460,171 @@ file(s)/folder(s)</property>
<action-widget response="-5">okbutton4</action-widget>
</action-widgets>
</object>
+ <object class="GtkAssistant" id="ExportAssistant">
+ <property name="events">GDK_KEY_PRESS_MASK | GDK_STRUCTURE_MASK</property>
+ <property name="border_width">12</property>
+ <property name="title" translatable="yes">Exporting actions</property>
+ <property name="modal">True</property>
+ <child>
+ <object class="GtkLabel" id="label1">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">This assistant will guide you through the process of exporting actions.</property>
+ </object>
+ <packing>
+ <property name="page_type">intro</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHBox" id="hbox1">
+ <property name="visible">True</property>
+ <child>
+ <object class="GtkScrolledWindow" id="scrolledwindow3">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hscrollbar_policy">automatic</property>
+ <property name="vscrollbar_policy">automatic</property>
+ <property name="shadow_type">in</property>
+ <child>
+ <object class="GtkTreeView" id="ActionsList">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="events">GDK_BUTTON_PRESS_MASK | GDK_KEY_PRESS_MASK</property>
+ <property name="headers_visible">False</property>
+ <property name="rules_hint">True</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label2">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Please select one or more actions
+to be exported.
+
+You may use Ctrl and Shift keys
+to extend a selection.</property>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="title">Selection of the exported actions</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHBox" id="hbox2">
+ <property name="visible">True</property>
+ <child>
+ <object class="GtkFileChooserWidget" id="ExportFolderChooser">
+ <property name="visible">True</property>
+ <property name="orientation">vertical</property>
+ <property name="local_only">False</property>
+ <property name="preview_widget_active">False</property>
+ <property name="use_preview_label">False</property>
+ <property name="action">select-folder</property>
+ </object>
+ <packing>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="title">Selection of the target folder</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label3">
+ <property name="visible">True</property>
+ <property name="use_markup">True</property>
+ </object>
+ <packing>
+ <property name="page_type">confirm</property>
+ <property name="title">Summary</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label4">
+ <property name="visible">True</property>
+ <property name="use_markup">True</property>
+ </object>
+ <packing>
+ <property name="page_type">summary</property>
+ <property name="title">Export is done</property>
+ </packing>
+ </child>
+ </object>
+ <object class="GtkAssistant" id="ImportAssistant">
+ <property name="border_width">12</property>
+ <property name="title" translatable="yes">Importing actions</property>
+ <property name="modal">True</property>
+ <child>
+ <object class="GtkLabel" id="label1">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">This assistant will guide you through the process of importing actions.</property>
+ </object>
+ <packing>
+ <property name="page_type">intro</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkFileChooserWidget" id="filechooserwidget1">
+ <property name="visible">True</property>
+ <property name="orientation">vertical</property>
+ <property name="local_only">False</property>
+ <property name="preview_widget_active">False</property>
+ <property name="use_preview_label">False</property>
+ <property name="select_multiple">True</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label3">
+ <property name="visible">True</property>
+ </object>
+ <packing>
+ <property name="page_type">confirm</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label2">
+ <property name="visible">True</property>
+ </object>
+ <packing>
+ <property name="page_type">summary</property>
+ </packing>
+ </child>
+ </object>
<object class="GtkImage" id="LegendButtonImage">
<property name="visible">True</property>
<property name="stock">gtk-help</property>
<property name="icon-size">4</property>
</object>
- <object class="GtkImage" id="ImportButtonImage">
+ <object class="GtkImage" id="DuplicateButtonImage">
<property name="visible">True</property>
- <property name="stock">gtk-convert</property>
+ <property name="stock">gtk-copy</property>
<property name="icon-size">4</property>
</object>
- <object class="GtkImage" id="ExportButtonImage">
+ <object class="GtkImage" id="ImportButtonImage">
<property name="visible">True</property>
- <property name="stock">gtk-execute</property>
+ <property name="stock">gtk-convert</property>
<property name="icon-size">4</property>
</object>
- <object class="GtkImage" id="DuplicateButtonImage">
+ <object class="GtkImage" id="ExportButtonImage">
<property name="visible">True</property>
- <property name="stock">gtk-copy</property>
+ <property name="stock">gtk-save</property>
<property name="icon-size">4</property>
</object>
<object class="GtkSizeGroup" id="IProfileConditionsLabelSizeGroup">
<widgets>
- <widget name="MenuLabelLabel"/>
- <widget name="MenuTooltipLabel"/>
- <widget name="MenuIconLabel"/>
- <widget name="ActionPathLabel"/>
<widget name="ActionParametersLabel"/>
- </widgets>
- </object>
- <object class="GtkSizeGroup" id="MainButtonsSizeGroup">
- <property name="mode">both</property>
- <widgets>
- <widget name="NewActionButton"/>
- <widget name="EditActionButton"/>
- <widget name="DeleteActionButton"/>
- <widget name="ImportButton"/>
- <widget name="ExportButton"/>
- <widget name="SaveAsButton"/>
- <widget name="DuplicateActionButton"/>
+ <widget name="ActionPathLabel"/>
+ <widget name="MenuIconLabel"/>
+ <widget name="MenuTooltipLabel"/>
+ <widget name="MenuLabelLabel"/>
</widgets>
</object>
</interface>
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]