[nautilus-actions] Edit capabilities



commit ee6f1e2860f67cc6d26aed4665370b75a0626ecc
Author: Pierre Wieser <pwieser trychlos org>
Date:   Mon Jun 14 07:13:23 2010 +0200

    Edit capabilities

 ChangeLog                             |   22 ++
 TODO                                  |    4 +
 po/POTFILES.in                        |    2 +
 src/core/na-icontext-factory.c        |    4 +-
 src/core/na-object-action.c           |    2 +
 src/nact/Makefile.am                  |    3 +
 src/nact/nact-add-capability-dialog.c |  567 +++++++++++++++++++++++++++++++++
 src/nact/nact-add-capability-dialog.h |   76 +++++
 src/nact/nact-add-capability.ui       |  145 +++++++++
 src/nact/nact-add-scheme.ui           |    1 +
 src/nact/nact-ibasenames-tab.c        |    1 +
 src/nact/nact-icapabilities-tab.c     |   65 ++++
 src/nact/nact-ifolders-tab.c          |    1 +
 src/nact/nact-imimetypes-tab.c        |    1 +
 src/nact/nact-ischemes-tab.c          |    1 +
 src/nact/nact-match-list.c            |   76 +++--
 src/nact/nact-match-list.h            |    9 +-
 src/nact/nact-schemes-list.c          |    6 +-
 18 files changed, 957 insertions(+), 29 deletions(-)
---
diff --git a/ChangeLog b/ChangeLog
index 8ca8615..935b07d 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,25 @@
+2010-06-14 Pierre Wieser <pwieser trychlos org>
+
+	* src/core/na-icontext-factory.c:
+	Change default capabilities to empty list.
+
+	* src/nact/nact-add-capability-dialog.c:
+	* src/nact/nact-add-capability-dialog.h:
+	* src/nact/nact-add-capability.ui: New files.
+
+	* po/POTFILES.in:
+	* src/nact/Makefile.am: Updated accordingly.
+
+	* src/nact/nact-match-list.c:
+	* src/nact/nact-match-list.h (nact_match_list_create_model):
+	Add match_header parameter.
+
+	* src/nact/nact-ibasenames-tab.c:
+	* src/nact/nact-icapabilities-tab.c:
+	* src/nact/nact-ifolders-tab.c:
+	* src/nact/nact-imimetypes-tab.c:
+	* src/nact/nact-ischemes-tab.c: Updated accordingly.
+
 2010-06-13 Pierre Wieser <pwieser trychlos org>
 
 	* src/nact/nact-match-list.c:
diff --git a/TODO b/TODO
index 3f769b8..32a5239 100644
--- a/TODO
+++ b/TODO
@@ -480,3 +480,7 @@ Parameter 	Description
 
 - ui.enhancement: let the user edit the current default schemes 
   when adding from defaults for a #NAIContext
