From 05f872662aebed4251a2cd599cac3fe3972edbd3 Mon Sep 17 00:00:00 2001 From: Pierre Wieser Date: Tue, 14 Jul 2009 20:24:20 +0200 Subject: [PATCH] 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(-) create mode 100644 src/nact/nact-assist-export.c create mode 100644 src/nact/nact-assist-export.h create mode 100644 src/nact/nact-assist-import.c create mode 100644 src/nact/nact-assist-import.h create mode 100644 src/nact/nact-assistant.c create mode 100644 src/nact/nact-assistant.h rename src/nact/{nact-gconf-schema.h => nact-gconf-keys.h} (54%) create mode 100644 src/nact/nact-gconf-reader.c create mode 100644 src/nact/nact-gconf-reader.h delete mode 100644 src/nact/nact-gconf-schema-writer.h delete mode 100644 src/nact/nact-gconf-schema.c rename src/nact/{nact-gconf-schema-writer.c => nact-gconf-writer.c} (67%) create mode 100644 src/nact/nact-gconf-writer.h diff --git a/ChangeLog b/ChangeLog index 2f0a03f7..684fd110 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,55 @@ +2009-07-14 Pierre Wieser + + 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 * src/nact/nact-main-window.c: diff --git a/src/common/na-action-profile.c b/src/common/na-action-profile.c index 0a75ff52..a931a9d6 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 b4895308..407ee2c7 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 ba690337..89fc8921 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 aa9ababa..6a05c7ba 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 b5d2d61e..a1dbc4fd 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 2d4456d7..5b3aa2d8 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 fe13916c..ab08afec 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 4df13bbc..754fc150 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 57a8a3cc..a8a9e80d 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 757f75af..b4a15993 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 218090bc..a512cf7b 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 00000000..9fbae76b --- /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 + * Rodrigo Moya + * Pierre Wieser + * ... and many others (see AUTHORS) + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include + +#include +#include + +#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( _( "About to export selected actions :\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\nInto the destination folder :\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( + _( "One or more errors have been detected when exporting actions.\n\n%s" ), + window->private->reason ); + + } else { + text = g_strdup( _( "Selected actions have been successfully exported...\n\n" )); + + tmp = g_strdup_printf( _( "%s...in folder :\n\n\t%s/\n\n" ), text, window->private->uri ); + g_free( text ); + text = tmp; + + tmp = g_strdup_printf( _( "%s...as files :\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 00000000..f61f001c --- /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 + * Rodrigo Moya + * Pierre Wieser + * ... 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 00000000..64c17266 --- /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 + * Rodrigo Moya + * Pierre Wieser + * ... and many others (see AUTHORS) + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include + +#include +#include + +#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( _( "About to import selected files :\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( _( "Selected files have been imported :\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 00000000..93bea857 --- /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 + * Rodrigo Moya + * Pierre Wieser + * ... 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 00000000..1befe39a --- /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 + * Rodrigo Moya + * Pierre Wieser + * ... and many others (see AUTHORS) + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include + +#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 00000000..ccdc3124 --- /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 + * Rodrigo Moya + * Pierre Wieser + * ... 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 3cac6db4..af74b868 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 -#include -#include -#include -#include - 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 00000000..4219053d --- /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 + * Rodrigo Moya + * Pierre Wieser + * ... and many others (see AUTHORS) + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include + +#include +#include +#include + +#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 00000000..fff99938 --- /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 + * Rodrigo Moya + * Pierre Wieser + * ... 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 + +#include +#include + +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.h b/src/nact/nact-gconf-schema-writer.h deleted file mode 100644 index 7b8cf7b7..00000000 --- a/src/nact/nact-gconf-schema-writer.h +++ /dev/null @@ -1,74 +0,0 @@ -/* - * 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 - * Rodrigo Moya - * Pierre Wieser - * ... and many others (see AUTHORS) - */ - -#ifndef __NACT_GCONF_SCHEMA_WRITER_H__ -#define __NACT_GCONF_SCHEMA_WRITER_H__ - -/* - * NactGConfSchemaWriter class definition. - * - * This is the base class for importing into and exporting from GConf - * storage subsystem. - */ - -#include "nact-gconf-schema.h" - -G_BEGIN_DECLS - -#define NACT_GCONF_SCHEMA_WRITER_TYPE ( nact_gconf_schema_writer_get_type()) -#define NACT_GCONF_SCHEMA_WRITER( object ) ( G_TYPE_CHECK_INSTANCE_CAST( object, NACT_GCONF_SCHEMA_WRITER_TYPE, NactGConfSchemaWriter )) -#define NACT_GCONF_SCHEMA_WRITER_CLASS( klass ) ( G_TYPE_CHECK_CLASS_CAST( klass, NACT_GCONF_SCHEMA_WRITER_TYPE, NactGConfSchemaWriterClass )) -#define NACT_IS_GCONF_SCHEMA_WRITER( object ) ( G_TYPE_CHECK_INSTANCE_TYPE( object, NACT_GCONF_SCHEMA_WRITER_TYPE )) -#define NACT_IS_GCONF_SCHEMA_WRITER_CLASS( klass ) ( G_TYPE_CHECK_CLASS_TYPE(( klass ), NACT_GCONF_SCHEMA_WRITER_TYPE )) -#define NACT_GCONF_SCHEMA_WRITER_GET_CLASS( object ) ( G_TYPE_INSTANCE_GET_CLASS(( object ), NACT_GCONF_SCHEMA_WRITER_TYPE, NactGConfSchemaWriterClass )) - -typedef struct NactGConfSchemaWriterPrivate NactGConfSchemaWriterPrivate; - -typedef struct { - NactGConfSchema parent; - NactGConfSchemaWriterPrivate *private; -} - NactGConfSchemaWriter; - -typedef struct NactGConfSchemaWriterClassPrivate NactGConfSchemaWriterClassPrivate; - -typedef struct { - NactGConfSchemaClass parent; - NactGConfSchemaWriterClassPrivate *private; -} - NactGConfSchemaWriterClass; - -GType nact_gconf_schema_writer_get_type( void ); - -void nact_gconf_schema_writer_export( NAAction *action, const gchar *folder, gchar **msg ); - -G_END_DECLS - -#endif /* __NACT_GCONF_SCHEMA_WRITER_H__ */ diff --git a/src/nact/nact-gconf-schema.c b/src/nact/nact-gconf-schema.c deleted file mode 100644 index 9f9e3af0..00000000 --- a/src/nact/nact-gconf-schema.c +++ /dev/null @@ -1,144 +0,0 @@ -/* - * 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 - * Rodrigo Moya - * Pierre Wieser - * ... and many others (see AUTHORS) - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include "nact-gconf-schema.h" - -/* private class data - */ -struct NactGConfSchemaClassPrivate { -}; - -/* private instance data - */ -struct NactGConfSchemaPrivate { - gboolean dispose_has_run; -}; - -static GObjectClass *st_parent_class = NULL; - -static GType register_type( void ); -static void class_init( NactGConfSchemaClass *klass ); -static void instance_init( GTypeInstance *instance, gpointer klass ); -static void instance_dispose( GObject *object ); -static void instance_finalize( GObject *object ); - -GType -nact_gconf_schema_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( NactGConfSchemaClass ), - NULL, - NULL, - ( GClassInitFunc ) class_init, - NULL, - NULL, - sizeof( NactGConfSchema ), - 0, - ( GInstanceInitFunc ) instance_init - }; - - GType type = g_type_register_static( G_TYPE_OBJECT, "NactGConfSchema", &info, 0 ); - - return( type ); -} - -static void -class_init( NactGConfSchemaClass *klass ) -{ - static const gchar *thisfn = "nact_gconf_schema_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( NactGConfSchemaClassPrivate, 1 ); -} - -static void -instance_init( GTypeInstance *instance, gpointer klass ) -{ - static const gchar *thisfn = "nact_gconf_schema_instance_init"; - g_debug( "%s: instance=%p, klass=%p", thisfn, instance, klass ); - - g_assert( NACT_IS_GCONF_SCHEMA( instance )); - NactGConfSchema *self = NACT_GCONF_SCHEMA( instance ); - - self->private = g_new0( NactGConfSchemaPrivate, 1 ); - - self->private->dispose_has_run = FALSE; -} - -static void -instance_dispose( GObject *object ) -{ - g_assert( NACT_IS_GCONF_SCHEMA( object )); - NactGConfSchema *self = NACT_GCONF_SCHEMA( object ); - - if( !self->private->dispose_has_run ){ - - self->private->dispose_has_run = TRUE; - - /* chain up to the parent class */ - G_OBJECT_CLASS( st_parent_class )->dispose( object ); - } -} - -static void -instance_finalize( GObject *object ) -{ - g_assert( NACT_IS_GCONF_SCHEMA( object )); - NactGConfSchema *self = NACT_GCONF_SCHEMA( object ); - - g_free( self->private ); - - /* chain call to parent class */ - if( st_parent_class->finalize ){ - G_OBJECT_CLASS( st_parent_class )->finalize( object ); - } -} 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 944c70db..9ffd256c 100644 --- a/src/nact/nact-gconf-schema-writer.c +++ b/src/nact/nact-gconf-writer.c @@ -34,32 +34,46 @@ #include -#include "nact-gconf-schema-writer.h" +#include +#include + +#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 element */ diff --git a/src/nact/nact-gconf-writer.h b/src/nact/nact-gconf-writer.h new file mode 100644 index 00000000..26e10bfa --- /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 + * Rodrigo Moya + * Pierre Wieser + * ... 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 + +#include +#include + +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 797db990..3cbcfab3 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 57a7ee40..a3992491 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 3a7d7195..fbe690a9 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 a87828a2..545174d0 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 75662572..83df734b 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 1542730d..400368b8 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 84fc0772..e09c3521 100644 --- a/src/nact/nautilus-actions-config.ui +++ b/src/nact/nautilus-actions-config.ui @@ -38,12 +38,8 @@ - + True - 4 - 2 - 4 - 4 True @@ -55,8 +51,9 @@ True - - + False + False + 0 @@ -70,10 +67,24 @@ True - 1 - 2 - - + False + False + 1 + + + + + D_uplicate + True + True + True + DuplicateButtonImage + True + + + False + False + 2 @@ -87,10 +98,9 @@ True - 3 - 4 - - + False + False + 3 @@ -103,15 +113,14 @@ True - 1 - 2 - - + False + False + 4 - - E_xport mode + + E_xport... True True True @@ -119,50 +128,11 @@ True - 1 - 2 - 2 - 3 - - - - - - - gtk-save-as - True - True - True - True - - - 1 - 2 - 3 - 4 - - - - - - - D_uplicate - True - True - True - DuplicateButtonImage - True - - - 2 - 3 - - + False + False + 5 - - - False @@ -172,21 +142,10 @@ - 6 - 2 - - - - - True - 0 - 0 - 10 - - False False - 3 + 6 + 0 @@ -227,7 +186,7 @@ False end - 0 + 1 @@ -1501,45 +1460,171 @@ file(s)/folder(s) okbutton4 + + GDK_KEY_PRESS_MASK | GDK_STRUCTURE_MASK + 12 + Exporting actions + True + + + True + This assistant will guide you through the process of exporting actions. + + + intro + + + + + True + + + True + True + automatic + automatic + in + + + True + True + GDK_BUTTON_PRESS_MASK | GDK_KEY_PRESS_MASK + False + True + + + + + 0 + + + + + True + Please select one or more actions +to be exported. + +You may use Ctrl and Shift keys +to extend a selection. + + + 1 + + + + + Selection of the exported actions + + + + + True + + + True + vertical + False + False + False + select-folder + + + 0 + + + + + Selection of the target folder + + + + + True + True + + + confirm + Summary + + + + + True + True + + + summary + Export is done + + + + + 12 + Importing actions + True + + + True + This assistant will guide you through the process of importing actions. + + + intro + + + + + True + vertical + False + False + False + True + + + + + True + + + confirm + + + + + True + + + summary + + + True gtk-help 4 - + True - gtk-convert + gtk-copy 4 - + True - gtk-execute + gtk-convert 4 - + True - gtk-copy + gtk-save 4 - - - - - - - - both - - - - - - - - + + + + -- 2.11.4.GIT