[nautilus-actions] Implement execution of singular vs. plural command forms
- From: Pierre Wieser <pwieser src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [nautilus-actions] Implement execution of singular vs. plural command forms
- Date: Thu, 29 Jul 2010 22:00:47 +0000 (UTC)
commit 129e5110f63db1e54df9126495247ab0c817f26f
Author: Pierre Wieser <pwieser trychlos org>
Date: Thu Jul 29 23:59:32 2010 +0200
Implement execution of singular vs. plural command forms
ChangeLog | 19 +++
src/api/na-object-action.h | 2 -
src/api/na-object-profile.h | 2 -
src/core/na-object-action.c | 29 -----
src/core/na-object-profile.c | 232 ------------------------------------
src/core/na-tokens.c | 144 +++++++++++++++++++++--
src/core/na-tokens.h | 13 ++-
src/plugin-menu/nautilus-actions.c | 194 ++++++++++++++++++++-----------
src/utils/nautilus-actions-run.c | 40 ++-----
9 files changed, 295 insertions(+), 380 deletions(-)
---
diff --git a/ChangeLog b/ChangeLog
index 698d642..a895631 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,24 @@
2010-07-29 Pierre Wieser <pwieser trychlos org>
+ Do some cleanup in NAObjectAction and NAObjectProfile code.
+ Implement execution of singular vs. plural command forms.
+
+ * src/api/na-object-action.h:
+ * src/core/na-object-action.c (na_object_action_is_candidate):
+ Removed function.
+
+ * src/api/na-object-profile.h:
+ * src/core/na-object-profile.c (na_object_profile_parse_parameters):
+ Removed function.
+
+ * src/core/na-tokens.c:
+ * src/core/na-tokens.h (na_tokens_execute_action): New function.
+
+ * src/plugin-menu/nautilus-actions.c (execute_action):
+ Move action execution to NATokens class.
+
+ * src/utils/nautilus-actions-run.c: Now use NATokens class.
+
* doc/: Renamed as docs/
* configure.ac:
diff --git a/src/api/na-object-action.h b/src/api/na-object-action.h
index f9e4ff7..dd1965d 100644
--- a/src/api/na-object-action.h
+++ b/src/api/na-object-action.h
@@ -84,8 +84,6 @@ gchar *na_object_action_get_new_profile_name( const NAObjectAction *act
void na_object_action_attach_profile( NAObjectAction *action, NAObjectProfile *profile );
void na_object_action_set_last_version( NAObjectAction *action );
-gboolean na_object_action_is_candidate( const NAObjectAction *action, guint target, GList *selection );
-
G_END_DECLS
#endif /* __NAUTILUS_ACTIONS_API_NA_OBJECT_ACTION_H__ */
diff --git a/src/api/na-object-profile.h b/src/api/na-object-profile.h
index a633bf3..8106234 100644
--- a/src/api/na-object-profile.h
+++ b/src/api/na-object-profile.h
@@ -79,8 +79,6 @@ GType na_object_profile_get_type( void );
NAObjectProfile *na_object_profile_new( void );
NAObjectProfile *na_object_profile_new_with_defaults( void );
-gchar *na_object_profile_parse_parameters( const NAObjectProfile *profile, gint target, GList *selected );
-
G_END_DECLS
#endif /* __NAUTILUS_ACTIONS_API_NA_OBJECT_PROFILE_H__ */
diff --git a/src/core/na-object-action.c b/src/core/na-object-action.c
index ec5c9f1..96ce4a1 100644
--- a/src/core/na-object-action.c
+++ b/src/core/na-object-action.c
@@ -761,32 +761,3 @@ na_object_action_set_last_version( NAObjectAction *action )
na_object_set_version( action, "2.0" );
}
}
-
-/**
- * na_object_action_is_candidate:
- * @action: the #NAObjectAction to be tested.
- * @target: the current target.
- * @selection: the current Nautilus selection.
- *
- * Returns: %TRUE if the @action may be candidate for this @target.
- *
- * Note that this public function will become NAIContext::is_candidate
- * when NAObjectAction will implement the interface.
- */
-gboolean
-na_object_action_is_candidate( const NAObjectAction *action, guint target, GList *selection )
-{
- gboolean is_candidate = FALSE;
-
- g_return_val_if_fail( NA_IS_OBJECT_ACTION( action ), is_candidate );
-
- if( !action->private->dispose_has_run ){
-
- is_candidate =
- ( na_object_is_target_selection( action ) && target == ITEM_TARGET_SELECTION ) ||
- ( na_object_is_target_location( action ) && target == ITEM_TARGET_LOCATION ) ||
- ( na_object_is_target_toolbar( action ) && target == ITEM_TARGET_TOOLBAR );
- }
-
- return( is_candidate );
-}
diff --git a/src/core/na-object-profile.c b/src/core/na-object-profile.c
index cd4d1ee..ae084fb 100644
--- a/src/core/na-object-profile.c
+++ b/src/core/na-object-profile.c
@@ -683,235 +683,3 @@ na_object_profile_new_with_defaults( void )
return( profile );
}
-
-/**
- * Expands the parameters path, in function of the found tokens.
- *
- * @profile: the selected profile.
- * @target: the current target.
- * @files: the list of currently selected #NASelectedInfo items.
- *
- * Valid parameters are :
- *
- * %d : base dir of the (first) selected file(s)/folder(s)
- * %f : the name of the (first) selected file/folder
- * %h : hostname of the (first) URI
- * %m : list of the basename of the selected files/directories separated by space.
- * %M : list of the selected files/directories with their complete path separated by space.
- * %p : port number from the (first) URI
- * %R : space-separated list of URIs
- * %s : scheme of the (first) URI
- * %u : (first) URI
- * %U : username of the (first) URI
- * %% : a percent sign
- *
- * Adding a parameter requires updating of :
- * - nautilus-actions/core/na-object-profile.c::na_object_profile_parse_parameters()
- * - nautilus-actions/nact/nact-icommand-tab.c:parse_parameters()
- * - nautilus-actions/nact/nautilus-actions-config-tool.ui:LegendDialog
- */
-gchar *
-na_object_profile_parse_parameters( const NAObjectProfile *profile, gint target, GList* files )
-{
- gchar *parsed = NULL;
- GString *string;
- GList *ifi;
- gboolean first;
- gchar *iuri, *ipath, *ibname;
- GFile *iloc;
- gchar *uri = NULL;
- gchar *scheme = NULL;
- gchar *dirname = NULL;
- gchar *filename = NULL;
- gchar *hostname = NULL;
- gchar *username = NULL;
- gint port_number = 0;
- GString *basename_list, *pathname_list, *uris_list;
- gchar *tmp, *iter, *old_iter;
- NAGnomeVFSURI *vfs;
-
- g_return_val_if_fail( NA_IS_OBJECT_PROFILE( profile ), NULL );
-
- if( profile->private->dispose_has_run ){
- return( NULL );
- }
-
- string = g_string_new( "" );
- basename_list = g_string_new( "" );
- pathname_list = g_string_new( "" );
- uris_list = g_string_new( "" );
- first = TRUE;
-
- for( ifi = files ; ifi ; ifi = ifi->next ){
-
- iuri = na_selected_info_get_uri( NA_SELECTED_INFO( ifi->data ));
- iloc = na_selected_info_get_location( NA_SELECTED_INFO( ifi->data ));
- ipath = g_file_get_path( iloc );
- ibname = g_file_get_basename( iloc );
-
- if( first ){
-
- vfs = g_new0( NAGnomeVFSURI, 1 );
- na_gnome_vfs_uri_parse( vfs, iuri );
-
- uri = g_strdup( iuri );
- dirname = ipath ? g_path_get_dirname( ipath ) : NULL;
- scheme = g_strdup( vfs->scheme );
- filename = g_strdup( ibname );
- hostname = g_strdup( vfs->host_name );
- username = g_strdup( vfs->user_name );
- port_number = vfs->host_port;
-
- first = FALSE;
- na_gnome_vfs_uri_free( vfs );
- }
-
- if( ibname ){
- if( strlen( basename_list->str )){
- basename_list = g_string_append( basename_list, " " );
- }
- tmp = g_shell_quote( ibname );
- g_string_append_printf( basename_list, "%s", tmp );
- g_free( tmp );
- }
-
- if( ipath ){
- if( strlen( pathname_list->str )){
- pathname_list = g_string_append( pathname_list, " " );
- }
- tmp = g_shell_quote( ipath );
- g_string_append_printf( pathname_list, "%s", tmp );
- g_free( tmp );
- }
-
- if( strlen( uris_list->str )){
- uris_list = g_string_append( uris_list, " " );
- }
- tmp = g_shell_quote( iuri );
- g_string_append_printf( uris_list, "%s", tmp );
- g_free( tmp );
-
- g_free( ibname );
- g_free( ipath );
- g_object_unref( iloc );
- g_free( iuri );
- }
-
- iter = na_object_get_parameters( profile );
- old_iter = iter;
-
- while(( iter = g_strstr_len( iter, strlen( iter ), "%" ))){
-
- string = g_string_append_len( string, old_iter, strlen( old_iter ) - strlen( iter ));
- switch( iter[1] ){
-
- /* base dir of the (first) selected item
- */
- case 'd':
- if( dirname ){
- tmp = g_shell_quote( dirname );
- string = g_string_append( string, tmp );
- g_free( tmp );
- }
- break;
-
- /* basename of the (first) selected item
- */
- case 'f':
- if( filename ){
- tmp = g_shell_quote( filename );
- string = g_string_append( string, tmp );
- g_free( tmp );
- }
- break;
-
- /* hostname of the (first) URI
- */
- case 'h':
- if( hostname ){
- string = g_string_append( string, hostname );
- }
- break;
-
- /* space-separated list of the basenames
- */
- case 'm':
- if( basename_list->str ){
- string = g_string_append( string, basename_list->str );
- }
- break;
-
- /* space-separated list of full pathnames
- */
- case 'M':
- if( pathname_list->str ){
- string = g_string_append( string, pathname_list->str );
- }
- break;
-
- /* port number of the (first) URI
- */
- case 'p':
- if( port_number > 0 ){
- g_string_append_printf( string, "%d", port_number );
- }
- break;
-
- /* list of URIs
- */
- case 'R':
- if( uris_list->str ){
- string = g_string_append( string, uris_list->str );
- }
- break;
-
- /* scheme of the (first) URI
- */
- case 's':
- if( scheme ){
- string = g_string_append( string, scheme );
- }
- break;
-
- /* URI of the first item
- */
- case 'u':
- if( uri ){
- string = g_string_append( string, uri );
- }
- break;
-
- /* username of the (first) URI
- */
- case 'U':
- if( username ){
- string = g_string_append( string, username );
- }
- break;
-
- /* a percent sign
- */
- case '%':
- string = g_string_append_c( string, '%' );
- break;
- }
-
- iter += 2; /* skip the % sign and the character after */
- old_iter = iter; /* store the new start of the string */
- }
-
- string = g_string_append_len( string, old_iter, strlen( old_iter ));
-
- g_free( uri );
- g_free( dirname );
- g_free( scheme );
- g_free( hostname );
- g_free( username );
- g_free( iter );
- g_string_free( uris_list, TRUE );
- g_string_free( basename_list, TRUE );
- g_string_free( pathname_list, TRUE );
-
- parsed = g_string_free( string, FALSE );
- return( parsed );
-}
diff --git a/src/core/na-tokens.c b/src/core/na-tokens.c
index 719c13f..4789596 100644
--- a/src/core/na-tokens.c
+++ b/src/core/na-tokens.c
@@ -35,6 +35,7 @@
#include <string.h>
#include <api/na-core-utils.h>
+#include <api/na-object-api.h>
#include "na-gnome-vfs-uri.h"
#include "na-selected-info.h"
@@ -74,11 +75,15 @@ struct NATokensPrivate {
static GObjectClass *st_parent_class = NULL;
-static GType register_type( void );
-static void class_init( NATokensClass *klass );
-static void instance_init( GTypeInstance *instance, gpointer klass );
-static void instance_dispose( GObject *object );
-static void instance_finalize( GObject *object );
+static GType register_type( void );
+static void class_init( NATokensClass *klass );
+static void instance_init( GTypeInstance *instance, gpointer klass );
+static void instance_dispose( GObject *object );
+static void instance_finalize( GObject *object );
+
+static void execute_action_command( const gchar *command, const NAObjectProfile *profile );
+static gboolean is_singular_exec( const NATokens *tokens, const gchar *exec );
+static gchar *parse_singular( const NATokens *tokens, const gchar *input, guint i, gboolean utf8 );
GType
na_tokens_get_type( void )
@@ -327,6 +332,123 @@ na_tokens_new_from_selection( GList *selection )
gchar *
na_tokens_parse_parameters( const NATokens *tokens, const gchar *input, gboolean utf8 )
{
+ return( parse_singular( tokens, input, 0, utf8 ));
+}
+
+/**
+ * na_tokens_execute_action:
+ * @tokens: a #NATokens object.
+ * @profile: the #NAObjectProfile to be executed.
+ *
+ * Execute the given action, regarding the context described by @tokens.
+ */
+void
+na_tokens_execute_action( const NATokens *tokens, const NAObjectProfile *profile )
+{
+ gchar *path, *parameters, *exec, *command;
+ gboolean singular;
+ guint i;
+
+ path = na_object_get_path( profile );
+ parameters = na_object_get_parameters( profile );
+ exec = g_strdup_printf( "%s %s", path, parameters );
+ g_free( parameters );
+ g_free( path );
+
+ singular = is_singular_exec( tokens, exec );
+
+ if( singular ){
+ for( i = 0 ; i < tokens->private->count ; ++i ){
+ command = parse_singular( tokens, exec, i, FALSE );
+ execute_action_command( command, profile );
+ g_free( command );
+ }
+
+ } else {
+ command = na_tokens_parse_parameters( tokens, exec, FALSE );
+ execute_action_command( command, profile );
+ g_free( command );
+ }
+
+
+ g_free( exec );
+}
+
+static void
+execute_action_command( const gchar *command, const NAObjectProfile *profile )
+{
+ static const gchar *thisfn = "nautilus_actions_execute_action_command";
+
+ g_debug( "%s: command=%s, profile=%p", thisfn, command, ( void * ) profile );
+
+ g_spawn_command_line_async( command, NULL );
+}
+
+/*
+ * na_tokens_is_singular_exec:
+ * @tokens: the current #NATokens object.
+ * @exec: the to be executed command-line before having been parsed
+ *
+ * Returns: %TRUE if the first parameter found in @exec command-line is
+ * of singular form, %FALSE else.
+ *
+ * %% and %c are considered here as singular parameters. This function
+ * so defaults to %TRUE as long as no plural form parameter is found.
+ */
+static gboolean
+is_singular_exec( const NATokens *tokens, const gchar *exec )
+{
+ gboolean singular;
+ gchar *found;
+
+ singular = TRUE;
+ found = g_strstr_len( exec, -1, "%" );
+
+ if( found ){
+ switch( found[1] ){
+ case 'b':
+ case 'c':
+ case 'd':
+ case 'f':
+ case 'h':
+ case 'n':
+ case 'p':
+ case 's':
+ case 'u':
+ case 'w':
+ case 'x':
+ case '%':
+ break;
+
+ case 'B':
+ case 'D':
+ case 'F':
+ case 'U':
+ case 'W':
+ case 'X':
+ singular = FALSE;
+ break;
+ }
+ }
+
+ return( singular );
+}
+
+/*
+ * na_tokens_parse_singular:
+ * @tokens: a #NATokens object.
+ * @input: the input string, may or may not contain tokens.
+ * @i: the number of the iteration in a multiple selection, starting with zero.
+ * @utf8: whether the @input string is UTF-8 encoded, or a standard ASCII
+ * string.
+ *
+ * A command is said of 'singular form' when its first parameter is not
+ * of plural form. In the case of a multiple selection, singular form
+ * commands are executed one time for each element of the selection
+ */
+static gchar *
+parse_singular( const NATokens *tokens, const gchar *input, guint i, gboolean utf8 )
+{
GString *output;
gchar *iter, *prev_iter, *tmp;
@@ -359,7 +481,7 @@ na_tokens_parse_parameters( const NATokens *tokens, const gchar *input, gboolean
switch( iter[1] ){
case 'b':
if( tokens->private->basenames ){
- tmp = g_shell_quote( tokens->private->basenames->data );
+ tmp = g_shell_quote( g_slist_nth_data( tokens->private->basenames, i ));
output = g_string_append( output, tmp );
g_free( tmp );
}
@@ -377,7 +499,7 @@ na_tokens_parse_parameters( const NATokens *tokens, const gchar *input, gboolean
case 'd':
if( tokens->private->basedirs ){
- tmp = g_shell_quote( tokens->private->basedirs->data );
+ tmp = g_shell_quote( g_slist_nth_data( tokens->private->basedirs, i ));
output = g_string_append( output, tmp );
g_free( tmp );
}
@@ -391,7 +513,7 @@ na_tokens_parse_parameters( const NATokens *tokens, const gchar *input, gboolean
case 'f':
if( tokens->private->filenames ){
- tmp = g_shell_quote( tokens->private->filenames->data );
+ tmp = g_shell_quote( g_slist_nth_data( tokens->private->filenames, i ));
output = g_string_append( output, tmp );
g_free( tmp );
}
@@ -433,7 +555,7 @@ na_tokens_parse_parameters( const NATokens *tokens, const gchar *input, gboolean
case 'u':
if( tokens->private->uris ){
- tmp = g_shell_quote( tokens->private->uris->data );
+ tmp = g_shell_quote( g_slist_nth_data( tokens->private->uris, i ));
output = g_string_append( output, tmp );
g_free( tmp );
}
@@ -447,7 +569,7 @@ na_tokens_parse_parameters( const NATokens *tokens, const gchar *input, gboolean
case 'w':
if( tokens->private->basenames_woext ){
- tmp = g_shell_quote( tokens->private->basenames_woext->data );
+ tmp = g_shell_quote( g_slist_nth_data( tokens->private->basenames_woext, i ));
output = g_string_append( output, tmp );
g_free( tmp );
}
@@ -461,7 +583,7 @@ na_tokens_parse_parameters( const NATokens *tokens, const gchar *input, gboolean
case 'x':
if( tokens->private->exts ){
- tmp = g_shell_quote( tokens->private->exts->data );
+ tmp = g_shell_quote( g_slist_nth_data( tokens->private->exts, i ));
output = g_string_append( output, tmp );
g_free( tmp );
}
diff --git a/src/core/na-tokens.h b/src/core/na-tokens.h
index 52eb198..802799f 100644
--- a/src/core/na-tokens.h
+++ b/src/core/na-tokens.h
@@ -42,18 +42,19 @@
* Note that until v2.30, tokens were parsed against selection list only
* when an item was selected in the Nautilus context menu (i.e. at
* execution time).
- * Starting with v2.32 (v3.0 ?), this same parsing may occur for each
- * displayed label (as new specs accept tokens in labels) - we so
+ * Starting with unstable v2.99 (stable v3.0), this same parsing may occur
+ * for each displayed label (as new specs accept tokens in labels) - we so
* factorize this parsing one time for each new selection in the Nautilus
* plugin, attaching the result to each item in the context menu.
*
* Adding a parameter requires updating of :
- * - nautilus-actions/core/na-object-profile.c::na_object_profile_parse_parameters()
+ * - src/core/na-tokens.c::na_tokens_is_singular_exec()
+ * - src/core/na-tokens.c::na_tokens_parse_parameters()
* - nautilus-actions/nact/nact-icommand-tab.c:parse_parameters()
- * - nautilus-actions/nact/nautilus-actions-config-tool.ui:LegendDialog
+ * - src/nact/nautilus-actions-config-tool.ui:LegendDialog
*/
-#include <glib-object.h>
+#include <api/na-object-profile.h>
G_BEGIN_DECLS
@@ -86,6 +87,8 @@ NATokens *na_tokens_new_from_selection( GList *selection );
gchar *na_tokens_parse_parameters( const NATokens *tokens, const gchar *string, gboolean utf8 );
+void na_tokens_execute_action ( const NATokens *tokens, const NAObjectProfile *profile );
+
G_END_DECLS
#endif /* __CORE_NA_TOKENS_H__ */
diff --git a/src/plugin-menu/nautilus-actions.c b/src/plugin-menu/nautilus-actions.c
index 02477e8..3868696 100644
--- a/src/plugin-menu/nautilus-actions.c
+++ b/src/plugin-menu/nautilus-actions.c
@@ -91,14 +91,14 @@ static GList *menu_provider_get_toolbar_items( NautilusMenuProvider *
static GList *get_menus_items( NautilusActions *plugin, guint target, GList *selection );
static GList *expand_tokens( GList *tree, NATokens *tokens );
static NAObjectItem *expand_tokens_item( NAObjectItem *item, NATokens *tokens );
+static void expand_tokens_context( NAIContext *context, NATokens *tokens );
static GList *build_nautilus_menus( NautilusActions *plugin, GList *tree, guint target, GList *files, NATokens *tokens );
static NAObjectProfile *get_candidate_profile( NautilusActions *plugin, NAObjectAction *action, guint target, GList *files );
-static NautilusMenuItem *create_item_from_profile( NAObjectProfile *profile, guint target, GList *files );
+static NautilusMenuItem *create_item_from_profile( NAObjectProfile *profile, guint target, GList *files, NATokens *tokens );
static NautilusMenuItem *create_item_from_menu( NAObjectMenu *menu, GList *subitems );
static NautilusMenuItem *create_menu_item( NAObjectItem *item );
static void attach_submenu_to_item( NautilusMenuItem *item, GList *subitems );
static void weak_notify_profile( NAObjectProfile *profile, NautilusMenuItem *item );
-static void destroy_notify_file_list( GList *list);
static void execute_action( NautilusMenuItem *item, NAObjectProfile *profile );
@@ -540,8 +540,15 @@ get_menus_items( NautilusActions *plugin, guint target, GList *selection )
}
/*
- * create a copy of the tree where all fields which may embed parameters
- * have been expanded
+ * create a copy of the tree where almost all fields which may embed
+ * parameters have been expanded
+ * here, 'almost' should be readen as:
+ * - all displayable fields, or fields which may have an impact on the display
+ * (e.g. label, tooltip, icon name)
+ * - all fields which we do not need later
+ *
+ * we keep until the last item activation the Exec key, whose first parameter
+ * actualy determines the form (singular or plural) of the execution..
*/
static GList *
expand_tokens( GList *pivot_tree, NATokens *tokens )
@@ -564,7 +571,11 @@ expand_tokens_item( NAObjectItem *item, NATokens *tokens )
gchar *old, *new;
GSList *subitems_slist, *its, *new_slist;
GList *subitems, *it, *new_list;
+ NAObjectItem *expanded_item;
+ /* label, tooltip and icon name
+ * plus the toolbar label if this is an action
+ */
old = na_object_get_label( item );
new = na_tokens_parse_parameters( tokens, old, TRUE );
na_object_set_label( item, new );
@@ -591,50 +602,110 @@ expand_tokens_item( NAObjectItem *item, NATokens *tokens )
g_free( new );
}
+ /* A NAObjectItem, whether it is an action or a menu, is also a NAIContext
+ */
+ expand_tokens_context( NA_ICONTEXT( item ), tokens );
+
+ /* subitems lists, whether this is the profiles list of an action
+ * or the items list of a menu, may be dynamic and embed a command;
+ * this command itself may embed parameters
+ */
subitems_slist = na_object_get_items_slist( item );
new_slist = NULL;
for( its = subitems_slist ; its ; its = its->next ){
old = ( gchar * ) its->data;
- new = na_tokens_parse_parameters( tokens, old, FALSE );
+ if( old[0] == '[' && old[strlen(old)-1] == ']' ){
+ new = na_tokens_parse_parameters( tokens, old, FALSE );
+ } else {
+ new = g_strdup( old );
+ }
new_slist = g_slist_prepend( new_slist, new );
}
na_object_set_items_slist( item, new_slist );
na_core_utils_slist_free( subitems_slist );
na_core_utils_slist_free( new_slist );
+ /* last, deal with subitems
+ */
subitems = na_object_get_items( item );
- new_list = NULL;
- for( it = subitems ; it ; it = it->next ){
- if( NA_IS_OBJECT_MENU( item )){
- expand_tokens_item( NA_OBJECT_ITEM( it->data ), tokens );
- } else {
- old = na_object_get_path( it->data );
- new = na_tokens_parse_parameters( tokens, old, FALSE );
- na_object_set_path( it->data, new );
- g_free( old );
- g_free( new );
+ if( NA_IS_OBJECT_MENU( item )){
+ new_list = NULL;
+
+ for( it = subitems ; it ; it = it->next ){
+ expanded_item = expand_tokens_item( NA_OBJECT_ITEM( it->data ), tokens );
+ new_list = g_list_prepend( new_list, expanded_item );
+ }
+
+ na_object_set_items( item, g_list_reverse( new_list ));
- old = na_object_get_parameters( it->data );
+ } else {
+ g_return_val_if_fail( NA_IS_OBJECT_ACTION( item ), NULL );
+
+ for( it = subitems ; it ; it = it->next ){
+
+ /* desktop Exec key = GConf path+parameters
+ * do not touch them here
+ */
+ old = na_object_get_working_dir( it->data );
new = na_tokens_parse_parameters( tokens, old, FALSE );
- na_object_set_parameters( it->data, new );
+ na_object_set_working_dir( it->data, new );
g_free( old );
g_free( new );
+
+ /* a NAObjectProfile is also a NAIContext
+ */
+ expand_tokens_context( NA_ICONTEXT( it->data ), tokens );
}
}
return( item );
}
+static void
+expand_tokens_context( NAIContext *context, NATokens *tokens )
+{
+ gchar *old, *new;
+
+ old = na_object_get_try_exec( context );
+ new = na_tokens_parse_parameters( tokens, old, FALSE );
+ na_object_set_try_exec( context, new );
+ g_free( old );
+ g_free( new );
+
+ old = na_object_get_show_if_registered( context );
+ new = na_tokens_parse_parameters( tokens, old, FALSE );
+ na_object_set_show_if_registered( context, new );
+ g_free( old );
+ g_free( new );
+
+ old = na_object_get_show_if_true( context );
+ new = na_tokens_parse_parameters( tokens, old, FALSE );
+ na_object_set_show_if_true( context, new );
+ g_free( old );
+ g_free( new );
+
+ old = na_object_get_show_if_running( context );
+ new = na_tokens_parse_parameters( tokens, old, FALSE );
+ na_object_set_show_if_running( context, new );
+ g_free( old );
+ g_free( new );
+}
+
/*
- * when building a menu for the toolbar, do not use menus hierarchy
- * files is a GList of NASelectedInfo items
+ * @plugin: this #NautilusActions module instance.
+ * @tree: a copy of the #NAPivot tree, where all fields - but
+ * displayable parameters expanded
+ * @target: whether we target location or context menu, or toolbar.
+ * @files: the current selection in the file-manager, as a #GList of #NASelectedInfo items
+ * @tokens: a #NATokens object which embeds all possible values, regarding the
+ * current selection, for all parameters
+ *
+ * When building a menu for the toolbar, do not use menus hierarchy
*
- * TODO: menus, actions and profiles may embed parameters in their data.
- * This mainly means that the objects have to be re-parsed for each new
- * selection (e.g. because a label may change if it depends of the current
- * selection). Thus, all the hierarchy must be recursively re-parsed, and
- * should be re-checked for validity !
+ * As menus, actions and profiles may embed parameters in their data,
+ * all the hierarchy must be recursively re-parsed, and should be
+ * re-checked for validity !
*/
static GList *
build_nautilus_menus( NautilusActions *plugin, GList *tree, guint target, GList *files, NATokens *tokens )
@@ -658,7 +729,7 @@ build_nautilus_menus( NautilusActions *plugin, GList *tree, guint target, GList
/* check this here as a security though NAPivot should only have
* loaded valid and enabled items
*/
- if( !na_object_is_enabled( it->data ) || !na_object_is_valid( it->data )){
+ if( !na_object_is_enabled( it->data )){
gchar *label = na_object_get_label( it->data );
g_warning( "%s: '%s' item: enabled=%s, valid=%s", thisfn, label,
na_object_is_enabled( it->data ) ? "True":"False",
@@ -668,6 +739,13 @@ build_nautilus_menus( NautilusActions *plugin, GList *tree, guint target, GList
}
#endif
+ /* but we have to re-check for validity as a label may become
+ * dynamically empty - thus the NAObjectItem invalid :(
+ */
+ if( !na_object_is_valid( it->data )){
+ continue;
+ }
+
if( !na_icontext_is_candidate( NA_ICONTEXT( it->data ), target, files )){
continue;
}
@@ -680,12 +758,12 @@ build_nautilus_menus( NautilusActions *plugin, GList *tree, guint target, GList
/*g_debug( "%s: submenu has %d items", thisfn, g_list_length( submenu ));*/
if( submenu ){
- if( target != ITEM_TARGET_TOOLBAR ){
- item = create_item_from_menu( NA_OBJECT_MENU( it->data ), submenu );
- menus_list = g_list_append( menus_list, item );
+ if( target == ITEM_TARGET_TOOLBAR ){
+ menus_list = g_list_concat( menus_list, submenu );
} else {
- menus_list = g_list_concat( menus_list, submenu );
+ item = create_item_from_menu( NA_OBJECT_MENU( it->data ), submenu );
+ menus_list = g_list_append( menus_list, item );
}
}
continue;
@@ -695,7 +773,7 @@ build_nautilus_menus( NautilusActions *plugin, GList *tree, guint target, GList
profile = get_candidate_profile( plugin, NA_OBJECT_ACTION( it->data ), target, files );
if( profile ){
- item = create_item_from_profile( profile, target, files );
+ item = create_item_from_profile( profile, target, files, tokens );
menus_list = g_list_append( menus_list, item );
}
}
@@ -736,7 +814,7 @@ get_candidate_profile( NautilusActions *plugin, NAObjectAction *action, guint ta
}
static NautilusMenuItem *
-create_item_from_profile( NAObjectProfile *profile, guint target, GList *files )
+create_item_from_profile( NAObjectProfile *profile, guint target, GList *files, NATokens *tokens )
{
NautilusMenuItem *item;
NAObjectAction *action;
@@ -759,30 +837,23 @@ create_item_from_profile( NAObjectProfile *profile, guint target, GList *files )
g_object_weak_ref( G_OBJECT( item ), ( GWeakNotify ) weak_notify_profile, duplicate );
g_object_set_data_full( G_OBJECT( item ),
- "nautilus-actions-files",
- na_selected_info_copy_list( files ),
- ( GDestroyNotify ) destroy_notify_file_list );
-
- g_object_set_data( G_OBJECT( item ),
- "nautilus-actions-target",
- GUINT_TO_POINTER( target ));
+ "nautilus-actions-tokens",
+ g_object_ref( tokens ),
+ ( GDestroyNotify ) g_object_unref );
return( item );
}
+/*
+ * called _after_ the NautilusMenuItem has been finalized
+ */
static void
weak_notify_profile( NAObjectProfile *profile, NautilusMenuItem *item )
{
g_debug( "nautilus_actions_weak_notify_profile: profile=%p (ref_count=%d)",
( void * ) profile, G_OBJECT( profile )->ref_count );
- g_object_unref( profile );
-}
-static void
-destroy_notify_file_list( GList *list)
-{
- g_debug( "nautilus_actions_destroy_notify_file_list" );
- na_selected_info_free_list( list );
+ g_object_unref( profile );
}
/*
@@ -842,35 +913,24 @@ attach_submenu_to_item( NautilusMenuItem *item, GList *subitems )
}
}
+/*
+ * callback triggered when an item is activated
+ * path and parameters must yet been parsed against tokens
+ *
+ * note that if first parameter if of singular form, then we have to loop
+ * againt the selected, each time replacing the singular parameters with
+ * the current item of the selection
+ */
static void
execute_action( NautilusMenuItem *item, NAObjectProfile *profile )
{
static const gchar *thisfn = "nautilus_actions_execute_action";
- GList *files;
- GString *cmd;
- gchar *param, *path;
- guint target;
+ NATokens *tokens;
g_debug( "%s: item=%p, profile=%p", thisfn, ( void * ) item, ( void * ) profile );
- files = ( GList * ) g_object_get_data( G_OBJECT( item ), "nautilus-actions-files" );
- target = GPOINTER_TO_UINT( g_object_get_data( G_OBJECT( item ), "nautilus-actions-target" ));
-
- path = na_object_get_path( profile );
- cmd = g_string_new( path );
-
- param = na_object_profile_parse_parameters( profile, target, files );
-
- if( param != NULL ){
- g_string_append_printf( cmd, " %s", param );
- g_free( param );
- }
-
- g_debug( "%s: executing '%s'", thisfn, cmd->str );
- g_spawn_command_line_async( cmd->str, NULL );
-
- g_string_free (cmd, TRUE);
- g_free( path );
+ tokens = NA_TOKENS( g_object_get_data( G_OBJECT( item ), "nautilus-actions-tokens" ));
+ na_tokens_execute_action( tokens, profile );
}
/*
diff --git a/src/utils/nautilus-actions-run.c b/src/utils/nautilus-actions-run.c
index 68d15e8..fa04404 100644
--- a/src/utils/nautilus-actions-run.c
+++ b/src/utils/nautilus-actions-run.c
@@ -43,6 +43,7 @@
#include <core/na-pivot.h>
#include <core/na-selected-info.h>
+#include <core/na-tokens.h>
#include <plugin-tracker/na-tracker.h>
#include <plugin-tracker/na-tracker-dbus.h>
@@ -78,7 +79,6 @@ static GList *get_selection_from_strv( const gchar **strv, gboolean ha
static NAObjectProfile *get_profile_for_targets( NAObjectAction *action, GList *targets );
static void execute_action( NAObjectAction *action, NAObjectProfile *profile, GList *targets );
static void dump_targets( GList *targets );
-static void free_targets( GList *targets );
static void exit_with_usage( void );
int
@@ -152,7 +152,7 @@ main( int argc, char** argv )
exit( status );
}
- if( !na_object_action_is_candidate( action, ITEM_TARGET_SELECTION, targets )){
+ if( !na_icontext_is_candidate( NA_ICONTEXT( action ), ITEM_TARGET_SELECTION, targets )){
g_printerr( _( "Action %s is not a valid candidate. Exiting.\n" ), id );
exit( status );
}
@@ -166,7 +166,7 @@ main( int argc, char** argv )
execute_action( action, profile, targets );
- free_targets( targets );
+ na_selected_info_free_list( targets );
exit( status );
}
@@ -367,8 +367,8 @@ get_profile_for_targets( NAObjectAction *action, GList *targets )
candidate = NULL;
profiles = na_object_get_items( action );
- for( ip = profiles ; ip && !candidate ; ip = ip->next ){
+ for( ip = profiles ; ip && !candidate ; ip = ip->next ){
if( na_icontext_is_candidate( NA_ICONTEXT( ip->data ), ITEM_TARGET_SELECTION, targets )){
candidate = NA_OBJECT_PROFILE( ip->data );
}
@@ -380,25 +380,11 @@ get_profile_for_targets( NAObjectAction *action, GList *targets )
static void
execute_action( NAObjectAction *action, NAObjectProfile *profile, GList *targets )
{
- static const gchar *thisfn = "nautilus_action_run_execute_action";
- GString *cmd;
- gchar *param, *path;
-
- path = na_object_get_path( profile );
- cmd = g_string_new( path );
-
- param = na_object_profile_parse_parameters( profile, ITEM_TARGET_SELECTION, targets );
-
- if( param != NULL ){
- g_string_append_printf( cmd, " %s", param );
- g_free( param );
- }
-
- g_debug( "%s: executing '%s'", thisfn, cmd->str );
- g_spawn_command_line_async( cmd->str, NULL );
+ /*static const gchar *thisfn = "nautilus_action_run_execute_action";*/
+ NATokens *tokens;
- g_string_free (cmd, TRUE);
- g_free( path );
+ tokens = na_tokens_new_from_selection( targets );
+ na_tokens_execute_action( tokens, profile );
}
/*
@@ -421,16 +407,6 @@ dump_targets( GList *targets )
}
/*
- *
- */
-static void
-free_targets( GList *targets )
-{
- g_list_foreach( targets, ( GFunc ) g_object_unref, NULL );
- g_list_free( targets );
-}
-
-/*
* print a help message and exit with failure
*/
static void
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]