[nautilus-actions] Expand NAObject fields which may embed parameters
- From: Pierre Wieser <pwieser src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [nautilus-actions] Expand NAObject fields which may embed parameters
- Date: Thu, 10 Jun 2010 22:35:20 +0000 (UTC)
commit 9c5f2ed407f00a596055e27c459d275ae6e0e04b
Author: Pierre Wieser <pwieser trychlos org>
Date: Wed May 26 22:06:03 2010 +0200
Expand NAObject fields which may embed parameters
ChangeLog | 14 +
TODO | 5 +
src/api/na-core-utils.h | 1 +
src/core/Makefile.am | 2 +
src/core/na-core-utils.c | 47 ++++-
src/core/na-tokens.c | 484 ++++++++++++++++++++++++++++++++++++
src/core/na-tokens.h | 91 +++++++
src/plugin-menu/nautilus-actions.c | 146 +++++++++--
8 files changed, 766 insertions(+), 24 deletions(-)
---
diff --git a/ChangeLog b/ChangeLog
index 99b0d25..d298a2e 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -6,6 +6,20 @@
* src/core/na-iabout.c: Update copyright notice.
+2010-05-26 Pierre Wieser <pwieser trychlos org>
+
+ * src/api/na-core-utils.h:
+ * src/core/na-core-utils.c (na_core_utils_dir_split_ext):
+ New function.
+
+ * src/core/na-tokens.h:
+ * src/core/na-tokens.c: New files.
+
+ * src/core/Makefile.am: Udated accordingly.
+
+ * src/plugin-menu/nautilus-actions.c:
+ Expand tokens which may embed parameters.
+
2010-05-20 Pierre Wieser <pwieser trychlos org>
* src/io-gconf/nagp-reader.c (read_done_profile_attach_profile):
diff --git a/TODO b/TODO
index 4a82554..44894a5 100644
--- a/TODO
+++ b/TODO
@@ -454,3 +454,8 @@ Parameter Description
%x (first) extension
%X space-separated list of extensions
%% the « % » character
+
+- an item may become invalid at runtime
+ e.g. when the label contains only a list of extension (%X)
+ but selected files do not have extension - most likely, there should be other examples..
+ => label must be expanded and checked and kept before testing for candidate
diff --git a/src/api/na-core-utils.h b/src/api/na-core-utils.h
index 9964b66..bb15faa 100644
--- a/src/api/na-core-utils.h
+++ b/src/api/na-core-utils.h
@@ -76,6 +76,7 @@ gchar *na_core_utils_gstring_joinv( const gchar *start, const gchar *separator
*/
gboolean na_core_utils_dir_is_writable_path( const gchar *path );
gboolean na_core_utils_dir_is_writable_uri( const gchar *uri );
+void na_core_utils_dir_split_ext( const gchar *string, gchar **first, gchar **ext );
/* file management
*/
diff --git a/src/core/Makefile.am b/src/core/Makefile.am
index 94125b7..3abe580 100644
--- a/src/core/Makefile.am
+++ b/src/core/Makefile.am
@@ -96,6 +96,8 @@ libna_core_la_SOURCES = \
na-selected-info.h \
na-updater.c \
na-updater.h \
+ na-tokens.c \
+ na-tokens.h \
$(NULL)
libna_core_la_LIBADD = \
diff --git a/src/core/na-core-utils.c b/src/core/na-core-utils.c
index 4ab06ad..37e49b7 100644
--- a/src/core/na-core-utils.c
+++ b/src/core/na-core-utils.c
@@ -327,7 +327,10 @@ na_core_utils_slist_join_at_end( GSList *slist, const gchar *link )
str = g_string_new( "" );
for( is = slist ; is ; is = is->next ){
- g_string_append_printf( str, "%s%s", ( const gchar * ) is->data, link );
+ if( str->len ){
+ g_string_append_printf( str, "%s", link );
+ }
+ g_string_append_printf( str, "%s", ( const gchar * ) is->data );
}
return( g_string_free( str, FALSE ));
@@ -672,6 +675,48 @@ info_dir_is_writable( GFile *file, const gchar *path_or_uri )
}
/**
+ * na_core_utils_dir_split_ext:
+ * @string: the input path or URI to be splitted.
+ * @first: a pointer to a buffer which will contain the first part of the split.
+ * @ext: a pointer to a buffer which will contain the extension part of the path.
+ *
+ * Split the given @string, returning the first part and the extension in newly
+ * allocated buffers which should be g_free() by the caller.
+ *
+ * Returns an empty string as extension if no extension is detected.
+ */
+void
+na_core_utils_dir_split_ext( const gchar *string, gchar **first, gchar **ext )
+{
+ gchar *dupped;
+ gchar **array, **iter;
+
+ dupped = g_strreverse( g_strdup( string ));
+ array = g_strsplit( dupped, ".", 2 );
+
+ if( g_strv_length( array ) == 1 ){
+ if( ext ){
+ *ext = g_strdup( "" );
+ }
+ if( first ){
+ *first = g_strreverse( g_strdup(( const gchar * ) *array ));
+ }
+ } else {
+ if( ext ){
+ *ext = g_strreverse( g_strdup(( const gchar * ) *array ));
+ }
+ iter = array;
+ ++iter;
+ if( first ){
+ *first = g_strreverse( g_strdup(( const gchar * ) *iter ));
+ }
+ }
+
+ g_strfreev( array );
+ g_free( dupped );
+}
+
+/**
* na_core_utils_file_delete:
* @path: the path of the file to be deleted.
*
diff --git a/src/core/na-tokens.c b/src/core/na-tokens.c
new file mode 100644
index 0000000..54c44df
--- /dev/null
+++ b/src/core/na-tokens.c
@@ -0,0 +1,484 @@
+/*
+ * Nautilus Actions
+ * A Nautilus extension which offers configurable context menu actions.
+ *
+ * Copyright (C) 2005 The GNOME Foundation
+ * Copyright (C) 2006, 2007, 2008 Frederic Ruaudel and others (see AUTHORS)
+ * Copyright (C) 2009, 2010 Pierre Wieser and others (see AUTHORS)
+ *
+ * This Program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this Library; see the file COPYING. If not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place,
+ * Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Authors:
+ * Frederic Ruaudel <grumz grumz net>
+ * Rodrigo Moya <rodrigo gnome-db org>
+ * Pierre Wieser <pwieser trychlos org>
+ * ... and many others (see AUTHORS)
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+
+#include <api/na-core-utils.h>
+
+#include "na-gnome-vfs-uri.h"
+#include "na-selected-info.h"
+#include "na-tokens.h"
+
+/* private class data
+ */
+struct NATokensClassPrivate {
+ void *empty; /* so that gcc -pedantic is happy */
+};
+
+/* private instance data
+ */
+struct NATokensPrivate {
+ gboolean dispose_has_run;
+
+ guint count;
+
+ GSList *uris;
+ gchar *uris_str;
+ GSList *filenames;
+ gchar *filenames_str;
+ GSList *basedirs;
+ gchar *basedirs_str;
+ GSList *basenames;
+ gchar *basenames_str;
+ GSList *basenames_woext;
+ gchar *basenames_woext_str;
+ GSList *exts;
+ gchar *exts_str;
+
+ gchar *hostname;
+ gchar *username;
+ guint port;
+ gchar *scheme;
+};
+
+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 );
+
+GType
+na_tokens_get_type( void )
+{
+ static GType object_type = 0;
+
+ if( !object_type ){
+ object_type = register_type();
+ }
+
+ return( object_type );
+}
+
+static GType
+register_type( void )
+{
+ static const gchar *thisfn = "na_tokens_register_type";
+ GType type;
+
+ static GTypeInfo info = {
+ sizeof( NATokensClass ),
+ ( GBaseInitFunc ) NULL,
+ ( GBaseFinalizeFunc ) NULL,
+ ( GClassInitFunc ) class_init,
+ NULL,
+ NULL,
+ sizeof( NATokens ),
+ 0,
+ ( GInstanceInitFunc ) instance_init
+ };
+
+ g_debug( "%s", thisfn );
+
+ type = g_type_register_static( G_TYPE_OBJECT, "NATokens", &info, 0 );
+
+ return( type );
+}
+
+static void
+class_init( NATokensClass *klass )
+{
+ static const gchar *thisfn = "na_tokens_class_init";
+ GObjectClass *object_class;
+
+ g_debug( "%s: klass=%p", thisfn, ( void * ) klass );
+
+ st_parent_class = g_type_class_peek_parent( klass );
+
+ object_class = G_OBJECT_CLASS( klass );
+ object_class->dispose = instance_dispose;
+ object_class->finalize = instance_finalize;
+
+ klass->private = g_new0( NATokensClassPrivate, 1 );
+}
+
+static void
+instance_init( GTypeInstance *instance, gpointer klass )
+{
+ static const gchar *thisfn = "na_tokens_instance_init";
+ NATokens *self;
+
+ g_debug( "%s: instance=%p (%s), klass=%p",
+ thisfn, ( void * ) instance, G_OBJECT_TYPE_NAME( instance ), ( void * ) klass );
+ g_return_if_fail( NA_IS_TOKENS( instance ));
+ self = NA_TOKENS( instance );
+
+ self->private = g_new0( NATokensPrivate, 1 );
+
+ self->private->uris = NULL;
+ self->private->uris_str = NULL;
+ self->private->filenames = NULL;
+ self->private->filenames_str = NULL;
+ self->private->basedirs = NULL;
+ self->private->basedirs_str = NULL;
+ self->private->basenames = NULL;
+ self->private->basenames_str = NULL;
+ self->private->basenames_woext = NULL;
+ self->private->basenames_woext_str = NULL;
+ self->private->exts = NULL;
+ self->private->exts_str = NULL;
+
+ self->private->hostname = NULL;
+ self->private->username = NULL;
+ self->private->port = 0;
+ self->private->scheme = NULL;
+
+ self->private->dispose_has_run = FALSE;
+}
+
+static void
+instance_dispose( GObject *object )
+{
+ static const gchar *thisfn = "na_tokens_instance_dispose";
+ NATokens *self;
+
+ g_debug( "%s: object=%p (%s)", thisfn, ( void * ) object, G_OBJECT_TYPE_NAME( object ));
+ g_return_if_fail( NA_IS_TOKENS( object ));
+ self = NA_TOKENS( object );
+
+ if( !self->private->dispose_has_run ){
+
+ self->private->dispose_has_run = TRUE;
+
+ if( G_OBJECT_CLASS( st_parent_class )->dispose ){
+ G_OBJECT_CLASS( st_parent_class )->dispose( object );
+ }
+ }
+}
+
+static void
+instance_finalize( GObject *object )
+{
+ static const gchar *thisfn = "na_tokens_instance_finalize";
+ NATokens *self;
+
+ g_debug( "%s: object=%p", thisfn, ( void * ) object );
+ g_return_if_fail( NA_IS_TOKENS( object ));
+ self = NA_TOKENS( object );
+
+ g_free( self->private->scheme );
+ g_free( self->private->username );
+ g_free( self->private->hostname );
+
+ g_free( self->private->exts_str );
+ na_core_utils_slist_free( self->private->exts );
+ g_free( self->private->basenames_woext_str );
+ na_core_utils_slist_free( self->private->basenames_woext );
+ g_free( self->private->basenames_str );
+ na_core_utils_slist_free( self->private->basenames );
+ g_free( self->private->basedirs_str );
+ na_core_utils_slist_free( self->private->basedirs );
+ g_free( self->private->filenames_str );
+ na_core_utils_slist_free( self->private->filenames );
+ g_free( self->private->uris_str );
+ na_core_utils_slist_free( self->private->uris );
+
+ g_free( self->private );
+
+ /* chain call to parent class */
+ if( G_OBJECT_CLASS( st_parent_class )->finalize ){
+ G_OBJECT_CLASS( st_parent_class )->finalize( object );
+ }
+}
+
+/**
+ * na_tokens_new_from_selection:
+ * @selection: a #GList list of #NASelectedInfo objects.
+ *
+ * Returns: a new #NATokens object which holds all possible tokens.
+ */
+NATokens *
+na_tokens_new_from_selection( GList *selection )
+{
+ NATokens *tokens;
+ GList *it;
+ gchar *uri, *filename, *basedir, *basename, *bname_woext, *ext;
+ GFile *location;
+ gboolean first;
+ NAGnomeVFSURI *vfs;
+
+ first = TRUE;
+ tokens = g_object_new( NA_TOKENS_TYPE, NULL );
+
+ tokens->private->count = g_list_length( selection );
+
+ for( it = selection ; it ; it = it->next ){
+ location = na_selected_info_get_location( NA_SELECTED_INFO( it->data ));
+
+ uri = na_selected_info_get_uri( NA_SELECTED_INFO( it->data ));
+ filename = g_file_get_path( location );
+ basedir = g_path_get_dirname( filename );
+ basename = g_file_get_basename( location );
+ na_core_utils_dir_split_ext( basename, &bname_woext, &ext );
+
+ if( first ){
+ vfs = g_new0( NAGnomeVFSURI, 1 );
+ na_gnome_vfs_uri_parse( vfs, uri );
+
+ tokens->private->hostname = g_strdup( vfs->host_name );
+ tokens->private->username = g_strdup( vfs->user_name );
+ tokens->private->port = vfs->host_port;
+ tokens->private->scheme = g_strdup( vfs->scheme );
+
+ na_gnome_vfs_uri_free( vfs );
+ first = FALSE;
+ }
+
+ tokens->private->uris = g_slist_prepend( tokens->private->uris, uri );
+ tokens->private->filenames = g_slist_prepend( tokens->private->filenames, filename );
+ tokens->private->basedirs = g_slist_prepend( tokens->private->basedirs, basedir );
+ tokens->private->basenames = g_slist_prepend( tokens->private->basenames, basename );
+ tokens->private->basenames_woext = g_slist_prepend( tokens->private->basenames_woext, bname_woext );
+ tokens->private->exts = g_slist_prepend( tokens->private->exts, ext );
+
+ g_object_unref( location );
+ }
+
+ tokens->private->uris_str = na_core_utils_slist_join_at_end( tokens->private->uris, " " );
+ tokens->private->filenames_str = na_core_utils_slist_join_at_end( tokens->private->filenames, " " );
+ tokens->private->basedirs_str = na_core_utils_slist_join_at_end( tokens->private->basedirs, " " );
+ tokens->private->basenames_str = na_core_utils_slist_join_at_end( tokens->private->basenames, " " );
+ tokens->private->basenames_woext_str = na_core_utils_slist_join_at_end( tokens->private->basenames_woext, " " );
+ tokens->private->exts_str = na_core_utils_slist_join_at_end( tokens->private->exts, " " );
+
+ return( tokens );
+}
+
+/**
+ * na_tokens_parse_parameters:
+ * @tokens: a #NATokens object.
+ * @input: the input string, may or may not contain tokens.
+ * @utf8: whether the @input string is UTF-8 encoded, or a standard ASCII string.
+ *
+ * Expands the parameters in the given string.
+ *
+ * Valid parameters are :
+ *
+ * %b: (first) basename
+ * %B: space-separated list of basenames
+ * %c: count of selected items
+ * %d: (first) base directory
+ * %D: space-separated list of base directory of each selected items
+ * %f: (first) file name
+ * %F: space-separated list of selected file names
+ * %h: hostname of the (first) URI
+ * %n: username of the (first) URI
+ * %p: port number of the (first) URI
+ * %s: scheme of the (first) URI
+ * %u: (first) URI
+ * %U: space-separated list of selected URIs
+ * %w: (first) basename without the extension
+ * %W: space-separated list of basenames without their extension
+ * %x: (first) extension
+ * %X: space-separated list of extensions
+ * %%: the « % » character
+ *
+ * Returns: a copy of @input string with tokens expanded, as a newly
+ * allocated string which should be g_free() by the caller.
+ */
+gchar *
+na_tokens_parse_parameters( const NATokens *tokens, const gchar *input, gboolean utf8 )
+{
+ GString *output;
+ gchar *iter, *prev_iter, *tmp;
+
+ output = g_string_new( "" );
+
+ /* return NULL if input is NULL
+ */
+ if( !input ){
+ return( g_string_free( output, TRUE ));
+ }
+
+ /* return an empty string if input is empty
+ */
+ if( utf8 ){
+ if( !g_utf8_strlen( input, -1 )){
+ return( g_string_free( output, FALSE ));
+ }
+ } else {
+ if( !strlen( input )){
+ return( g_string_free( output, FALSE ));
+ }
+ }
+
+ iter = ( gchar * ) input;
+ prev_iter = iter;
+
+ while(( iter = g_strstr_len( iter, -1, "%" ))){
+ output = g_string_append_len( output, prev_iter, strlen( prev_iter ) - strlen( iter ));
+
+ switch( iter[1] ){
+ case 'b':
+ if( tokens->private->basenames ){
+ tmp = g_shell_quote( tokens->private->basenames->data );
+ output = g_string_append( output, tmp );
+ g_free( tmp );
+ }
+ break;
+
+ case 'B':
+ if( tokens->private->basenames ){
+ output = g_string_append( output, tokens->private->basenames_str );
+ }
+ break;
+
+ case 'c':
+ g_string_append_printf( output, "%d", tokens->private->count );
+ break;
+
+ case 'd':
+ if( tokens->private->basedirs ){
+ tmp = g_shell_quote( tokens->private->basedirs->data );
+ output = g_string_append( output, tmp );
+ g_free( tmp );
+ }
+ break;
+
+ case 'D':
+ if( tokens->private->basedirs ){
+ output = g_string_append( output, tokens->private->basedirs_str );
+ }
+ break;
+
+ case 'f':
+ if( tokens->private->filenames ){
+ tmp = g_shell_quote( tokens->private->filenames->data );
+ output = g_string_append( output, tmp );
+ g_free( tmp );
+ }
+ break;
+
+ case 'F':
+ if( tokens->private->filenames ){
+ output = g_string_append( output, tokens->private->filenames_str );
+ }
+ break;
+
+ case 'h':
+ if( tokens->private->hostname ){
+ tmp = g_shell_quote( tokens->private->hostname );
+ output = g_string_append( output, tmp );
+ g_free( tmp );
+ }
+ break;
+
+ case 'n':
+ if( tokens->private->username ){
+ tmp = g_shell_quote( tokens->private->username );
+ output = g_string_append( output, tmp );
+ g_free( tmp );
+ }
+ break;
+
+ case 'p':
+ g_string_append_printf( output, "%d", tokens->private->port );
+ break;
+
+ case 's':
+ if( tokens->private->scheme ){
+ tmp = g_shell_quote( tokens->private->scheme );
+ output = g_string_append( output, tmp );
+ g_free( tmp );
+ }
+ break;
+
+ case 'u':
+ if( tokens->private->uris ){
+ tmp = g_shell_quote( tokens->private->uris->data );
+ output = g_string_append( output, tmp );
+ g_free( tmp );
+ }
+ break;
+
+ case 'U':
+ if( tokens->private->uris ){
+ output = g_string_append( output, tokens->private->uris_str );
+ }
+ break;
+
+ case 'w':
+ if( tokens->private->basenames_woext ){
+ tmp = g_shell_quote( tokens->private->basenames_woext->data );
+ output = g_string_append( output, tmp );
+ g_free( tmp );
+ }
+ break;
+
+ case 'W':
+ if( tokens->private->basenames_woext ){
+ output = g_string_append( output, tokens->private->basenames_woext_str );
+ }
+ break;
+
+ case 'x':
+ if( tokens->private->exts ){
+ tmp = g_shell_quote( tokens->private->exts->data );
+ output = g_string_append( output, tmp );
+ g_free( tmp );
+ }
+ break;
+
+ case 'X':
+ if( tokens->private->exts ){
+ output = g_string_append( output, tokens->private->exts_str );
+ }
+ break;
+
+ /* a percent sign
+ */
+ case '%':
+ output = g_string_append_c( output, '%' );
+ break;
+ }
+
+ iter += 2; /* skip the % sign and the character after */
+ prev_iter = iter; /* store the new start of the string */
+ }
+
+ output = g_string_append_len( output, prev_iter, strlen( prev_iter ));
+
+ return( g_string_free( output, FALSE ));
+}
diff --git a/src/core/na-tokens.h b/src/core/na-tokens.h
new file mode 100644
index 0000000..c54bf99
--- /dev/null
+++ b/src/core/na-tokens.h
@@ -0,0 +1,91 @@
+/*
+ * Nautilus Actions
+ * A Nautilus extension which offers configurable context menu modules.
+ *
+ * Copyright (C) 2005 The GNOME Foundation
+ * Copyright (C) 2006, 2007, 2008 Frederic Ruaudel and others (see AUTHORS)
+ * Copyright (C) 2009, 2010 Pierre Wieser and others (see AUTHORS)
+ *
+ * This Program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this Library; see the file COPYING. If not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place,
+ * Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Authors:
+ * Frederic Ruaudel <grumz grumz net>
+ * Rodrigo Moya <rodrigo gnome-db org>
+ * Pierre Wieser <pwieser trychlos org>
+ * ... and many others (see AUTHORS)
+ */
+
+#ifndef __CORE_NA_TOKENS_H__
+#define __CORE_NA_TOKENS_H__
+
+/**
+ * SECTION: na_tokens
+ * @short_description: #NATokens class definition.
+ * @include: core/na-tokens.h
+ *
+ * The #NATokens class manages the tokens which are to be replaced with
+ * elements of the current selection at runtime.
+ *
+ * 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 tokenss 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()
+ * - nautilus-actions/nact/nact-icommand-tab.c:parse_parameters()
+ * - nautilus-actions/nact/nautilus-actions-config-tool.ui:LegendDialog
+ */
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define NA_TOKENS_TYPE ( na_tokens_get_type())
+#define NA_TOKENS( object ) ( G_TYPE_CHECK_INSTANCE_CAST( object, NA_TOKENS_TYPE, NATokens ))
+#define NA_TOKENS_CLASS( klass ) ( G_TYPE_CHECK_CLASS_CAST( klass, NA_TOKENS_TYPE, NATokensClass ))
+#define NA_IS_TOKENS( object ) ( G_TYPE_CHECK_INSTANCE_TYPE( object, NA_TOKENS_TYPE ))
+#define NA_IS_TOKENS_CLASS( klass ) ( G_TYPE_CHECK_CLASS_TYPE(( klass ), NA_TOKENS_TYPE ))
+#define NA_TOKENS_GET_CLASS( object ) ( G_TYPE_INSTANCE_GET_CLASS(( object ), NA_TOKENS_TYPE, NATokensClass ))
+
+typedef struct NATokensPrivate NATokensPrivate;
+
+typedef struct {
+ GObject parent;
+ NATokensPrivate *private;
+}
+ NATokens;
+
+typedef struct NATokensClassPrivate NATokensClassPrivate;
+
+typedef struct {
+ GObjectClass parent;
+ NATokensClassPrivate *private;
+}
+ NATokensClass;
+
+GType na_tokens_get_type( void );
+
+NATokens *na_tokens_new_from_selection( GList *selection );
+
+gchar *na_tokens_parse_parameters( const NATokens *tokens, const gchar *string, gboolean utf8 );
+
+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 5e1bccc..e1c3048 100644
--- a/src/plugin-menu/nautilus-actions.c
+++ b/src/plugin-menu/nautilus-actions.c
@@ -40,6 +40,7 @@
#include <libnautilus-extension/nautilus-file-info.h>
#include <libnautilus-extension/nautilus-menu-provider.h>
+#include <api/na-core-utils.h>
#include <api/na-object-api.h>
#include <core/na-pivot.h>
@@ -47,6 +48,7 @@
#include <core/na-iprefs.h>
#include <core/na-ipivot-consumer.h>
#include <core/na-selected-info.h>
+#include <core/na-tokens.h>
#include "nautilus-actions.h"
@@ -86,8 +88,10 @@ static GList *menu_provider_get_background_items( NautilusMenuProvide
static GList *menu_provider_get_file_items( NautilusMenuProvider *provider, GtkWidget *window, GList *files );
static GList *menu_provider_get_toolbar_items( NautilusMenuProvider *provider, GtkWidget *window, NautilusFileInfo *current_folder );
-static GList *get_file_or_background_items( NautilusActions *plugin, guint target, GList *selection );
-static GList *build_nautilus_menus( NautilusActions *plugin, GList *tree, guint target, GList *files );
+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 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_menu( NAObjectMenu *menu, GList *subitems );
@@ -417,8 +421,7 @@ menu_provider_get_background_items( NautilusMenuProvider *provider, GtkWidget *w
selected = na_selected_info_get_list_from_item( current_folder );
- nautilus_menus_list = get_file_or_background_items(
- NAUTILUS_ACTIONS( provider ), ITEM_TARGET_LOCATION, selected );
+ nautilus_menus_list = get_menus_items( NAUTILUS_ACTIONS( provider ), ITEM_TARGET_LOCATION, selected );
na_selected_info_free_list( selected );
}
@@ -453,8 +456,7 @@ menu_provider_get_file_items( NautilusMenuProvider *provider, GtkWidget *window,
selected = na_selected_info_get_list_from_list(( GList * ) files );
- nautilus_menus_list = get_file_or_background_items(
- NAUTILUS_ACTIONS( provider ), ITEM_TARGET_SELECTION, selected );
+ nautilus_menus_list = get_menus_items( NAUTILUS_ACTIONS( provider ), ITEM_TARGET_SELECTION, selected );
na_selected_info_free_list( selected );
}
@@ -474,7 +476,6 @@ menu_provider_get_toolbar_items( NautilusMenuProvider *provider, GtkWidget *wind
GList *nautilus_menus_list = NULL;
gchar *uri;
GList *selected;
- GList *pivot_tree;
g_return_val_if_fail( NAUTILUS_IS_ACTIONS( provider ), NULL );
@@ -485,12 +486,9 @@ menu_provider_get_toolbar_items( NautilusMenuProvider *provider, GtkWidget *wind
thisfn, ( void * ) provider, ( void * ) window, ( void * ) current_folder, uri );
g_free( uri );
- pivot_tree = na_pivot_get_items( NAUTILUS_ACTIONS( provider )->private->pivot );
-
selected = na_selected_info_get_list_from_item( current_folder );
- nautilus_menus_list = build_nautilus_menus(
- NAUTILUS_ACTIONS( provider ), pivot_tree, ITEM_TARGET_TOOLBAR, selected );
+ nautilus_menus_list = get_menus_items( NAUTILUS_ACTIONS( provider ), ITEM_TARGET_TOOLBAR, selected );
na_selected_info_free_list( selected );
}
@@ -499,38 +497,140 @@ menu_provider_get_toolbar_items( NautilusMenuProvider *provider, GtkWidget *wind
}
static GList *
-get_file_or_background_items( NautilusActions *plugin, guint target, GList *selection )
+get_menus_items( NautilusActions *plugin, guint target, GList *selection )
{
GList *menus_list;
- GList *pivot_tree;
+ NATokens *tokens;
+ GList *pivot_tree, *copy_tree;
gboolean root_menu;
gboolean add_about;
g_return_val_if_fail( NA_IS_PIVOT( plugin->private->pivot ), NULL );
+ tokens = na_tokens_new_from_selection( selection );
pivot_tree = na_pivot_get_items( plugin->private->pivot );
+ copy_tree = expand_tokens( pivot_tree, tokens );
- menus_list = build_nautilus_menus( plugin, pivot_tree, target, selection );
+ menus_list = build_nautilus_menus( plugin, pivot_tree, target, selection, tokens );
- root_menu = na_iprefs_read_bool( NA_IPREFS( plugin->private->pivot ), IPREFS_CREATE_ROOT_MENU, FALSE );
- if( root_menu ){
- menus_list = create_root_menu( plugin, menus_list );
- }
+ na_object_unref_items( copy_tree );
+ g_object_unref( tokens );
+
+ if( target != ITEM_TARGET_TOOLBAR ){
+
+ root_menu = na_iprefs_read_bool( NA_IPREFS( plugin->private->pivot ), IPREFS_CREATE_ROOT_MENU, FALSE );
+ if( root_menu ){
+ menus_list = create_root_menu( plugin, menus_list );
+ }
- add_about = na_iprefs_read_bool( NA_IPREFS( plugin->private->pivot ), IPREFS_ADD_ABOUT_ITEM, TRUE );
- if( add_about ){
- menus_list = add_about_item( plugin, menus_list );
+ add_about = na_iprefs_read_bool( NA_IPREFS( plugin->private->pivot ), IPREFS_ADD_ABOUT_ITEM, TRUE );
+ if( add_about ){
+ menus_list = add_about_item( plugin, menus_list );
+ }
}
return( menus_list );
}
/*
+ * create a copy of the tree where all fields which may embed parameters
+ * have been expanded
+ */
+static GList *
+expand_tokens( GList *pivot_tree, NATokens *tokens )
+{
+ GList *tree, *it;
+
+ tree = NULL;
+
+ for( it = pivot_tree ; it ; it = it->next ){
+ NAObjectItem *item = NA_OBJECT_ITEM( na_object_duplicate( it->data ));
+ tree = g_list_prepend( tree, expand_tokens_item( item, tokens ));
+ }
+
+ return( g_list_reverse( tree ));
+}
+
+static NAObjectItem *
+expand_tokens_item( NAObjectItem *item, NATokens *tokens )
+{
+ gchar *old, *new;
+ GSList *subitems_slist, *its, *new_slist;
+ GList *subitems, *it, *new_list;
+
+ old = na_object_get_label( item );
+ new = na_tokens_parse_parameters( tokens, old, TRUE );
+ na_object_set_label( item, new );
+ g_free( old );
+ g_free( new );
+
+ old = na_object_get_tooltip( item );
+ new = na_tokens_parse_parameters( tokens, old, TRUE );
+ na_object_set_tooltip( item, new );
+ g_free( old );
+ g_free( new );
+
+ old = na_object_get_icon( item );
+ new = na_tokens_parse_parameters( tokens, old, TRUE );
+ na_object_set_icon( item, new );
+ g_free( old );
+ g_free( new );
+
+ if( NA_IS_OBJECT_ACTION( item )){
+ old = na_object_get_toolbar_label( item );
+ new = na_tokens_parse_parameters( tokens, old, TRUE );
+ na_object_set_toolbar_label( item, new );
+ g_free( old );
+ g_free( new );
+ }
+
+ 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 );
+ 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 );
+
+ 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 );
+
+ old = na_object_get_parameters( it->data );
+ new = na_tokens_parse_parameters( tokens, old, FALSE );
+ na_object_set_parameters( it->data, new );
+ g_free( old );
+ g_free( new );
+ }
+ }
+
+ return( item );
+}
+
+/*
* when building a menu for the toolbar, do not use menus hierarchy
* files is a GList of NASelectedInfo items
+ *
+ * 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
+ * re-checked for validity !
*/
static GList *
-build_nautilus_menus( NautilusActions *plugin, GList *tree, guint target, GList *files )
+build_nautilus_menus( NautilusActions *plugin, GList *tree, guint target, GList *files, NATokens *tokens )
{
static const gchar *thisfn = "nautilus_actions_build_nautilus_menus";
GList *menus_list = NULL;
@@ -569,7 +669,7 @@ build_nautilus_menus( NautilusActions *plugin, GList *tree, guint target, GList
*/
if( NA_IS_OBJECT_MENU( it->data )){
subitems = na_object_get_items( it->data );
- submenu = build_nautilus_menus( plugin, subitems, target, files );
+ submenu = build_nautilus_menus( plugin, subitems, target, files, tokens );
/*g_debug( "%s: submenu has %d items", thisfn, g_list_length( submenu ));*/
if( submenu ){
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]