+
+- bug: when expanding/collapsing a tree in IActionsList with the left/right arrows, we get
+  NA-core-CRITICAL **: na_ifactory_object_get_as_void: assertion `NA_IS_IFACTORY_OBJECT( object )' failed
+  we do not get this same message when using the menu or just the Enter key
diff --git a/po/POTFILES.in b/po/POTFILES.in
index c5c9744..8e053d0 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -22,6 +22,8 @@ src/nact/base-window.c
 src/nact/egg-desktop-file.c
 src/nact/egg-sm-client.c
 src/nact/nact-application.c
+src/nact/nact-add-capability-dialog.c
+src/nact/nact-add-capability.ui
 src/nact/nact-add-scheme.ui
 src/nact/nact-assistant-export.c
 src/nact/nact-assistant-export.ui
diff --git a/src/core/na-icontext-factory.c b/src/core/na-icontext-factory.c
index 27c2602..a82c1ab 100644
--- a/src/core/na-icontext-factory.c
+++ b/src/core/na-icontext-factory.c
@@ -487,9 +487,9 @@ NADataDef data_def_conditions [] = {
 					"- Writable: selected items are writable by user\n" \
 					"- Executable: selected items are executable by user\n" \
 					"- Local: selected items are local.\n" \
-					"Defaults to \"*;\"." ),
+					"Defaults to empty list." ),
 				NAFD_TYPE_STRING_LIST,
-				"*",
+				NULL,
 				FALSE,
 				TRUE,
 				TRUE,
diff --git a/src/core/na-object-action.c b/src/core/na-object-action.c
index e5c4a02..924d44f 100644
--- a/src/core/na-object-action.c
+++ b/src/core/na-object-action.c
@@ -354,6 +354,8 @@ ifactory_object_read_done( NAIFactoryObject *instance, const NAIFactoryProvider
 	 */
 	na_icontext_read_done( NA_ICONTEXT( instance ));
 
+	na_object_dump( instance );
+
 	/* last, set other action defaults
 	 */
 	na_factory_object_set_defaults( instance );
diff --git a/src/nact/Makefile.am b/src/nact/Makefile.am
index cb1bcad..48f875e 100644
--- a/src/nact/Makefile.am
+++ b/src/nact/Makefile.am
@@ -70,6 +70,8 @@ nautilus_actions_config_tool_SOURCES = \
 	egg-sm-client-xsmp.c								\
 	egg-tree-multi-dnd.c								\
 	egg-tree-multi-dnd.h								\
+	nact-add-capability-dialog.c						\
+	nact-add-capability-dialog.h						\
 	nact-add-scheme-dialog.c							\
 	nact-add-scheme-dialog.h							\
 	nact-application.c									\
@@ -173,6 +175,7 @@ nautilus_actions_config_tool_LDADD = \
 pkgdata_DATA = \
 	nautilus-actions-config-tool.actions				\
 	nautilus-actions-maintainer.actions					\
+	nact-add-capability.ui								\
 	nact-add-scheme.ui									\
 	nact-assistant-export.ui							\
 	nact-preferences.ui									\
diff --git a/src/nact/nact-add-capability-dialog.c b/src/nact/nact-add-capability-dialog.c
new file mode 100644
index 0000000..1d90dc7
--- /dev/null
+++ b/src/nact/nact-add-capability-dialog.c
@@ -0,0 +1,567 @@
+/*
+ * 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 <glib/gi18n.h>
+
+#include <api/na-core-utils.h>
+
+#include "nact-add-capability-dialog.h"
+
+/* private class data
+ */
+struct NactAddCapabilityDialogClassPrivate {
+	void *empty;						/* so that gcc -pedantic is happy */
+};
+
+/* private instance data
+ */
+struct NactAddCapabilityDialogPrivate {
+	gboolean dispose_has_run;
+	GSList  *already_used;
+	gchar   *capability;
+};
+
+/* column ordering in the model
+ */
+enum {
+	CAPABILITY_KEYWORD_COLUMN = 0,
+	CAPABILITY_DESC_COLUMN,
+	CAPABILITY_ALREADY_USED_COLUMN,
+	CAPABILITY_N_COLUMN
+};
+
+typedef struct {
+	gchar *keyword;
+	gchar *desc;
+}
+	CapabilityTextStruct;
+
+static CapabilityTextStruct st_caps[] = {
+		{ "Owner",      N_( "User is the owner of the item" ) },
+		{ "Readable",   N_( "Item is readable by the user" ) },
+		{ "Writable",   N_( "Item is writable by the user" ) },
+		{ "Executable", N_( "Item is executable by the user" ) },
+		{ "Local",      N_( "Item is local" ) },
+		{ NULL },
+};
+
+static GObjectClass *st_parent_class = NULL;
+
+static GType    register_type( void );
+static void     class_init( NactAddCapabilityDialogClass *klass );
+static void     instance_init( GTypeInstance *instance, gpointer klass );
+static void     instance_dispose( GObject *dialog );
+static void     instance_finalize( GObject *dialog );
+
+static NactAddCapabilityDialog *add_capability_dialog_new( BaseWindow *parent );
+
+static gchar   *base_get_iprefs_window_id( const BaseWindow *window );
+static gchar   *base_get_dialog_name( const BaseWindow *window );
+static gchar   *base_get_ui_filename( const BaseWindow *dialog );
+static void     on_base_initial_load_dialog( NactAddCapabilityDialog *editor, gpointer user_data );
+static void     on_base_runtime_init_dialog( NactAddCapabilityDialog *editor, gpointer user_data );
+static void     on_base_all_widgets_showed( NactAddCapabilityDialog *editor, gpointer user_data );
+static void     on_cancel_clicked( GtkButton *button, NactAddCapabilityDialog *editor );
+static void     on_ok_clicked( GtkButton *button, NactAddCapabilityDialog *editor );
+static void     on_selection_changed( GtkTreeSelection *selection, BaseWindow *window );
+static void     display_keyword( GtkTreeViewColumn *column, GtkCellRenderer *cell, GtkTreeModel *model, GtkTreeIter *iter, BaseWindow *window );
+static void     display_description( GtkTreeViewColumn *column, GtkCellRenderer *cell, GtkTreeModel *model, GtkTreeIter *iter, BaseWindow *window );
+static void     display_label( GtkTreeViewColumn *column, GtkCellRenderer *cell, GtkTreeModel *model, GtkTreeIter *iter, BaseWindow *window, guint column_id );
+static gboolean setup_values_iter( GtkTreeModel *model, GtkTreePath *path, GtkTreeIter* iter, GSList *capabilities );
+static void     validate_dialog( NactAddCapabilityDialog *editor );
+static gboolean base_dialog_response( GtkDialog *dialog, gint code, BaseWindow *window );
+
+GType
+nact_add_capability_dialog_get_type( void )
+{
+	static GType dialog_type = 0;
+
+	if( !dialog_type ){
+		dialog_type = register_type();
+	}
+
+	return( dialog_type );
+}
+
+static GType
+register_type( void )
+{
+	static const gchar *thisfn = "nact_add_capability_dialog_register_type";
+	GType type;
+
+	static GTypeInfo info = {
+		sizeof( NactAddCapabilityDialogClass ),
+		( GBaseInitFunc ) NULL,
+		( GBaseFinalizeFunc ) NULL,
+		( GClassInitFunc ) class_init,
+		NULL,
+		NULL,
+		sizeof( NactAddCapabilityDialog ),
+		0,
+		( GInstanceInitFunc ) instance_init
+	};
+
+	g_debug( "%s", thisfn );
+
+	type = g_type_register_static( BASE_DIALOG_TYPE, "NactAddCapabilityDialog", &info, 0 );
+
+	return( type );
+}
+
+static void
+class_init( NactAddCapabilityDialogClass *klass )
+{
+	static const gchar *thisfn = "nact_add_capability_dialog_class_init";
+	GObjectClass *object_class;
+	BaseWindowClass *base_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( NactAddCapabilityDialogClassPrivate, 1 );
+
+	base_class = BASE_WINDOW_CLASS( klass );
+	base_class->dialog_response = base_dialog_response;
+	base_class->get_toplevel_name = base_get_dialog_name;
+	base_class->get_iprefs_window_id = base_get_iprefs_window_id;
+	base_class->get_ui_filename = base_get_ui_filename;
+}
+
+static void
+instance_init( GTypeInstance *instance, gpointer klass )
+{
+	static const gchar *thisfn = "nact_add_capability_dialog_instance_init";
+	NactAddCapabilityDialog *self;
+
+	g_return_if_fail( NACT_IS_ADD_CAPABILITY_DIALOG( instance ));
+	g_debug( "%s: instance=%p, klass=%p", thisfn, ( void * ) instance, ( void * ) klass );
+	self = NACT_ADD_CAPABILITY_DIALOG( instance );
+
+	self->private = g_new0( NactAddCapabilityDialogPrivate, 1 );
+
+	base_window_signal_connect(
+			BASE_WINDOW( instance ),
+			G_OBJECT( instance ),
+			BASE_WINDOW_SIGNAL_INITIAL_LOAD,
+			G_CALLBACK( on_base_initial_load_dialog ));
+
+	base_window_signal_connect(
+			BASE_WINDOW( instance ),
+			G_OBJECT( instance ),
+			BASE_WINDOW_SIGNAL_RUNTIME_INIT,
+			G_CALLBACK( on_base_runtime_init_dialog ));
+
+	base_window_signal_connect(
+			BASE_WINDOW( instance ),
+			G_OBJECT( instance ),
+			BASE_WINDOW_SIGNAL_ALL_WIDGETS_SHOWED,
+			G_CALLBACK( on_base_all_widgets_showed));
+
+	self->private->dispose_has_run = FALSE;
+	self->private->capability = NULL;
+}
+
+static void
+instance_dispose( GObject *dialog )
+{
+	static const gchar *thisfn = "nact_add_capability_dialog_instance_dispose";
+	NactAddCapabilityDialog *self;
+	GtkTreeView *listview;
+	GtkTreeModel *model;
+	GtkTreeSelection *selection;
+
+	g_return_if_fail( NACT_IS_ADD_CAPABILITY_DIALOG( dialog ));
+	g_debug( "%s: dialog=%p", thisfn, ( void * ) dialog );
+	self = NACT_ADD_CAPABILITY_DIALOG( dialog );
+
+	if( !self->private->dispose_has_run ){
+
+		self->private->dispose_has_run = TRUE;
+
+		listview = GTK_TREE_VIEW( base_window_get_widget( BASE_WINDOW( dialog ), "CapabilitiesTreeView" ));
+		model = gtk_tree_view_get_model( listview );
+		selection = gtk_tree_view_get_selection( listview );
+		gtk_tree_selection_unselect_all( selection );
+		gtk_list_store_clear( GTK_LIST_STORE( model ));
+
+		/* chain up to the parent class */
+		if( G_OBJECT_CLASS( st_parent_class )->dispose ){
+			G_OBJECT_CLASS( st_parent_class )->dispose( dialog );
+		}
+	}
+}
+
+static void
+instance_finalize( GObject *dialog )
+{
+	static const gchar *thisfn = "nact_add_capability_dialog_instance_finalize";
+	NactAddCapabilityDialog *self;
+
+	g_return_if_fail( NACT_IS_ADD_CAPABILITY_DIALOG( dialog ));
+	g_debug( "%s: dialog=%p", thisfn, ( void * ) dialog );
+	self = NACT_ADD_CAPABILITY_DIALOG( dialog );
+
+	na_core_utils_slist_free( self->private->already_used );
+	g_free( self->private->capability );
+
+	g_free( self->private );
+
+	/* chain call to parent class */
+	if( G_OBJECT_CLASS( st_parent_class )->finalize ){
+		G_OBJECT_CLASS( st_parent_class )->finalize( dialog );
+	}
+}
+
+/*
+ * Returns a newly allocated NactAddCapabilityDialog object.
+ *
+ * @parent: the BaseWindow parent of this dialog (usually, the main
+ * toplevel window of the application).
+ */
+static NactAddCapabilityDialog *
+add_capability_dialog_new( BaseWindow *parent )
+{
+	return( g_object_new( NACT_ADD_CAPABILITY_DIALOG_TYPE, BASE_WINDOW_PROP_PARENT, parent, NULL ));
+}
+
+/**
+ * nact_add_capability_dialog_run:
+ * @parent: the BaseWindow parent of this dialog
+ *  (usually the NactMainWindow).
+ * @capabilities: list of already used capabilities.
+ *
+ * Initializes and runs the dialog.
+ *
+ * Returns: the selected capability, as a newly allocated string which should
+ * be g_free() by the caller, or NULL.
+ */
+gchar *
+nact_add_capability_dialog_run( BaseWindow *parent, GSList *capabilities )
+{
+	static const gchar *thisfn = "nact_add_capability_dialog_run";
+	NactAddCapabilityDialog *dialog;
+	gchar *capability;
+
+	g_debug( "%s: parent=%p", thisfn, ( void * ) parent );
+
+	g_return_val_if_fail( BASE_IS_WINDOW( parent ), NULL );
+
+	dialog = add_capability_dialog_new( parent );
+	dialog->private->already_used = na_core_utils_slist_duplicate( capabilities );
+
+	base_window_run( BASE_WINDOW( dialog ));
+
+	capability = g_strdup( dialog->private->capability );
+
+	g_object_unref( dialog );
+
+	return( capability );
+}
+
+static gchar *
+base_get_iprefs_window_id( const BaseWindow *window )
+{
+	return( g_strdup( "add-capability-dialog" ));
+}
+
+static gchar *
+base_get_dialog_name( const BaseWindow *window )
+{
+	return( g_strdup( "AddCapabilityDialog" ));
+}
+
+static gchar *
+base_get_ui_filename( const BaseWindow *dialog )
+{
+	return( g_strdup( PKGDATADIR "/nact-add-capability.ui" ));
+}
+
+static void
+on_base_initial_load_dialog( NactAddCapabilityDialog *dialog, gpointer user_data )
+{
+	static const gchar *thisfn = "nact_add_capability_dialog_on_initial_load_dialog";
+	GtkTreeView *listview;
+	GtkTreeModel *model;
+	GtkTreeViewColumn *column;
+	GtkCellRenderer *text_cell;
+	GtkTreeSelection *selection;
+
+	g_return_if_fail( NACT_IS_ADD_CAPABILITY_DIALOG( dialog ));
+
+	if( !dialog->private->dispose_has_run ){
+		g_debug( "%s: dialog=%p, user_data=%p", thisfn, ( void * ) dialog, ( void * ) user_data );
+
+		listview = GTK_TREE_VIEW( base_window_get_widget( BASE_WINDOW( dialog ), "CapabilitiesTreeView" ));
+
+		model = GTK_TREE_MODEL( gtk_list_store_new( CAPABILITY_N_COLUMN, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_BOOLEAN ));
+		gtk_tree_view_set_model( listview, GTK_TREE_MODEL( model ));
+		g_object_unref( model );
+
+		text_cell = gtk_cell_renderer_text_new();
+		column = gtk_tree_view_column_new_with_attributes(
+				"capability-keyword",
+				text_cell,
+				"text", CAPABILITY_KEYWORD_COLUMN,
+				NULL );
+		gtk_tree_view_append_column( listview, column );
+		gtk_tree_sortable_set_sort_column_id( GTK_TREE_SORTABLE( model ), CAPABILITY_KEYWORD_COLUMN, GTK_SORT_ASCENDING );
+		gtk_tree_view_column_set_cell_data_func(
+				column, text_cell, ( GtkTreeCellDataFunc ) display_keyword, dialog, NULL );
+
+		text_cell = gtk_cell_renderer_text_new();
+		column = gtk_tree_view_column_new_with_attributes(
+				"capability-description",
+				text_cell,
+				"text", CAPABILITY_DESC_COLUMN,
+				NULL );
+		gtk_tree_view_append_column( listview, column );
+		gtk_tree_view_column_set_cell_data_func(
+				column, text_cell, ( GtkTreeCellDataFunc ) display_description, dialog, NULL );
+
+		gtk_tree_view_set_headers_visible( listview, FALSE );
+
+		selection = gtk_tree_view_get_selection( listview );
+		gtk_tree_selection_set_mode( selection, GTK_SELECTION_BROWSE );
+	}
+}
+
+static void
+on_base_runtime_init_dialog( NactAddCapabilityDialog *dialog, gpointer user_data )
+{
+	static const gchar *thisfn = "nact_add_capability_dialog_on_runtime_init_dialog";
+	GtkTreeView *listview;
+	GtkListStore *model;
+	GtkTreeIter row;
+	guint i;
+
+	g_return_if_fail( NACT_IS_ADD_CAPABILITY_DIALOG( dialog ));
+
+	if( !dialog->private->dispose_has_run ){
+		g_debug( "%s: dialog=%p, user_data=%p", thisfn, ( void * ) dialog, ( void * ) user_data );
+
+		listview = GTK_TREE_VIEW( base_window_get_widget( BASE_WINDOW( dialog ), "CapabilitiesTreeView" ));
+		model = GTK_LIST_STORE( gtk_tree_view_get_model( listview ));
+
+		for( i = 0 ; st_caps[i].keyword ; i = i+1 ){
+			gtk_list_store_append( model, &row );
+			gtk_list_store_set( model, &row,
+					CAPABILITY_KEYWORD_COLUMN, st_caps[i].keyword,
+					CAPABILITY_DESC_COLUMN, st_caps[i].desc,
+					CAPABILITY_ALREADY_USED_COLUMN, FALSE,
+					-1 );
+		}
+
+		gtk_tree_model_foreach( GTK_TREE_MODEL( model ), ( GtkTreeModelForeachFunc ) setup_values_iter, dialog->private->already_used );
+
+		base_window_signal_connect(
+				BASE_WINDOW( dialog ),
+				G_OBJECT( gtk_tree_view_get_selection( listview )),
+				"changed",
+				G_CALLBACK( on_selection_changed ));
+
+		base_window_signal_connect_by_name(
+				BASE_WINDOW( dialog ),
+				"CancelButton",
+				"clicked",
+				G_CALLBACK( on_cancel_clicked ));
+
+		base_window_signal_connect_by_name(
+				BASE_WINDOW( dialog ),
+				"OKButton",
+				"clicked",
+				G_CALLBACK( on_ok_clicked ));
+	}
+}
+
+static void
+on_base_all_widgets_showed( NactAddCapabilityDialog *dialog, gpointer user_data )
+{
+	static const gchar *thisfn = "nact_add_capability_dialog_on_all_widgets_showed";
+	GtkTreeView *listview;
+	GtkTreePath *path;
+	GtkTreeSelection *selection;
+
+	g_return_if_fail( NACT_IS_ADD_CAPABILITY_DIALOG( dialog ));
+
+	if( !dialog->private->dispose_has_run ){
+
+		g_debug( "%s: dialog=%p, user_data=%p", thisfn, ( void * ) dialog, ( void * ) user_data );
+
+		listview = GTK_TREE_VIEW( base_window_get_widget( BASE_WINDOW( dialog ), "CapabilitiesTreeView" ));
+		path = gtk_tree_path_new_first();
+		selection = gtk_tree_view_get_selection( listview );
+		gtk_tree_selection_select_path( selection, path );
+		gtk_tree_path_free( path );
+	}
+}
+
+static void
+on_cancel_clicked( GtkButton *button, NactAddCapabilityDialog *dialog )
+{
+	GtkWindow *toplevel = base_window_get_toplevel( BASE_WINDOW( dialog ));
+
+	gtk_dialog_response( GTK_DIALOG( toplevel ), GTK_RESPONSE_CLOSE );
+}
+
+static void
+on_ok_clicked( GtkButton *button, NactAddCapabilityDialog *dialog )
+{
+	GtkWindow *toplevel = base_window_get_toplevel( BASE_WINDOW( dialog ));
+
+	gtk_dialog_response( GTK_DIALOG( toplevel ), GTK_RESPONSE_OK );
+}
+
+static void
+on_selection_changed( GtkTreeSelection *selection, BaseWindow *window )
+{
+	GList *rows;
+	GtkTreeModel *model;
+	GtkTreePath *path;
+	GtkTreeIter iter;
+	gboolean used;
+	GtkWidget *button;
+
+	rows = gtk_tree_selection_get_selected_rows( selection, &model );
+	used = FALSE;
+
+	if( g_list_length( rows ) == 1 ){
+		path = ( GtkTreePath * ) rows->data;
+		gtk_tree_model_get_iter( model, &iter, path );
+		gtk_tree_model_get( model, &iter, CAPABILITY_ALREADY_USED_COLUMN, &used, -1 );
+	}
+
+	button = base_window_get_widget( window, "OKButton" );
+	gtk_widget_set_sensitive( button, !used );
+}
+
+static void
+display_keyword( GtkTreeViewColumn *column, GtkCellRenderer *cell, GtkTreeModel *model, GtkTreeIter *iter, BaseWindow *window )
+{
+	display_label( column, cell, model, iter, window, CAPABILITY_KEYWORD_COLUMN );
+}
+
+static void
+display_description( GtkTreeViewColumn *column, GtkCellRenderer *cell, GtkTreeModel *model, GtkTreeIter *iter, BaseWindow *window )
+{
+	display_label( column, cell, model, iter, window, CAPABILITY_DESC_COLUMN );
+}
+
+static void
+display_label( GtkTreeViewColumn *column, GtkCellRenderer *cell, GtkTreeModel *model, GtkTreeIter *iter, BaseWindow *window, guint column_id )
+{
+	gboolean used;
+
+	gtk_tree_model_get( model, iter, CAPABILITY_ALREADY_USED_COLUMN, &used, -1 );
+	g_object_set( cell, "style-set", FALSE, NULL );
+
+	if( used ){
+		g_object_set( cell, "style", PANGO_STYLE_ITALIC, "style-set", TRUE, NULL );
+	}
+}
+
+static gboolean
+setup_values_iter( GtkTreeModel *model, GtkTreePath *path, GtkTreeIter* iter, GSList *capabilities )
+{
+	gchar *keyword;
+	gchar *description, *new_description;
+
+	gtk_tree_model_get( model, iter, CAPABILITY_KEYWORD_COLUMN, &keyword, CAPABILITY_DESC_COLUMN, &description, -1 );
+
+	if( na_core_utils_slist_find_negated( capabilities, keyword )){
+		/* i18n: add a comment when a capability is already used by current item */
+		new_description = g_strdup_printf( _( "%s (already used)"), description );
+		gtk_list_store_set( GTK_LIST_STORE( model ), iter, CAPABILITY_DESC_COLUMN, new_description, CAPABILITY_ALREADY_USED_COLUMN, TRUE, -1 );
+		g_free( new_description );
+	}
+
+	g_free( description );
+	g_free( keyword );
+
+	return( FALSE ); /* don't stop looping */
+}
+
+static void
+validate_dialog( NactAddCapabilityDialog *dialog )
+{
+	GtkTreeView *listview;
+	GtkTreeSelection *selection;
+	GtkTreeModel *model;
+	GList *rows;
+	GtkTreePath *path;
+	GtkTreeIter iter;
+
+	listview = GTK_TREE_VIEW( base_window_get_widget( BASE_WINDOW( dialog ), "CapabilitiesTreeView" ));
+	selection = gtk_tree_view_get_selection( listview );
+	rows = gtk_tree_selection_get_selected_rows( selection, &model );
+
+	if( g_list_length( rows ) == 1 ){
+		path = ( GtkTreePath * ) rows->data;
+		gtk_tree_model_get_iter( model, &iter, path );
+		gtk_tree_model_get( model, &iter, CAPABILITY_KEYWORD_COLUMN, &dialog->private->capability, -1 );
+	}
+}
+
+static gboolean
+base_dialog_response( GtkDialog *dialog_box, gint code, BaseWindow *window )
+{
+	static const gchar *thisfn = "nact_add_capability_dialog_on_dialog_response";
+	NactAddCapabilityDialog *dialog;
+
+	g_return_val_if_fail( NACT_IS_ADD_CAPABILITY_DIALOG( window ), FALSE );
+
+	dialog = NACT_ADD_CAPABILITY_DIALOG( window );
+
+	if( !dialog->private->dispose_has_run ){
+		g_debug( "%s: dialog_box=%p, code=%d, window=%p", thisfn, ( void * ) dialog_box, code, ( void * ) window );
+
+		switch( code ){
+			case GTK_RESPONSE_OK:
+				validate_dialog( dialog );
+
+			case GTK_RESPONSE_NONE:
+			case GTK_RESPONSE_DELETE_EVENT:
+			case GTK_RESPONSE_CLOSE:
+			case GTK_RESPONSE_CANCEL:
+				return( TRUE );
+				break;
+		}
+	}
+
+	return( FALSE );
+}
diff --git a/src/nact/nact-add-capability-dialog.h b/src/nact/nact-add-capability-dialog.h
new file mode 100644
index 0000000..54c7684
--- /dev/null
+++ b/src/nact/nact-add-capability-dialog.h
@@ -0,0 +1,76 @@
+/*
+ * 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)
+ */
+
+#ifndef __NACT_ADD_CAPABILITY_DIALOG_H__
+#define __NACT_ADD_CAPABILITY_DIALOG_H__
+
+/**
+ * SECTION: nact_add_capability_dialog
+ * @short_description: #NactAddCapabilityDialog class definition.
+ * @include: nact/nact-add-capability-dialog.h
+ *
+ * The dialog let the user pick a capability from the default list
+ * when adding a new capability to a profile (resp. an action, a menu).
+ */
+
+#include "base-dialog.h"
+
+G_BEGIN_DECLS
+
+#define NACT_ADD_CAPABILITY_DIALOG_TYPE					( nact_add_capability_dialog_get_type())
+#define NACT_ADD_CAPABILITY_DIALOG( object )			( G_TYPE_CHECK_INSTANCE_CAST( object, NACT_ADD_CAPABILITY_DIALOG_TYPE, NactAddCapabilityDialog ))
+#define NACT_ADD_CAPABILITY_DIALOG_CLASS( klass )		( G_TYPE_CHECK_CLASS_CAST( klass, NACT_ADD_CAPABILITY_DIALOG_TYPE, NactAddCapabilityDialogClass ))
+#define NACT_IS_ADD_CAPABILITY_DIALOG( object )			( G_TYPE_CHECK_INSTANCE_TYPE( object, NACT_ADD_CAPABILITY_DIALOG_TYPE ))
+#define NACT_IS_ADD_CAPABILITY_DIALOG_CLASS( klass )	( G_TYPE_CHECK_CLASS_TYPE(( klass ), NACT_ADD_CAPABILITY_DIALOG_TYPE ))
+#define NACT_ADD_CAPABILITY_DIALOG_GET_CLASS( object )	( G_TYPE_INSTANCE_GET_CLASS(( object ), NACT_ADD_CAPABILITY_DIALOG_TYPE, NactAddCapabilityDialogClass ))
+
+typedef struct NactAddCapabilityDialogPrivate      NactAddCapabilityDialogPrivate;
+
+typedef struct {
+	BaseDialog                      parent;
+	NactAddCapabilityDialogPrivate *private;
+}
+	NactAddCapabilityDialog;
+
+typedef struct NactAddCapabilityDialogClassPrivate NactAddCapabilityDialogClassPrivate;
+
+typedef struct {
+	BaseDialogClass                      parent;
+	NactAddCapabilityDialogClassPrivate *private;
+}
+	NactAddCapabilityDialogClass;
+
+GType  nact_add_capability_dialog_get_type( void );
+
+gchar *nact_add_capability_dialog_run( BaseWindow *parent, GSList *capabilities );
+
+G_END_DECLS
+
+#endif /* __NACT_ADD_CAPABILITY_DIALOG_H__ */
diff --git a/src/nact/nact-add-capability.ui b/src/nact/nact-add-capability.ui
new file mode 100644
index 0000000..fe3d311
--- /dev/null
+++ b/src/nact/nact-add-capability.ui
@@ -0,0 +1,145 @@
+<?xml version="1.0"?>
+<interface>
+  <!-- interface-requires gtk+ 2.12 -->
+  <!-- interface-naming-policy toplevel-contextual -->
+  <object class="GtkDialog" id="AddCapabilityDialog">
+    <property name="border_width">5</property>
+    <property name="title" translatable="yes">Adding a new scheme</property>
+    <property name="modal">True</property>
+    <property name="type_hint">dialog</property>
+    <property name="has_separator">False</property>
+    <child internal-child="vbox">
+      <object class="GtkVBox" id="dialog-vbox1">
+        <property name="visible">True</property>
+        <property name="orientation">vertical</property>
+        <property name="spacing">2</property>
+        <child>
+          <object class="GtkFrame" id="frame1">
+            <property name="visible">True</property>
+            <property name="border_width">6</property>
+            <property name="label_xalign">0</property>
+            <property name="shadow_type">in</property>
+            <child>
+              <object class="GtkAlignment" id="alignment1">
+                <property name="visible">True</property>
+                <property name="top_padding">6</property>
+                <property name="bottom_padding">6</property>
+                <property name="left_padding">12</property>
+                <property name="right_padding">6</property>
+                <child>
+                  <object class="GtkVBox" id="vbox1">
+                    <property name="visible">True</property>
+                    <property name="orientation">vertical</property>
+                    <property name="spacing">6</property>
+                    <child>
+                      <object class="GtkHBox" id="hbox1">
+                        <property name="visible">True</property>
+                        <property name="spacing">6</property>
+                        <child>
+                          <object class="GtkScrolledWindow" id="scrolledwindow1">
+                            <property name="visible">True</property>
+                            <property name="can_focus">True</property>
+                            <property name="hscrollbar_policy">automatic</property>
+                            <property name="vscrollbar_policy">automatic</property>
+                            <property name="shadow_type">in</property>
+                            <child>
+                              <object class="GtkTreeView" id="CapabilitiesTreeView">
+                                <property name="visible">True</property>
+                                <property name="can_focus">True</property>
+                                <property name="enable_search">False</property>
+                                <property name="show_expanders">False</property>
+                              </object>
+                            </child>
+                          </object>
+                          <packing>
+                            <property name="position">0</property>
+                          </packing>
+                        </child>
+                        <child>
+                          <object class="GtkVBox" id="vbox2">
+                            <property name="visible">True</property>
+                            <property name="orientation">vertical</property>
+                            <child>
+                              <placeholder/>
+                            </child>
+                            <child>
+                              <placeholder/>
+                            </child>
+                          </object>
+                          <packing>
+                            <property name="expand">False</property>
+                            <property name="position">1</property>
+                          </packing>
+                        </child>
+                      </object>
+                      <packing>
+                        <property name="position">0</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <placeholder/>
+                    </child>
+                  </object>
+                </child>
+              </object>
+            </child>
+            <child type="label">
+              <object class="GtkLabel" id="label1">
+                <property name="visible">True</property>
+                <property name="xpad">5</property>
+                <property name="label" translatable="yes">&lt;b&gt;Capabilities&lt;/b&gt;</property>
+                <property name="use_markup">True</property>
+              </object>
+            </child>
+          </object>
+          <packing>
+            <property name="position">1</property>
+          </packing>
+        </child>
+        <child internal-child="action_area">
+          <object class="GtkHButtonBox" id="dialog-action_area1">
+            <property name="visible">True</property>
+            <property name="layout_style">end</property>
+            <child>
+              <object class="GtkButton" id="CancelButton">
+                <property name="label">gtk-cancel</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">True</property>
+                <property name="use_stock">True</property>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">False</property>
+                <property name="position">0</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkButton" id="OKButton">
+                <property name="label">gtk-ok</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">True</property>
+                <property name="use_stock">True</property>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">False</property>
+                <property name="position">1</property>
+              </packing>
+            </child>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="pack_type">end</property>
+            <property name="position">0</property>
+          </packing>
+        </child>
+      </object>
+    </child>
+    <action-widgets>
+      <action-widget response="0">CancelButton</action-widget>
+      <action-widget response="0">OKButton</action-widget>
+    </action-widgets>
+  </object>
+</interface>
diff --git a/src/nact/nact-add-scheme.ui b/src/nact/nact-add-scheme.ui
index bbed867..46e1d3e 100644
--- a/src/nact/nact-add-scheme.ui
+++ b/src/nact/nact-add-scheme.ui
@@ -114,6 +114,7 @@
             <child type="label">
               <object class="GtkLabel" id="label1">
                 <property name="visible">True</property>
+                <property name="xpad">5</property>
                 <property name="label" translatable="yes">&lt;b&gt;Scheme&lt;/b&gt;</property>
                 <property name="use_markup">True</property>
               </object>
diff --git a/src/nact/nact-ibasenames-tab.c b/src/nact/nact-ibasenames-tab.c
index 24ba4f3..4fd6825 100644
--- a/src/nact/nact-ibasenames-tab.c
+++ b/src/nact/nact-ibasenames-tab.c
@@ -162,6 +162,7 @@ nact_ibasenames_tab_initial_load_toplevel( NactIBasenamesTab *instance )
 				( pget_filters ) get_basenames,
 				( pset_filters ) set_basenames,
 				NULL,
+				MATCH_LIST_MUST_MATCH_ONE_OF,
 				_( "Basename filter" ));
 	}
 }
diff --git a/src/nact/nact-icapabilities-tab.c b/src/nact/nact-icapabilities-tab.c
index 13be5a5..2f47ed5 100644
--- a/src/nact/nact-icapabilities-tab.c
+++ b/src/nact/nact-icapabilities-tab.c
@@ -40,6 +40,8 @@
 
 #include "nact-gtk-utils.h"
 #include "nact-main-tab.h"
+#include "nact-match-list.h"
+#include "nact-add-capability-dialog.h"
 #include "nact-icapabilities-tab.h"
 
 /* private interface data
@@ -70,6 +72,8 @@ static SelectionCountStruct st_counts[] = {
 		{ NULL }
 };
 
+#define ITAB_NAME						"capabilities"
+
 static gboolean st_initialized = FALSE;
 static gboolean st_finalized = FALSE;
 
@@ -82,8 +86,11 @@ static void         on_tab_updatable_selection_changed( NactICapabilitiesTab *in
 static void         on_tab_updatable_enable_tab( NactICapabilitiesTab *instance, NAObjectItem *item );
 static void         on_selcount_ope_changed( GtkComboBox *combo, NactICapabilitiesTab *instance );
 static void         on_selcount_int_changed( GtkEntry *entry, NactICapabilitiesTab *instance );
+static void         on_add_clicked( GtkButton *button, BaseWindow *window );
 static gboolean     tab_set_sensitive( NactICapabilitiesTab *instance );
 static GtkTreeView *get_capabilities_tree_view( NactICapabilitiesTab *instance );
+static GSList      *get_capabilities( NAIContext *context );
+static void         set_capabilities( NAIContext *context, GSList *list );
 static void         init_count_combobox( NactICapabilitiesTab *instance );
 static void         set_selection_count_selection( NactICapabilitiesTab *instance, const gchar *ope, const gchar *uint );
 static gchar       *get_selection_count_selection( NactICapabilitiesTab *instance );
@@ -162,6 +169,7 @@ void
 nact_icapabilities_tab_initial_load_toplevel( NactICapabilitiesTab *instance )
 {
 	static const gchar *thisfn = "nact_icapabilities_tab_initial_load_toplevel";
+	GtkWidget *list, *add, *remove;
 
 	g_return_if_fail( NACT_IS_ICAPABILITIES_TAB( instance ));
 
@@ -170,6 +178,19 @@ nact_icapabilities_tab_initial_load_toplevel( NactICapabilitiesTab *instance )
 		g_debug( "%s: instance=%p", thisfn, ( void * ) instance );
 
 		init_count_combobox( instance );
+
+		list = base_window_get_widget( BASE_WINDOW( instance ), "CapabilitiesTreeView" );
+		add = base_window_get_widget( BASE_WINDOW( instance ), "AddCapabilityButton" );
+		remove = base_window_get_widget( BASE_WINDOW( instance ), "RemoveCapabilityButton" );
+
+		nact_match_list_create_model( BASE_WINDOW( instance ),
+				ITAB_NAME, TAB_CAPABILITIES,
+				list, add, remove,
+				( pget_filters ) get_capabilities,
+				( pset_filters ) set_capabilities,
+				( pon_add_cb ) on_add_clicked,
+				MATCH_LIST_MUST_MATCH_ALL_OF,
+				_( "Capability filter" ));
 	}
 }
 
@@ -186,6 +207,7 @@ nact_icapabilities_tab_runtime_init_toplevel( NactICapabilitiesTab *instance )
 		g_debug( "%s: instance=%p", thisfn, ( void * ) instance );
 
 		listview = get_capabilities_tree_view( instance );
+		nact_match_list_init_view( BASE_WINDOW( instance ), ITAB_NAME );
 		runtime_init_connect_signals( instance, listview );
 	}
 }
@@ -254,6 +276,7 @@ nact_icapabilities_tab_dispose( NactICapabilitiesTab *instance )
 		g_debug( "%s: instance=%p", thisfn, ( void * ) instance );
 
 		dispose_count_combobox( instance );
+		nact_match_list_dispose( BASE_WINDOW( instance ), ITAB_NAME );
 	}
 }
 
@@ -300,6 +323,7 @@ on_tab_updatable_selection_changed( NactICapabilitiesTab *instance, gint count_s
 		gtk_widget_set_sensitive( entry, context != NULL );
 		nact_gtk_utils_set_editable( GTK_OBJECT( entry ), editable );
 
+		nact_match_list_on_selection_changed( BASE_WINDOW( instance ), ITAB_NAME, count_selected );
 		tab_set_sensitive( instance );
 	}
 }
@@ -371,6 +395,35 @@ on_selcount_int_changed( GtkEntry *entry, NactICapabilitiesTab *instance )
 	}
 }
 
+static void
+on_add_clicked( GtkButton *button, BaseWindow *window )
+{
+	NAObjectItem *item;
+	NAObjectProfile *profile;
+	NAIContext *context;
+	GSList *capabilities;
+	gchar *new_cap;
+
+	g_object_get(
+			G_OBJECT( window ),
+			TAB_UPDATABLE_PROP_EDITED_ACTION, &item,
+			TAB_UPDATABLE_PROP_EDITED_PROFILE, &profile,
+			NULL );
+
+	context = ( profile ? NA_ICONTEXT( profile ) : ( NAIContext * ) item );
+
+	if( context ){
+		capabilities = na_object_get_capabilities( context );
+		new_cap = nact_add_capability_dialog_run( window, capabilities );
+		g_debug( "nact_icapabilities_tab_on_add_clicked: new_cap=%s", new_cap );
+
+		if( new_cap ){
+			nact_match_list_insert_row( window, ITAB_NAME, new_cap, FALSE, FALSE );
+			g_free( new_cap );
+		}
+	}
+}
+
 static gboolean
 tab_set_sensitive( NactICapabilitiesTab *instance )
 {
@@ -401,6 +454,18 @@ get_capabilities_tree_view( NactICapabilitiesTab *instance )
 	return( GTK_TREE_VIEW( treeview ));
 }
 
+static GSList *
+get_capabilities( NAIContext *context )
+{
+	return( na_object_get_capabilities( context ));
+}
+
+static void
+set_capabilities( NAIContext *context, GSList *list )
+{
+	na_object_set_capabilities( context, list );
+}
+
 static void
 init_count_combobox( NactICapabilitiesTab *instance )
 {
diff --git a/src/nact/nact-ifolders-tab.c b/src/nact/nact-ifolders-tab.c
index 40ac1a2..31cf815 100644
--- a/src/nact/nact-ifolders-tab.c
+++ b/src/nact/nact-ifolders-tab.c
@@ -167,6 +167,7 @@ nact_ifolders_tab_initial_load_toplevel( NactIFoldersTab *instance )
 				( pget_filters ) get_folders,
 				( pset_filters ) set_folders,
 				NULL,
+				MATCH_LIST_MUST_MATCH_ONE_OF,
 				_( "Folder filter" ));
 	}
 }
diff --git a/src/nact/nact-imimetypes-tab.c b/src/nact/nact-imimetypes-tab.c
index 92c14bb..376857e 100644
--- a/src/nact/nact-imimetypes-tab.c
+++ b/src/nact/nact-imimetypes-tab.c
@@ -160,6 +160,7 @@ nact_imimetypes_tab_initial_load_toplevel( NactIMimetypesTab *instance )
 				( pget_filters ) get_mimetypes,
 				( pset_filters ) set_mimetypes,
 				NULL,
+				MATCH_LIST_MUST_MATCH_ONE_OF,
 				_( "Mimetype filter" ));
 	}
 }
diff --git a/src/nact/nact-ischemes-tab.c b/src/nact/nact-ischemes-tab.c
index 9cda0f9..ab9e56d 100644
--- a/src/nact/nact-ischemes-tab.c
+++ b/src/nact/nact-ischemes-tab.c
@@ -157,6 +157,7 @@ nact_ischemes_tab_initial_load_toplevel( NactISchemesTab *instance )
 				( pget_filters ) get_schemes,
 				( pset_filters ) set_schemes,
 				NULL,
+				MATCH_LIST_MUST_MATCH_ONE_OF,
 				_( "Scheme filter" ));
 	}
 }
diff --git a/src/nact/nact-match-list.c b/src/nact/nact-match-list.c
index ed45949..ad6d5a1 100644
--- a/src/nact/nact-match-list.c
+++ b/src/nact/nact-match-list.c
@@ -51,27 +51,42 @@ enum {
 	N_COLUMN
 };
 
+typedef struct {
+	guint  header_id;
+	gchar *header_label;
+}
+	ColumnHeaderStruct;
+
+/* i18n: label of the header of the column which let the user select a positive filter
+ */
+static ColumnHeaderStruct st_match_headers[] = {
+	{ MATCH_LIST_MUST_MATCH_ONE_OF, N_( "Must match one of" ) },
+	{ MATCH_LIST_MUST_MATCH_ALL_OF, N_( "Must match all of" ) },
+	{ 0 }
+};
+
 static gboolean st_on_selection_change = FALSE;
 
-static void     on_add_filter_clicked( GtkButton *button, MatchListStr *data );
-static void     on_filter_clicked( GtkTreeViewColumn *treeviewcolumn, MatchListStr *data );
-static void     on_filter_edited( GtkCellRendererText *renderer, const gchar *path, const gchar *text, MatchListStr *data );
-static gboolean on_key_pressed_event( GtkWidget *widget, GdkEventKey *event, MatchListStr *data );
-static void     on_must_match_clicked( GtkTreeViewColumn *treeviewcolumn, MatchListStr *data );
-static void     on_must_match_toggled( GtkCellRendererToggle *cell_renderer, gchar *path, MatchListStr *data );
-static void     on_must_not_match_clicked( GtkTreeViewColumn *treeviewcolumn, MatchListStr *data );
-static void     on_must_not_match_toggled( GtkCellRendererToggle *cell_renderer, gchar *path, MatchListStr *data );
-static void     on_remove_filter_clicked( GtkButton *button, MatchListStr *data );
-static void     on_selection_changed( GtkTreeSelection *selection, MatchListStr *data );
-
-static void     add_filter( MatchListStr *data, const gchar *filter, const gchar *prefix );
-static void     delete_current_row( MatchListStr *data );
-static void     edit_inline( MatchListStr *data );
-static void     insert_new_row( MatchListStr *data );
-static void     insert_new_row_data( MatchListStr *data, const gchar *filter, gboolean match, gboolean no_match );
-static void     iter_for_setup( gchar *filter, GtkTreeModel *model );
-static void     sort_on_column( GtkTreeViewColumn *treeviewcolumn, MatchListStr *data, guint colid );
-static gboolean tab_set_sensitive( MatchListStr *data );
+static void         on_add_filter_clicked( GtkButton *button, MatchListStr *data );
+static void         on_filter_clicked( GtkTreeViewColumn *treeviewcolumn, MatchListStr *data );
+static void         on_filter_edited( GtkCellRendererText *renderer, const gchar *path, const gchar *text, MatchListStr *data );
+static gboolean     on_key_pressed_event( GtkWidget *widget, GdkEventKey *event, MatchListStr *data );
+static void         on_must_match_clicked( GtkTreeViewColumn *treeviewcolumn, MatchListStr *data );
+static void         on_must_match_toggled( GtkCellRendererToggle *cell_renderer, gchar *path, MatchListStr *data );
+static void         on_must_not_match_clicked( GtkTreeViewColumn *treeviewcolumn, MatchListStr *data );
+static void         on_must_not_match_toggled( GtkCellRendererToggle *cell_renderer, gchar *path, MatchListStr *data );
+static void         on_remove_filter_clicked( GtkButton *button, MatchListStr *data );
+static void         on_selection_changed( GtkTreeSelection *selection, MatchListStr *data );
+
+static void         add_filter( MatchListStr *data, const gchar *filter, const gchar *prefix );
+static void         delete_current_row( MatchListStr *data );
+static void         edit_inline( MatchListStr *data );
+static const gchar *get_must_match_header( guint id );
+static void         insert_new_row( MatchListStr *data );
+static void         insert_new_row_data( MatchListStr *data, const gchar *filter, gboolean match, gboolean no_match );
+static void         iter_for_setup( gchar *filter, GtkTreeModel *model );
+static void         sort_on_column( GtkTreeViewColumn *treeviewcolumn, MatchListStr *data, guint colid );
+static gboolean     tab_set_sensitive( MatchListStr *data );
 
 /**
  * nact_match_list_create_model:
@@ -93,6 +108,7 @@ nact_match_list_create_model( BaseWindow *window,
 		const gchar *tab_name, guint tab_id,
 		GtkWidget *listview, GtkWidget *addbutton, GtkWidget *removebutton,
 		pget_filters pget, pset_filters pset, pon_add_cb pon_add,
+		guint match_header,
 		const gchar *item_header )
 {
 	MatchListStr *data;
@@ -110,6 +126,7 @@ nact_match_list_create_model( BaseWindow *window,
 	data->pget = pget;
 	data->pset = pset;
 	data->pon_add = pon_add;
+	data->match_header = match_header;
 	data->item_header = g_strdup( item_header );
 	data->editable = FALSE;
 	data->sort_column = 0;
@@ -131,9 +148,7 @@ nact_match_list_create_model( BaseWindow *window,
 	radio_cell = gtk_cell_renderer_toggle_new();
 	gtk_cell_renderer_toggle_set_radio( GTK_CELL_RENDERER_TOGGLE( radio_cell ), TRUE );
 	column = gtk_tree_view_column_new_with_attributes(
-			/* i18n: label of the header of a column which let the user select a positive filter
-			 */
-			_( "Must match one of" ),
+			get_must_match_header( match_header ),
 			radio_cell,
 			"active", MUST_MATCH_COLUMN,
 			NULL );
@@ -317,6 +332,7 @@ nact_match_list_on_selection_changed( BaseWindow *window, const gchar *tab_name,
 	context = ( profile ? NA_ICONTEXT( profile ) : ( NAIContext * ) item );
 	data->editable = editable;
 	filters = ( *data->pget )( context );
+	g_debug( "%s: filters=%p (count=%d)", thisfn, ( void * ) filters, filters ? g_slist_length( filters ) : -1 );
 
 	st_on_selection_change = TRUE;
 
@@ -326,6 +342,7 @@ nact_match_list_on_selection_changed( BaseWindow *window, const gchar *tab_name,
 	gtk_list_store_clear( GTK_LIST_STORE( model ));
 
 	if( filters ){
+		na_core_utils_slist_dump( filters );
 		g_slist_foreach( filters, ( GFunc ) iter_for_setup, model );
 	}
 
@@ -334,6 +351,7 @@ nact_match_list_on_selection_changed( BaseWindow *window, const gchar *tab_name,
 
 	nact_gtk_utils_set_editable( GTK_OBJECT( data->addbutton ), data->editable );
 	nact_gtk_utils_set_editable( GTK_OBJECT( data->removebutton ), data->editable );
+	gtk_widget_set_sensitive( data->removebutton, FALSE );
 
 	st_on_selection_change = FALSE;
 
@@ -762,6 +780,20 @@ edit_inline( MatchListStr *data )
 	g_list_free( rows );
 }
 
+static const gchar *
+get_must_match_header( guint id )
+{
+	guint i;
+
+	for( i = 0 ; st_match_headers[i].header_id ; ++i ){
+		if( st_match_headers[i].header_id == id ){
+			return( st_match_headers[i].header_label );
+		}
+	}
+
+	return( "" );
+}
+
 static void
 insert_new_row( MatchListStr *data )
 {
diff --git a/src/nact/nact-match-list.h b/src/nact/nact-match-list.h
index 078605a..2315c5e 100644
--- a/src/nact/nact-match-list.h
+++ b/src/nact/nact-match-list.h
@@ -43,7 +43,12 @@ G_BEGIN_DECLS
 
 typedef GSList * ( *pget_filters )( void * );
 typedef void     ( *pset_filters )( void *, GSList * );
-typedef gchar *  ( *pon_add_cb )  ( void *, BaseWindow * );
+typedef void     ( *pon_add_cb )  ( void *, BaseWindow * );
+
+enum {
+	MATCH_LIST_MUST_MATCH_ONE_OF = 1,
+	MATCH_LIST_MUST_MATCH_ALL_OF,
+};
 
 typedef struct {
 	BaseWindow      *window;
@@ -54,6 +59,7 @@ typedef struct {
 	pget_filters     pget;
 	pset_filters     pset;
 	pon_add_cb       pon_add;
+	guint            match_header;
 	gchar           *item_header;
 	gboolean         editable;
 	guint            sort_column;
@@ -65,6 +71,7 @@ void  nact_match_list_create_model        ( BaseWindow *window, const gchar *tab
 		guint tab_id,
 		GtkWidget *listview, GtkWidget *addbutton, GtkWidget *removebutton,
 		pget_filters pget, pset_filters pset, pon_add_cb pon_add,
+		guint match_header,
 		const gchar *item_header );
 
 void  nact_match_list_init_view           ( BaseWindow *window, const gchar *tab_name );
diff --git a/src/nact/nact-schemes-list.c b/src/nact/nact-schemes-list.c
index e8ec4b7..aee1373 100644
--- a/src/nact/nact-schemes-list.c
+++ b/src/nact/nact-schemes-list.c
@@ -357,15 +357,13 @@ setup_values_iter( GtkTreeModel *model, GtkTreePath *path, GtkTreeIter* iter, GS
 {
 	gchar *keyword;
 	gchar *description, *new_description;
-	gboolean used;
 
-	gtk_tree_model_get( model, iter, SCHEMES_KEYWORD_COLUMN, &keyword, SCHEMES_DESC_COLUMN, &description, SCHEMES_ALREADY_USED_COLUMN, &used, -1 );
+	gtk_tree_model_get( model, iter, SCHEMES_KEYWORD_COLUMN, &keyword, SCHEMES_DESC_COLUMN, &description, -1 );
 
 	if( na_core_utils_slist_find_negated( schemes, keyword )){
 		/* i18n: add a comment when a scheme is already used by current item */
 		new_description = g_strdup_printf( _( "%s (already used)"), description );
-		used = TRUE;
-		gtk_list_store_set( GTK_LIST_STORE( model ), iter, SCHEMES_DESC_COLUMN, new_description, SCHEMES_ALREADY_USED_COLUMN, used, -1 );
+		gtk_list_store_set( GTK_LIST_STORE( model ), iter, SCHEMES_DESC_COLUMN, new_description, SCHEMES_ALREADY_USED_COLUMN, TRUE, -1 );
 		g_free( new_description );
 	}
 



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]