[nautilus-actions] Deal with mimetypes
- From: Pierre Wieser <pwieser src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [nautilus-actions] Deal with mimetypes
- Date: Thu, 10 Jun 2010 22:34:20 +0000 (UTC)
commit a01af1ce4318a089ffa0b66da625101f690c52c3
Author: Pierre Wieser <pwieser trychlos org>
Date: Mon May 3 05:55:01 2010 +0200
Deal with mimetypes
A boolean is set to TRUE when the context is to be selected for all mimetypes.
File mimetype is only checked when some specific types are specified.
ChangeLog | 19 ++
TODO | 3 +
src/api/na-icontext.h | 5 +-
src/api/na-ifactory-object-data.h | 1 +
src/api/na-object-api.h | 23 ++-
src/core/na-icontext-factory.c | 28 +++
src/core/na-icontext.c | 428 +++++++++++++++++++++++++++++++++++-
src/core/na-object-action.c | 31 +++
src/core/na-object-menu.c | 33 +++
src/core/na-object-profile.c | 27 ++-
src/nact/nact-iconditions-tab.c | 2 +-
src/plugin-menu/nautilus-actions.c | 17 +--
12 files changed, 576 insertions(+), 41 deletions(-)
---
diff --git a/ChangeLog b/ChangeLog
index 5803356..b1ff1e5 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -45,6 +45,25 @@
* src/utils/nautilus-actions-run.c:
Mark two new strings for translation.
+2010-05-03 Pierre Wieser <pwieser trychlos org>
+
+ * src/api/na-icontext.h:
+ * src/api/na-ifactory-object-data.h:
+ * src/api/na-object-api.h:
+ * src/core/na-icontext-factory.c:
+ * src/core/na-icontext.c:
+ Define new NAFO_DATA_ALL_MIMETYPES data, set to TRUE when the context
+ is to be selected for all mimetypes.
+
+ * src/core/na-object-action.c:
+ * src/core/na-object-menu.c:
+ * src/core/na-object-profile.c:
+ * src/plugin-menu/nautilus-actions.c:
+ All objects implement NAIContextInterface.
+
+ * src/nact/nact-iconditions-tab.c (na_object_is_matchcase):
+ Renamed as na_object_get_matchcase().
+
2010-04-19 Pierre Wieser <pwieser trychlos org>
* src/api/na-ifactory-object-data.h:
diff --git a/TODO b/TODO
index c205ba2..95d6c26 100644
--- a/TODO
+++ b/TODO
@@ -141,3 +141,6 @@
- "x-nautilus-desktop:///" is rather a scheme than a folder => actually is an URI
- enhancement.ui: add a 'why this item is invalid'
+
+- setup the dynamic all-mimetypes data
+
diff --git a/src/api/na-icontext.h b/src/api/na-icontext.h
index cfcb8c9..49f011b 100644
--- a/src/api/na-icontext.h
+++ b/src/api/na-icontext.h
@@ -86,8 +86,9 @@ GType na_icontext_get_type( void );
gboolean na_icontext_is_candidate( const NAIContext *object, guint target, GList *selection );
gboolean na_icontext_is_valid ( const NAIContext *object );
-void na_icontext_set_scheme ( NAIContext *object, const gchar *scheme, gboolean selected );
-void na_icontext_replace_folder( NAIContext *object, const gchar *old, const gchar *new );
+void na_icontext_have_all_mimetypes( NAIContext *object );
+void na_icontext_set_scheme ( NAIContext *object, const gchar *scheme, gboolean selected );
+void na_icontext_replace_folder ( NAIContext *object, const gchar *old, const gchar *new );
G_END_DECLS
diff --git a/src/api/na-ifactory-object-data.h b/src/api/na-ifactory-object-data.h
index 305659e..3dc6875 100644
--- a/src/api/na-ifactory-object-data.h
+++ b/src/api/na-ifactory-object-data.h
@@ -87,6 +87,7 @@ G_BEGIN_DECLS
#define NAFO_DATA_BASENAMES "na-factory-data-basenames"
#define NAFO_DATA_MATCHCASE "na-factory-data-matchcase"
#define NAFO_DATA_MIMETYPES "na-factory-data-mimetypes"
+#define NAFO_DATA_ALL_MIMETYPES "na-factory-data-all-mimetypes"
#define NAFO_DATA_ISFILE "na-factory-data-isfile"
#define NAFO_DATA_ISDIR "na-factory-data-isdir"
#define NAFO_DATA_MULTIPLE "na-factory-data-multiple"
diff --git a/src/api/na-object-api.h b/src/api/na-object-api.h
index 6b46826..95113d0 100644
--- a/src/api/na-object-api.h
+++ b/src/api/na-object-api.h
@@ -154,20 +154,14 @@ G_BEGIN_DECLS
*/
#define na_object_get_path( obj ) (( gchar * ) na_ifactory_object_get_as_void( NA_IFACTORY_OBJECT( obj ), NAFO_DATA_PATH ))
#define na_object_get_parameters( obj ) (( gchar * ) na_ifactory_object_get_as_void( NA_IFACTORY_OBJECT( obj ), NAFO_DATA_PARAMETERS ))
-#define na_object_get_basenames( obj ) (( GSList * ) na_ifactory_object_get_as_void( NA_IFACTORY_OBJECT( obj ), NAFO_DATA_BASENAMES ))
-#define na_object_is_matchcase( obj ) (( gboolean ) GPOINTER_TO_UINT( na_ifactory_object_get_as_void( NA_IFACTORY_OBJECT( obj ), NAFO_DATA_MATCHCASE )))
-#define na_object_get_mimetypes( obj ) (( GSList * ) na_ifactory_object_get_as_void( NA_IFACTORY_OBJECT( obj ), NAFO_DATA_MIMETYPES ))
#define na_object_is_file( obj ) (( gboolean ) GPOINTER_TO_UINT( na_ifactory_object_get_as_void( NA_IFACTORY_OBJECT( obj ), NAFO_DATA_ISFILE )))
#define na_object_is_dir( obj ) (( gboolean ) GPOINTER_TO_UINT( na_ifactory_object_get_as_void( NA_IFACTORY_OBJECT( obj ), NAFO_DATA_ISDIR )))
#define na_object_is_multiple( obj ) (( gboolean ) GPOINTER_TO_UINT( na_ifactory_object_get_as_void( NA_IFACTORY_OBJECT( obj ), NAFO_DATA_MULTIPLE )))
-#define na_object_get_schemes( obj ) (( GSList * ) na_ifactory_object_get_as_void( NA_IFACTORY_OBJECT( obj ), NAFO_DATA_SCHEMES ))
-#define na_object_get_folders( obj ) (( GSList * ) na_ifactory_object_get_as_void( NA_IFACTORY_OBJECT( obj ), NAFO_DATA_FOLDERS ))
#define na_object_set_path( obj, path ) na_ifactory_object_set_from_void( NA_IFACTORY_OBJECT( obj ), NAFO_DATA_PATH, ( const void * )( path ))
#define na_object_set_parameters( obj, parms ) na_ifactory_object_set_from_void( NA_IFACTORY_OBJECT( obj ), NAFO_DATA_PARAMETERS, ( const void * )( parms ))
#define na_object_set_basenames( obj, bnames ) na_ifactory_object_set_from_void( NA_IFACTORY_OBJECT( obj ), NAFO_DATA_BASENAMES, ( const void * )( bnames ))
#define na_object_set_matchcase( obj, match ) na_ifactory_object_set_from_void( NA_IFACTORY_OBJECT( obj ), NAFO_DATA_MATCHCASE, ( const void * ) GUINT_TO_POINTER( match ))
-#define na_object_set_mimetypes( obj, types ) na_ifactory_object_set_from_void( NA_IFACTORY_OBJECT( obj ), NAFO_DATA_MIMETYPES, ( const void * )( types ))
#define na_object_set_isfile( obj, isfile ) na_ifactory_object_set_from_void( NA_IFACTORY_OBJECT( obj ), NAFO_DATA_ISFILE, ( const void * ) GUINT_TO_POINTER( isfile ))
#define na_object_set_isdir( obj, isdir ) na_ifactory_object_set_from_void( NA_IFACTORY_OBJECT( obj ), NAFO_DATA_ISDIR, ( const void * ) GUINT_TO_POINTER( isdir ))
#define na_object_set_multiple( obj, multiple ) na_ifactory_object_set_from_void( NA_IFACTORY_OBJECT( obj ), NAFO_DATA_MULTIPLE, ( const void * ) GUINT_TO_POINTER( multiple ))
@@ -176,6 +170,23 @@ G_BEGIN_DECLS
/* NAIContext
*/
+#define na_object_get_only_show_in( obj ) (( GSList * ) na_ifactory_object_get_as_void( NA_IFACTORY_OBJECT( obj ), NAFO_DATA_ONLY_SHOW ))
+#define na_object_get_not_show_in( obj ) (( GSList * ) na_ifactory_object_get_as_void( NA_IFACTORY_OBJECT( obj ), NAFO_DATA_NOT_SHOW ))
+#define na_object_get_try_exec( obj ) (( gchar * ) na_ifactory_object_get_as_void( NA_IFACTORY_OBJECT( obj ), NAFO_DATA_TRY_EXEC ))
+#define na_object_get_show_if_registered( obj ) (( gchar * ) na_ifactory_object_get_as_void( NA_IFACTORY_OBJECT( obj ), NAFO_DATA_SHOW_IF_REGISTERED ))
+#define na_object_get_show_if_true( obj ) (( gchar * ) na_ifactory_object_get_as_void( NA_IFACTORY_OBJECT( obj ), NAFO_DATA_SHOW_IF_TRUE ))
+#define na_object_get_show_if_running( obj ) (( gchar * ) na_ifactory_object_get_as_void( NA_IFACTORY_OBJECT( obj ), NAFO_DATA_SHOW_IF_RUNNING ))
+#define na_object_get_mimetypes( obj ) (( GSList * ) na_ifactory_object_get_as_void( NA_IFACTORY_OBJECT( obj ), NAFO_DATA_MIMETYPES ))
+#define na_object_get_all_mimetypes( obj ) (( gboolean ) GPOINTER_TO_UINT( na_ifactory_object_get_as_void( NA_IFACTORY_OBJECT( obj ), NAFO_DATA_ALL_MIMETYPES )))
+#define na_object_get_basenames( obj ) (( GSList * ) na_ifactory_object_get_as_void( NA_IFACTORY_OBJECT( obj ), NAFO_DATA_BASENAMES ))
+#define na_object_get_matchcase( obj ) (( gboolean ) GPOINTER_TO_UINT( na_ifactory_object_get_as_void( NA_IFACTORY_OBJECT( obj ), NAFO_DATA_MATCHCASE )))
+#define na_object_get_selection_count( obj ) (( gchar * ) na_ifactory_object_get_as_void( NA_IFACTORY_OBJECT( obj ), NAFO_DATA_SELECTION_COUNT ))
+#define na_object_get_schemes( obj ) (( GSList * ) na_ifactory_object_get_as_void( NA_IFACTORY_OBJECT( obj ), NAFO_DATA_SCHEMES ))
+#define na_object_get_folders( obj ) (( GSList * ) na_ifactory_object_get_as_void( NA_IFACTORY_OBJECT( obj ), NAFO_DATA_FOLDERS ))
+#define na_object_get_capabilities( obj ) (( GSList * ) na_ifactory_object_get_as_void( NA_IFACTORY_OBJECT( obj ), NAFO_DATA_CAPABILITITES ))
+
+#define na_object_set_mimetypes( obj, types ) na_ifactory_object_set_from_void( NA_IFACTORY_OBJECT( obj ), NAFO_DATA_MIMETYPES, ( const void * )( types ))
+#define na_object_set_all_mimetypes( obj, all ) na_ifactory_object_set_from_void( NA_IFACTORY_OBJECT( obj ), NAFO_DATA_ALL_MIMETYPES, ( const void * ) GUINT_TO_POINTER( all ))
#define na_object_set_scheme( obj, scheme, add ) na_icontext_set_scheme( NA_ICONTEXT( obj ), ( const gchar * )( scheme ), ( add ))
#define na_object_replace_folder( obj, old, new ) na_icontext_replace_folder( NA_ICONTEXT( obj ), ( const gchar * )( old ), ( const gchar * )( new ))
diff --git a/src/core/na-icontext-factory.c b/src/core/na-icontext-factory.c
index 187a5e1..726c505 100644
--- a/src/core/na-icontext-factory.c
+++ b/src/core/na-icontext-factory.c
@@ -121,6 +121,34 @@ NADataDef data_def_conditions [] = {
"You must set one option for each pattern you need" ),
N_( "<EXPR>" ) },
+ /* a runtime boolean set to TRUE if we detect that the previous string list
+ * just cover all mimetypes - this let us optimize the check for candidate
+ * in the menu plugin
+ * when FALSE, than we have to check each and every mimetype :(
+ */
+ { NAFO_DATA_ALL_MIMETYPES,
+ FALSE,
+ FALSE,
+ TRUE,
+ "Does the mimetypes list is generic ?",
+ "The generic wildcard may be coded as '*', or '*/*' or 'all' or 'all/*'."
+ "In each case, we will try to spend as less time as possible to check " \
+ "selection mimetypes",
+ NAFD_TYPE_BOOLEAN,
+ "false",
+ TRUE,
+ TRUE,
+ FALSE,
+ FALSE,
+ NULL,
+ NULL,
+ 0,
+ NULL,
+ 0,
+ 0,
+ NULL,
+ NULL },
+
{ NAFO_DATA_ISFILE,
TRUE,
TRUE,
diff --git a/src/core/na-icontext.c b/src/core/na-icontext.c
index 174bfab..5c132f4 100644
--- a/src/core/na-icontext.c
+++ b/src/core/na-icontext.c
@@ -32,6 +32,7 @@
#include <config.h>
#endif
+#include <dbus/dbus-glib.h>
#include <string.h>
#include <libnautilus-extension/nautilus-file-info.h>
@@ -57,6 +58,21 @@ static void interface_base_finalize( NAIContextInterface *klass );
static gboolean v_is_candidate( NAIContext *object, guint target, GList *selection );
+static gboolean is_candidate_for_target( const NAIContext *object, guint target, GList *files );
+static gboolean is_candidate_for_show_in( const NAIContext *object, guint target, GList *files );
+static gboolean is_candidate_for_try_exec( const NAIContext *object, guint target, GList *files );
+static gboolean is_candidate_for_show_if_registered( const NAIContext *object, guint target, GList *files );
+static gboolean is_candidate_for_show_if_true( const NAIContext *object, guint target, GList *files );
+static gboolean is_candidate_for_show_if_running( const NAIContext *object, guint target, GList *files );
+static gboolean is_candidate_for_mimetypes( const NAIContext *object, guint target, GList *files );
+static gboolean is_mimetype_of( const gchar *file_type, const gchar *group, const gchar *subgroup );
+static void split_mimetype( const gchar *mimetype, gchar **group, gchar **subgroup );
+static gboolean is_candidate_for_basenames( const NAIContext *object, guint target, GList *files );
+static gboolean is_candidate_for_selection_count( const NAIContext *object, guint target, GList *files );
+static gboolean is_candidate_for_schemes( const NAIContext *object, guint target, GList *files );
+static gboolean is_candidate_for_folders( const NAIContext *object, guint target, GList *files );
+static gboolean is_candidate_for_capabilities( const NAIContext *object, guint target, GList *files );
+
static gboolean is_target_location_candidate( const NAIContext *object, NASelectedInfo *current_folder );
static gboolean is_target_toolbar_candidate( const NAIContext *object, NASelectedInfo *current_folder );
static gboolean is_current_folder_inside( const NAIContext *object, NASelectedInfo *current_folder );
@@ -67,6 +83,7 @@ static gboolean is_valid_isfiledir( const NAIContext *object );
static gboolean is_valid_schemes( const NAIContext *object );
static gboolean is_valid_folders( const NAIContext *object );
+static gboolean is_positive_assertion( const gchar *assertion );
static gboolean validate_schemes( GSList *object_schemes, NASelectedInfo *iter );
/**
@@ -171,18 +188,36 @@ na_icontext_is_candidate( const NAIContext *object, guint target, GList *files )
is_candidate = v_is_candidate( NA_ICONTEXT( object ), target, files );
- switch( target ){
- case ITEM_TARGET_LOCATION:
- is_candidate = is_target_location_candidate( object, ( NASelectedInfo * ) files->data );
- break;
+ if( is_candidate ){
+ is_candidate =
+ is_candidate_for_target( object, target, files ) &&
+ is_candidate_for_show_in( object, target, files ) &&
+ is_candidate_for_try_exec( object, target, files ) &&
+ is_candidate_for_show_if_registered( object, target, files ) &&
+ is_candidate_for_show_if_true( object, target, files ) &&
+ is_candidate_for_show_if_running( object, target, files ) &&
+ is_candidate_for_mimetypes( object, target, files ) &&
+ is_candidate_for_basenames( object, target, files ) &&
+ is_candidate_for_selection_count( object, target, files ) &&
+ is_candidate_for_schemes( object, target, files ) &&
+ is_candidate_for_folders( object, target, files ) &&
+ is_candidate_for_capabilities( object, target, files );
+ }
+
+ if( is_candidate ){
+ switch( target ){
+ case ITEM_TARGET_LOCATION:
+ is_candidate = is_target_location_candidate( object, ( NASelectedInfo * ) files->data );
+ break;
- case ITEM_TARGET_TOOLBAR:
- is_candidate = is_target_toolbar_candidate( object, ( NASelectedInfo * ) files->data );
- break;
+ case ITEM_TARGET_TOOLBAR:
+ is_candidate = is_target_toolbar_candidate( object, ( NASelectedInfo * ) files->data );
+ break;
- case ITEM_TARGET_SELECTION:
- default:
- is_candidate = is_target_selection_candidate( object, files );
+ case ITEM_TARGET_SELECTION:
+ default:
+ is_candidate = is_target_selection_candidate( object, files );
+ }
}
return( is_candidate );
@@ -218,6 +253,40 @@ na_icontext_is_valid( const NAIContext *object )
}
/**
+ * na_icontext_have_all_mimetypes:
+ * @context: the #NAIContext object to be checked.
+ *
+ * Check if this object is valid for all mimetypes. This is done at load
+ * time, and let us spend as less time as possible when testing for
+ * candidates.
+ */
+void
+na_icontext_have_all_mimetypes( NAIContext *object )
+{
+ gboolean all = TRUE;
+ GSList *mimetypes = na_object_get_mimetypes( object );
+ GSList *im;
+
+ for( im = mimetypes ; im ; im = im->next ){
+ if( !im->data || !strlen( im->data )){
+ continue;
+ }
+ const gchar *imtype = ( const gchar * ) im->data;
+ if( !strcmp( imtype, "*" ) ||
+ !strcmp( imtype, "*/*" ) ||
+ !strcmp( imtype, "all" ) ||
+ !strcmp( imtype, "all/*" ) ||
+ !strcmp( imtype, "all/all" )){
+ continue;
+ }
+ all = FALSE;
+ break;
+ }
+
+ na_object_set_all_mimetypes( object, all );
+}
+
+/**
* na_icontext_set_scheme:
* @profile: the #NAIContext to be updated.
* @scheme: name of the scheme.
@@ -284,6 +353,324 @@ v_is_candidate( NAIContext *object, guint target, GList *selection )
return( is_candidate );
}
+/*
+ * whether the given NAIContext object is candidate for this target
+ * target is context menu for location, context menu for selection or toolbar for location
+ * only actions are concerned by this check
+ */
+static gboolean
+is_candidate_for_target( const NAIContext *object, guint target, GList *files )
+{
+ static const gchar *thisfn = "na_icontext_is_candidate_for_target";
+ gboolean ok = TRUE;
+
+ if( NA_IS_OBJECT_ACTION( object )){
+ switch( target ){
+ case ITEM_TARGET_LOCATION:
+ ok = na_object_is_target_location( object );
+ break;
+
+ case ITEM_TARGET_TOOLBAR:
+ ok = na_object_is_target_toolbar( object );
+ break;
+
+ case ITEM_TARGET_SELECTION:
+ ok = na_object_is_target_selection( object );
+ break;
+
+ default:
+ g_warning( "%s: unknonw target=%d", thisfn, target );
+ }
+ }
+
+ return( ok );
+}
+
+/*
+ * only show in / not show in
+ * only one of these two data may be set
+ */
+static gboolean
+is_candidate_for_show_in( const NAIContext *object, guint target, GList *files )
+{
+ gboolean ok = TRUE;
+
+ /* TODO: how-to get current running environment ? */
+
+ return( ok );
+}
+
+/*
+ * if the data is set, it should be the path of an executable file
+ */
+static gboolean
+is_candidate_for_try_exec( const NAIContext *object, guint target, GList *files )
+{
+ gboolean ok = TRUE;
+ gchar *tryexec = na_object_get_try_exec( object );
+
+ if( tryexec && strlen( tryexec )){
+ ok = FALSE;
+ GFile *file = g_file_new_for_path( tryexec );
+ GFileInfo *info = g_file_query_info( file, G_FILE_ATTRIBUTE_ACCESS_CAN_EXECUTE, G_FILE_QUERY_INFO_NONE, NULL, NULL );
+ ok = g_file_info_get_attribute_boolean( info, G_FILE_ATTRIBUTE_ACCESS_CAN_EXECUTE );
+ g_object_unref( info );
+ g_object_unref( file );
+ }
+
+ g_free( tryexec );
+
+ return( ok );
+}
+
+static gboolean
+is_candidate_for_show_if_registered( const NAIContext *object, guint target, GList *files )
+{
+ static const gchar *thisfn = "na_icontext_is_candidate_for_show_if_registered";
+ gboolean ok = TRUE;
+ gchar *name = na_object_get_show_if_registered( object );
+
+ if( name && strlen( name )){
+ ok = FALSE;
+ GError *error = NULL;
+ DBusGConnection *connection = dbus_g_bus_get( DBUS_BUS_SESSION, &error );
+
+ if( !connection ){
+ if( error ){
+ g_warning( "%s: %s", thisfn, error->message );
+ g_error_free( error );
+ }
+
+ } else {
+ DBusGProxy *proxy = dbus_g_proxy_new_for_name( connection, name, NULL, NULL );
+ ok = ( proxy != NULL );
+ dbus_g_connection_unref( connection );
+ }
+ }
+
+ g_free( name );
+
+ return( ok );
+}
+
+static gboolean
+is_candidate_for_show_if_true( const NAIContext *object, guint target, GList *files )
+{
+ gboolean ok = TRUE;
+ gchar *command = na_object_get_show_if_true( object );
+
+ if( command && strlen( command )){
+ ok = FALSE;
+ gchar *stdout = NULL;
+ g_spawn_command_line_sync( command, &stdout, NULL, NULL, NULL );
+
+ if( stdout && !strcmp( stdout, "true" )){
+ ok = TRUE;
+ }
+
+ g_free( stdout );
+ }
+
+ g_free( command );
+
+ return( ok );
+}
+
+static gboolean
+is_candidate_for_show_if_running( const NAIContext *object, guint target, GList *files )
+{
+ gboolean ok = TRUE;
+ gchar *running = na_object_get_show_if_running( object );
+
+ if( running && strlen( running )){
+ /* TODO: how to get the list of running processes ?
+ * or how to known if a given process is currently running
+ */
+ }
+
+ g_free( running );
+
+ return( ok );
+}
+
+/*
+ * object may embed a list of - possibly negated - mimetypes
+ * each file of the selection must satisfy all conditions of this list
+ * an empty list is considered the same as '*' or '* / *'
+ *
+ * most time, we will just have '*' - so try to optimize the code to
+ * be as fast as possible when we don't filter on mimetype
+ *
+ * mimetypes are of type : "image/ *; !image/jpeg"
+ * file mimetype must be compatible with at least one positive assertion
+ * (they are ORed), while not being of any negative assertions (they are
+ * ANDed)
+ */
+static gboolean
+is_candidate_for_mimetypes( const NAIContext *object, guint target, GList *files )
+{
+ gboolean ok = TRUE;
+ gboolean all = na_object_get_all_mimetypes( object );
+ GList *it;
+
+ if( !all ){
+ GSList *mimetypes = na_object_get_mimetypes( object );
+ GSList *im;
+ gboolean positive;
+ guint count_positive = 0;
+ guint count_compatible = 0;
+
+ for( im = mimetypes ; im && ok ; im = im->data ){
+ const gchar *imtype = ( const gchar * ) im->data;
+ positive = is_positive_assertion( imtype );
+ if( positive ){
+ count_positive += 1;
+ }
+ gchar *imgroup, *imsubgroup;
+ split_mimetype( imtype, &imgroup, &imsubgroup );
+
+ for( it = files ; it && ok ; it = it->next ){
+ gchar *ftype = na_selected_info_get_mime_type( NA_SELECTED_INFO( it->data ));
+ gboolean type_of = is_mimetype_of( ftype, imgroup, imsubgroup );
+
+ if( positive ){
+ if( type_of ){
+ count_compatible += 1;
+ }
+ } else {
+ if( type_of ){
+ ok = FALSE;
+ break;
+ }
+ }
+
+ g_free( ftype );
+ }
+
+ g_free( imgroup );
+ g_free( imsubgroup );
+ }
+
+ if( count_positive > 0 && count_compatible == 0 ){
+ ok = FALSE;
+ }
+
+ na_core_utils_slist_free( mimetypes );
+ }
+
+ return( ok );
+}
+
+/*
+ * does the file have a mimetype which is 'a sort of' specified one ?
+ * for example, "image/jpeg" is clearly a sort of "image/ *"
+ * but how to check to see if "msword/xml" is a sort of "application/xml" ??
+ */
+static gboolean
+is_mimetype_of( const gchar *file_type, const gchar *group, const gchar *subgroup )
+{
+ gboolean is_type_of;
+ gchar *fgroup, *fsubgroup;
+
+ split_mimetype( file_type, &fgroup, &fsubgroup );
+
+ is_type_of = ( strcmp( fgroup, group ) == 0 );
+ if( is_type_of ){
+ if( strcmp( subgroup, "*" )){
+ is_type_of = ( strcmp( fsubgroup, subgroup ) == 0 );
+ }
+ }
+
+ g_free( fgroup );
+ g_free( fsubgroup );
+
+ return( is_type_of );
+}
+
+static void
+split_mimetype( const gchar *mimetype, gchar **group, gchar **subgroup )
+{
+ GSList *slist = na_core_utils_slist_from_split( mimetype, "/" );
+ GSList *is = slist;
+ *group = g_strdup(( const gchar * ) is->data );
+ is = is->next;
+ *subgroup = g_strdup(( const gchar * ) is->data );
+ na_core_utils_slist_free( slist );
+}
+
+static gboolean
+is_candidate_for_basenames( const NAIContext *object, guint target, GList *files )
+{
+ gboolean ok = TRUE;
+ GSList *basenames = na_object_get_basenames( object );
+
+ if( basenames ){
+ gboolean matchcase = na_object_get_matchcase( object );
+ matchcase = FALSE;
+
+ na_core_utils_slist_free( basenames );
+ }
+
+ return( ok );
+}
+
+static gboolean
+is_candidate_for_selection_count( const NAIContext *object, guint target, GList *files )
+{
+ gboolean ok = TRUE;
+ gchar *selection_count = na_object_get_selection_count( object );
+
+ if( selection_count && strlen( selection_count )){
+
+ }
+
+ g_free( selection_count );
+
+ return( ok );
+}
+
+static gboolean
+is_candidate_for_schemes( const NAIContext *object, guint target, GList *files )
+{
+ gboolean ok = TRUE;
+ GSList *schemes = na_object_get_schemes( object );
+
+ if( schemes ){
+
+ na_core_utils_slist_free( schemes );
+ }
+
+ return( ok );
+}
+
+static gboolean
+is_candidate_for_folders( const NAIContext *object, guint target, GList *files )
+{
+ gboolean ok = TRUE;
+ GSList *folders = na_object_get_folders( object );
+
+ if( folders ){
+
+ na_core_utils_slist_free( folders );
+ }
+
+ return( ok );
+}
+
+static gboolean
+is_candidate_for_capabilities( const NAIContext *object, guint target, GList *files )
+{
+ gboolean ok = TRUE;
+ GSList *capabilities = na_object_get_capabilities( object );
+
+ if( capabilities ){
+
+ na_core_utils_slist_free( capabilities );
+ }
+
+ return( ok );
+}
+
static gboolean
is_target_location_candidate( const NAIContext *object, NASelectedInfo *current_folder )
{
@@ -357,7 +744,7 @@ is_target_selection_candidate( const NAIContext *object, GList *files )
gchar *tmp_pattern, *tmp_filename, *tmp_filename2, *tmp_mimetype, *tmp_mimetype2;
basenames = na_object_get_basenames( object );
- matchcase = na_object_is_matchcase( object );
+ matchcase = na_object_get_matchcase( object );
multiple = na_object_is_multiple( object );
isdir = na_object_is_dir( object );
isfile = na_object_is_file( object );
@@ -617,6 +1004,25 @@ is_valid_folders( const NAIContext *object )
return( valid );
}
+/*
+ * "image/ *" is a positive assertion
+ * "!image/jpeg" is a negative one
+ */
+static gboolean
+is_positive_assertion( const gchar *assertion )
+{
+ gboolean positive = TRUE;
+
+ if( assertion ){
+ const gchar *stripped = g_strstrip(( gchar * ) assertion );
+ if( stripped ){
+ positive = ( stripped[0] != '!' );
+ }
+ }
+
+ return( positive );
+}
+
static gboolean
validate_schemes( GSList *object_schemes, NASelectedInfo *nfi )
{
diff --git a/src/core/na-object-action.c b/src/core/na-object-action.c
index e0e0e5a..c86d232 100644
--- a/src/core/na-object-action.c
+++ b/src/core/na-object-action.c
@@ -84,6 +84,9 @@ static void ifactory_object_read_done( NAIFactoryObject *instance, const
static guint ifactory_object_write_start( NAIFactoryObject *instance, const NAIFactoryProvider *writer, void *writer_data, GSList **messages );
static guint ifactory_object_write_done( NAIFactoryObject *instance, const NAIFactoryProvider *writer, void *writer_data, GSList **messages );
+static void icontext_iface_init( NAIContextInterface *iface );
+static gboolean icontext_is_candidate( NAIContext *object, guint target, GList *selection );
+
static void convert_pre_v2_action( NAIFactoryObject *instance );
static void deals_with_toolbar_label( NAIFactoryObject *instance );
@@ -122,6 +125,12 @@ register_type( void )
( GInstanceInitFunc ) instance_init
};
+ static const GInterfaceInfo icontext_iface_info = {
+ ( GInterfaceInitFunc ) icontext_iface_init,
+ NULL,
+ NULL
+ };
+
static const GInterfaceInfo ifactory_object_iface_info = {
( GInterfaceInitFunc ) ifactory_object_iface_init,
NULL,
@@ -132,6 +141,8 @@ register_type( void )
type = g_type_register_static( NA_OBJECT_ITEM_TYPE, "NAObjectAction", &info, 0 );
+ g_type_add_interface_static( type, NA_ICONTEXT_TYPE, &icontext_iface_info );
+
g_type_add_interface_static( type, NA_IFACTORY_OBJECT_TYPE, &ifactory_object_iface_info );
return( type );
@@ -337,6 +348,10 @@ ifactory_object_read_done( NAIFactoryObject *instance, const NAIFactoryProvider
*/
deals_with_toolbar_label( instance );
+ /* test for all mimetypes
+ */
+ na_icontext_have_all_mimetypes( NA_ICONTEXT( instance ));
+
/* last, set other action defaults
*/
na_factory_object_set_defaults( instance );
@@ -378,6 +393,22 @@ ifactory_object_write_done( NAIFactoryObject *instance, const NAIFactoryProvider
return( code );
}
+static void
+icontext_iface_init( NAIContextInterface *iface )
+{
+ static const gchar *thisfn = "na_object_action_icontext_iface_init";
+
+ g_debug( "%s: iface=%p", thisfn, ( void * ) iface );
+
+ iface->is_candidate = icontext_is_candidate;
+}
+
+static gboolean
+icontext_is_candidate( NAIContext *object, guint target, GList *selection )
+{
+ return( TRUE );
+}
+
/*
* do we have a pre-v2 action ?
* it may be identified by an version = "1.x"
diff --git a/src/core/na-object-menu.c b/src/core/na-object-menu.c
index 047d339..76e19c2 100644
--- a/src/core/na-object-menu.c
+++ b/src/core/na-object-menu.c
@@ -82,6 +82,9 @@ static void ifactory_object_read_done( NAIFactoryObject *instance, const
static guint ifactory_object_write_start( NAIFactoryObject *instance, const NAIFactoryProvider *writer, void *writer_data, GSList **messages );
static guint ifactory_object_write_done( NAIFactoryObject *instance, const NAIFactoryProvider *writer, void *writer_data, GSList **messages );
+static void icontext_iface_init( NAIContextInterface *iface );
+static gboolean icontext_is_candidate( NAIContext *object, guint target, GList *selection );
+
static gboolean menu_is_valid( const NAObjectMenu *menu );
static gboolean is_valid_label( const NAObjectMenu *menu );
@@ -116,6 +119,12 @@ register_type( void )
( GInstanceInitFunc ) instance_init
};
+ static const GInterfaceInfo icontext_iface_info = {
+ ( GInterfaceInitFunc ) icontext_iface_init,
+ NULL,
+ NULL
+ };
+
static const GInterfaceInfo ifactory_object_iface_info = {
( GInterfaceInitFunc ) ifactory_object_iface_init,
NULL,
@@ -126,6 +135,8 @@ register_type( void )
type = g_type_register_static( NA_OBJECT_ITEM_TYPE, "NAObjectMenu", &info, 0 );
+ g_type_add_interface_static( type, NA_ICONTEXT_TYPE, &icontext_iface_info );
+
g_type_add_interface_static( type, NA_IFACTORY_OBJECT_TYPE, &ifactory_object_iface_info );
return( type );
@@ -315,6 +326,12 @@ ifactory_object_read_start( NAIFactoryObject *instance, const NAIFactoryProvider
static void
ifactory_object_read_done( NAIFactoryObject *instance, const NAIFactoryProvider *reader, void *reader_data, GSList **messages )
{
+ /* test for all mimetypes
+ */
+ na_icontext_have_all_mimetypes( NA_ICONTEXT( instance ));
+
+ /* last, set other action defaults
+ */
na_factory_object_set_defaults( instance );
}
@@ -332,6 +349,22 @@ ifactory_object_write_done( NAIFactoryObject *instance, const NAIFactoryProvider
return( NA_IIO_PROVIDER_CODE_OK );
}
+static void
+icontext_iface_init( NAIContextInterface *iface )
+{
+ static const gchar *thisfn = "na_object_menu_icontext_iface_init";
+
+ g_debug( "%s: iface=%p", thisfn, ( void * ) iface );
+
+ iface->is_candidate = icontext_is_candidate;
+}
+
+static gboolean
+icontext_is_candidate( NAIContext *object, guint target, GList *selection )
+{
+ return( TRUE );
+}
+
static gboolean
menu_is_valid( const NAObjectMenu *menu )
{
diff --git a/src/core/na-object-profile.c b/src/core/na-object-profile.c
index 17b728c..ff7b1eb 100644
--- a/src/core/na-object-profile.c
+++ b/src/core/na-object-profile.c
@@ -83,7 +83,8 @@ static gboolean ifactory_object_is_valid( const NAIFactoryObject *object );
static void ifactory_object_read_done( NAIFactoryObject *instance, const NAIFactoryProvider *reader, void *reader_data, GSList **messages );
static guint ifactory_object_write_done( NAIFactoryObject *instance, const NAIFactoryProvider *writer, void *writer_data, GSList **messages );
-static void icontext_conditions_iface_init( NAIContextInterface *iface );
+static void icontext_iface_init( NAIContextInterface *iface );
+static gboolean icontext_is_candidate( NAIContext *object, guint target, GList *selection );
static gboolean profile_is_valid( const NAObjectProfile *profile );
static gboolean is_valid_path_parameters( const NAObjectProfile *profile );
@@ -120,8 +121,8 @@ register_type( void )
( GInstanceInitFunc ) instance_init
};
- static const GInterfaceInfo icontext_conditions_iface_info = {
- ( GInterfaceInitFunc ) icontext_conditions_iface_init,
+ static const GInterfaceInfo icontext_iface_info = {
+ ( GInterfaceInitFunc ) icontext_iface_init,
NULL,
NULL
};
@@ -136,7 +137,7 @@ register_type( void )
type = g_type_register_static( NA_OBJECT_ID_TYPE, "NAObjectProfile", &info, 0 );
- g_type_add_interface_static( type, NA_ICONTEXT_TYPE, &icontext_conditions_iface_info );
+ g_type_add_interface_static( type, NA_ICONTEXT_TYPE, &icontext_iface_info );
g_type_add_interface_static( type, NA_IFACTORY_OBJECT_TYPE, &ifactory_object_iface_info );
@@ -327,6 +328,12 @@ ifactory_object_is_valid( const NAIFactoryObject *object )
static void
ifactory_object_read_done( NAIFactoryObject *instance, const NAIFactoryProvider *reader, void *reader_data, GSList **messages )
{
+ /* test for all mimetypes
+ */
+ na_icontext_have_all_mimetypes( NA_ICONTEXT( instance ));
+
+ /* last, set other action defaults
+ */
na_factory_object_set_defaults( instance );
}
@@ -337,11 +344,19 @@ ifactory_object_write_done( NAIFactoryObject *instance, const NAIFactoryProvider
}
static void
-icontext_conditions_iface_init( NAIContextInterface *iface )
+icontext_iface_init( NAIContextInterface *iface )
{
- static const gchar *thisfn = "na_object_profile_icontext_conditions_iface_init";
+ static const gchar *thisfn = "na_object_profile_icontext_iface_init";
g_debug( "%s: iface=%p", thisfn, ( void * ) iface );
+
+ iface->is_candidate = icontext_is_candidate;
+}
+
+static gboolean
+icontext_is_candidate( NAIContext *object, guint target, GList *selection )
+{
+ return( TRUE );
}
static gboolean
diff --git a/src/nact/nact-iconditions-tab.c b/src/nact/nact-iconditions-tab.c
index 6e26c54..8a107b5 100644
--- a/src/nact/nact-iconditions-tab.c
+++ b/src/nact/nact-iconditions-tab.c
@@ -370,7 +370,7 @@ on_tab_updatable_selection_changed( NactIConditionsTab *instance, gint count_sel
nact_gtk_utils_set_editable( GTK_OBJECT( basenames_widget ), editable );
matchcase_button = get_matchcase_button( instance );
- matchcase = profile ? na_object_is_matchcase( profile ) : FALSE;
+ matchcase = profile ? na_object_get_matchcase( profile ) : FALSE;
gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( matchcase_button ), matchcase );
gtk_widget_set_sensitive( GTK_WIDGET( matchcase_button ), item != NULL );
nact_gtk_utils_set_editable( GTK_OBJECT( matchcase_button ), editable );
diff --git a/src/plugin-menu/nautilus-actions.c b/src/plugin-menu/nautilus-actions.c
index 0406ac9..b78f915 100644
--- a/src/plugin-menu/nautilus-actions.c
+++ b/src/plugin-menu/nautilus-actions.c
@@ -538,7 +538,6 @@ build_nautilus_menus( NautilusActions *plugin, GList *tree, guint target, GList
GList *it;
NAObjectProfile *profile;
NautilusMenuItem *item;
- gchar *action_label;
g_debug( "%s: plugin=%p, tree=%p, target=%d, files=%p (count=%d)",
thisfn, ( void * ) plugin, ( void * ) tree, target,
@@ -562,9 +561,9 @@ build_nautilus_menus( NautilusActions *plugin, GList *tree, guint target, GList
}
#endif
- /*if( !na_icontext_is_candidate( it->data, target, files )){
+ if( !na_icontext_is_candidate( NA_ICONTEXT( it->data ), target, files )){
continue;
- }*/
+ }
/* recursively build sub-menus
*/
@@ -586,24 +585,12 @@ build_nautilus_menus( NautilusActions *plugin, GList *tree, guint target, GList
}
g_return_val_if_fail( NA_IS_OBJECT_ACTION( it->data ), NULL );
- action_label = na_object_get_label( it->data );
- /* to be removed when NAObjectAction will implement NAIContext interface
- */
- if( !na_object_action_is_candidate( it->data, target, files )){
- g_debug( "%s: action %s is not candidate", thisfn, action_label );
- g_free( action_label );
- continue;
- }
-
- g_debug( "%s: action %s is candidate", thisfn, action_label );
profile = get_candidate_profile( plugin, NA_OBJECT_ACTION( it->data ), target, files );
if( profile ){
item = create_item_from_profile( profile, target, files );
menus_list = g_list_append( menus_list, item );
}
-
- g_free( action_label );
}
return( menus_list );
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]