[nautilus-actions] Deal with mimetypes



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]