[nautilus-actions] Review selection criteria



commit 9b839a67e5de85e175df4a864a706f5aa67b77e5
Author: Pierre Wieser <pwieser trychlos org>
Date:   Fri Jan 15 16:35:07 2010 +0100

    Review selection criteria
    
    Fix menu items sensitivity when provider is not writable or selection is multiple.

 ChangeLog                                  |   13 ++
 nautilus-actions/nact/nact-iactions-list.c |  152 +++++++++++------
 nautilus-actions/nact/nact-main-menubar.c  |  263 +++++++++++++++++++---------
 nautilus-actions/nact/nact-window.c        |   34 ++++-
 nautilus-actions/nact/nact-window.h        |    1 +
 5 files changed, 327 insertions(+), 136 deletions(-)
---
diff --git a/ChangeLog b/ChangeLog
index 52bddd3..e80b24e 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,16 @@
+2009-01-15 Pierre Wieser <pwieser trychlos org>
+
+	* nautilus-actions/nact/nact-iactions-list.c (filter_selection):
+	Review selection criteria, introducing implicit selection.
+
+	* nautilus-actions/nact/nact-main-menubar.c (on_update_sensitivities):
+	Review menu items sensitivity, especially when provider is not writable.
+	Enable new item even when selection is multiple.
+
+	* nautilus-actions/nact/nact-window.c:
+	* nautilus-actions/nact/nact-window.h (nact_window_is_writable_item):
+	New function.
+
 2009-01-05 Pierre Wieser <pwieser trychlos org>
 
 	* configure.ac: Bump version number.
diff --git a/nautilus-actions/nact/nact-iactions-list.c b/nautilus-actions/nact/nact-iactions-list.c
index 2ab917e..3a015e6 100644
--- a/nautilus-actions/nact/nact-iactions-list.c
+++ b/nautilus-actions/nact/nact-iactions-list.c
@@ -55,9 +55,7 @@ struct NactIActionsListInterfacePrivate {
 /* when iterating through a selection
  */
 typedef struct {
-	guint nb_profiles;
-	guint nb_actions;
-	guint nb_menus;
+	gboolean has_menu_or_action;
 }
 	SelectionIter;
 
@@ -86,7 +84,11 @@ static void     free_column_edited_callback( NactIActionsList *instance, NAObjec
 
 static void     display_label( GtkTreeViewColumn *column, GtkCellRenderer *cell, GtkTreeModel *model, GtkTreeIter *iter, NactIActionsList *instance );
 static gboolean filter_selection( GtkTreeSelection *selection, GtkTreeModel *model, GtkTreePath *path, gboolean path_currently_selected, NactIActionsList *instance );
+static gboolean filter_selection_is_homogeneous( GtkTreeSelection *selection, NAObject *object );
 static void     filter_selection_iter( GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, SelectionIter *str );
+static gboolean filter_selection_has_menu_or_action( GtkTreeSelection *selection );
+static gboolean filter_selection_is_implicitely_selected( NAObject *object );
+static void     filter_selection_set_implicitely_selected_childs( NAObject *object, gboolean select );
 static gboolean have_dnd_mode( NactIActionsList *instance, IActionsListInstanceData *ialid );
 static gboolean have_filter_selection_mode( NactIActionsList *instance, IActionsListInstanceData *ialid );
 static gboolean have_only_actions( NactIActionsList *instance, IActionsListInstanceData *ialid );
@@ -889,66 +891,95 @@ display_label( GtkTreeViewColumn *column, GtkCellRenderer *cell, GtkTreeModel *m
  * and to hope that this will be easily copyable anywhere after.
  * We know how to insert profiles, or how to insert actions or menus,
  * but not how nor where to insert e.g. a mix selection.
- * So the selection allows :
- * - only profiles, maybe from different actions
- * - or only actions or menus.
  *
- * Note that we do not allow here a selection to be made or not. What
- * we actually allow is only toggle the selection state. And so, we
- * only deal with "do we allow to toggle from non-selected ?"
+ * So a selection must first be homogeneous, i.e. it only contains
+ * explicitely selected profiles _or_ menus or actions (and their childs).
+ *
+ * To simplify the selection management while letting the user actually
+ * select almost anything, we are doing following assumptions:
+ * - when the user selects one row, all childs are also automatically
+ *   selected ; visible childs are setup so that they are known as
+ *   'indirectly' selected
+ * - when a row is set as 'indirectly' selected, user cannot select
+ *   nor unselect it (sort of readonly or mandatory implied selection)
+ *   while the parent stays itself selected
  */
 static gboolean
 filter_selection( GtkTreeSelection *selection, GtkTreeModel *model, GtkTreePath *path, gboolean path_currently_selected, NactIActionsList *instance )
 {
-	SelectionIter *str;
+	static const gchar *thisfn = "nact_iactions_list_filter_selection";
+	GList *selected_paths;
 	GtkTreeIter iter;
 	NAObject *object;
-	gboolean select_ok;
-
-	if( path_currently_selected ){
-		return( TRUE );
-	}
-
-	/* iter through the selection: does it contain profiles ? actions or
-	 * menus ? or both ?
-	 */
-	str = g_new0( SelectionIter, 1 );
-	str->nb_profiles = 0;
-	str->nb_actions = 0;
-	str->nb_menus = 0;
-
-	gtk_tree_selection_selected_foreach( selection, ( GtkTreeSelectionForeachFunc ) filter_selection_iter, str );
-
-	/* if there is not yet any selection, then anything is allowed
-	 */
-	if( str->nb_profiles + str->nb_actions + str->nb_menus == 0 ){
-		return( TRUE );
-	}
 
 	gtk_tree_model_get_iter( model, &iter, path );
 	gtk_tree_model_get( model, &iter, IACTIONS_LIST_NAOBJECT_COLUMN, &object, -1 );
-
 	g_return_val_if_fail( object, FALSE );
 	g_return_val_if_fail( NA_IS_OBJECT_ID( object ), FALSE );
 
-	select_ok = FALSE;
+	/* if there is not yet any selection, then anything is allowed
+	 */
+	selected_paths = gtk_tree_selection_get_selected_rows( selection, NULL );
+	if( !selected_paths || !g_list_length( selected_paths )){
+		/*g_debug( "%s: current selection is empty: allowing this one", thisfn );*/
+		filter_selection_set_implicitely_selected_childs( object, !path_currently_selected );
+		return( TRUE );
+	}
 
-	/* selecting a profile is only ok if a profile is already selected
+	/* if the object at the row is already 'implicitely' selected, i.e.
+	 * selected because of the selection of one of its parents, then
+	 * nothing is allowed
 	 */
-	if( NA_IS_OBJECT_PROFILE( object )){
-		select_ok = ( str->nb_actions + str->nb_menus == 0 );
+	if( filter_selection_is_implicitely_selected( object )){
+		g_debug( "%s: implicitely selected item: selection not allowed", thisfn );
+		g_object_unref( object );
+		return( FALSE );
 	}
 
-	/* selecting an action or a menu is only ok if no profile is selected
+	/* object at the row is not 'implicitely' selected: we may so select
+	 * or unselect it while the selection stays homogeneous
+	 * (rather we set its childs to the corresponding implied status)
 	 */
-	if( NA_IS_OBJECT_ITEM( object )){
-		select_ok = ( str->nb_profiles == 0 );
+	if( path_currently_selected ||
+		filter_selection_is_homogeneous( selection, object )){
+
+			filter_selection_set_implicitely_selected_childs( object, !path_currently_selected );
 	}
+	g_object_unref( object );
+	return( TRUE );
+}
 
+/*
+ * does the selection stay homogeneous when adding this object ?
+ */
+static gboolean
+filter_selection_is_homogeneous( GtkTreeSelection *selection, NAObject *object )
+{
+	gboolean homogeneous;
+
+	if( filter_selection_has_menu_or_action( selection )){
+		homogeneous = !NA_IS_OBJECT_PROFILE( object );
+	} else {
+		homogeneous = NA_IS_OBJECT_PROFILE( object );
+	}
+
+	return( homogeneous );
+}
+
+static gboolean
+filter_selection_has_menu_or_action( GtkTreeSelection *selection )
+{
+	gboolean has_menu_or_action;
+	SelectionIter *str;
+
+	has_menu_or_action = FALSE;
+	str = g_new0( SelectionIter, 1 );
+	str->has_menu_or_action = has_menu_or_action;
+	gtk_tree_selection_selected_foreach( selection, ( GtkTreeSelectionForeachFunc ) filter_selection_iter, str );
+	has_menu_or_action = str->has_menu_or_action;
 	g_free( str );
-	g_object_unref( object );
 
-	return( select_ok );
+	return( has_menu_or_action );
 }
 
 static void
@@ -958,20 +989,39 @@ filter_selection_iter( GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter
 
 	gtk_tree_model_get( model, iter, IACTIONS_LIST_NAOBJECT_COLUMN, &object, -1 );
 
-	g_return_if_fail( object );
-	g_return_if_fail( NA_IS_OBJECT_ID( object ));
+	if( NA_IS_OBJECT_ITEM( object )){
+		str->has_menu_or_action = TRUE;
+	}
 
-	if( NA_IS_OBJECT_PROFILE( object )){
-		str->nb_profiles += 1;
+	g_object_unref( object );
+}
 
-	} else if( NA_IS_OBJECT_ACTION( object )){
-		str->nb_actions += 1;
+static gboolean
+filter_selection_is_implicitely_selected( NAObject *object )
+{
+	gboolean selected;
 
-	} else if( NA_IS_OBJECT_MENU( object )){
-		str->nb_menus += 1;
-	}
+	selected = ( gboolean ) GPOINTER_TO_UINT( g_object_get_data( G_OBJECT( object), "nact-implicit-selection" ));
 
-	g_object_unref( object );
+	return( selected );
+}
+
+/*
+ * the object is being selected (resp. unselected)
+ * recursively set the 'implicit selection' flag for all its childs
+ */
+static void
+filter_selection_set_implicitely_selected_childs( NAObject *object, gboolean select )
+{
+	GList *childs, *ic;
+
+	if( NA_IS_OBJECT_ITEM( object )){
+		childs = na_object_get_items_list( object );
+		for( ic = childs ; ic ; ic = ic->next ){
+			g_object_set_data( G_OBJECT( ic->data ), "nact-implicit-selection", GUINT_TO_POINTER(( guint ) select ));
+			filter_selection_set_implicitely_selected_childs( NA_OBJECT( ic->data ), select );
+		}
+	}
 }
 
 static gboolean
diff --git a/nautilus-actions/nact/nact-main-menubar.c b/nautilus-actions/nact/nact-main-menubar.c
index 2d1be8d..6ba21f9 100644
--- a/nautilus-actions/nact/nact-main-menubar.c
+++ b/nautilus-actions/nact/nact-main-menubar.c
@@ -601,124 +601,219 @@ static void
 on_update_sensitivities( NactMainWindow *window, gpointer user_data )
 {
 	static const gchar *thisfn = "nact_main_menubar_on_update_sensitivities";
+	NactApplication *application;
+	NAPivot *pivot;
+	gboolean is_level_zero_writable;
+	gboolean has_writable_providers;
+	gboolean has_modified_items;
+	GList *selected_items, *is;
+	NAObject *first_parent;
+	gboolean is_first_parent_writable;
+	gboolean new_item_enabled;
+	gboolean new_profile_enabled;
+	NAObject *selected_action;
+	NAObject *parent_item;
 	MenubarIndicatorsStruct *mis;
-	NAObject *item;
-	NAObject *profile;
-	NAObject *selected_row;
-	gboolean has_modified;
-	gint count_list;
+	gboolean is_clipboard_empty;
 	gint count_selected;
+	gboolean are_parents_writable;
+	NAObject *selected_item;
 	gboolean cut_enabled;
 	gboolean copy_enabled;
 	gboolean paste_enabled;
 	gboolean paste_into_enabled;
 	gboolean duplicate_enabled;
 	gboolean delete_enabled;
-	gboolean clipboard_is_empty;
-	gboolean new_item_enabled;
-	gboolean readonly_item;
-	gboolean writable_provider;
-	gboolean writable_item;
-	gboolean has_writables;
-	NAObjectItem *parent;
-	gboolean writable_parent;
+	gint count_list;
 
-	g_debug( "%s: window=%p", thisfn, ( void * ) window );
+	g_debug( "%s: window=%p, user_data=%p", thisfn, ( void * ) window, ( void * ) user_data );
 	g_return_if_fail( NACT_IS_MAIN_WINDOW( window ));
 
-	mis = ( MenubarIndicatorsStruct * ) g_object_get_data( G_OBJECT( window ), MENUBAR_PROP_INDICATORS );
-	has_writables = nact_window_has_writable_providers( NACT_WINDOW( window ));
-	/*g_debug( "%s: has_writables=%s", thisfn, has_writables ? "True":"False" );*/
+	application = NACT_APPLICATION( base_window_get_application( BASE_WINDOW( window )));
+	pivot = nact_application_get_pivot( application );
+	is_level_zero_writable = na_pivot_is_level_zero_writable( pivot );
 
-	g_object_get(
-			G_OBJECT( window ),
-			TAB_UPDATABLE_PROP_EDITED_ACTION, &item,
-			TAB_UPDATABLE_PROP_EDITED_PROFILE, &profile,
-			TAB_UPDATABLE_PROP_SELECTED_ROW, &selected_row,
-			NULL );
-	g_return_if_fail( !item || NA_IS_OBJECT_ITEM( item ));
-	g_return_if_fail( !profile || NA_IS_OBJECT_PROFILE( profile ));
+	has_writable_providers = nact_window_has_writable_providers( NACT_WINDOW( window ));
+	has_modified_items = nact_main_window_has_modified_items( window );
 
-	has_modified = nact_main_window_has_modified_items( window );
-	readonly_item = item ? na_object_is_readonly( item ) : FALSE;
-	writable_provider = item ? nact_window_is_writable_provider( NACT_WINDOW( window ), NA_OBJECT_ITEM( item )) : FALSE;
-	writable_item = writable_provider && !readonly_item;
-
-	parent = item ? na_object_get_parent( item ) : NULL;
-	writable_parent = parent
-		? nact_window_is_writable_provider( NACT_WINDOW( window ), parent ) && !na_object_is_readonly( parent )
-		: FALSE;
-
-	/* new menu enabled if selection is a menu or an action
-	 * new action enabled if selection is a menu or an action
-	 * adding a new item requires that parent be writable
+	selected_items = nact_iactions_list_bis_get_selected_items( NACT_IACTIONS_LIST( window ));
+	first_parent = selected_items && g_list_length( selected_items )
+			? ( NAObject * ) na_object_get_parent( selected_items->data )
+			: NULL;
+	is_first_parent_writable = first_parent
+			? nact_window_is_writable_item( NACT_WINDOW( window ), NA_OBJECT_ID( first_parent ))
+			: is_level_zero_writable;
+
+	mis = ( MenubarIndicatorsStruct * ) g_object_get_data( G_OBJECT( window ), MENUBAR_PROP_INDICATORS );
+	is_clipboard_empty = ( mis->clipboard_menus + mis->clipboard_actions + mis->clipboard_profiles == 0 );
+	count_selected = mis->selected_menus + mis->selected_actions + mis->selected_profiles;
+	g_return_if_fail( selected_items == NULL || count_selected == g_list_length( selected_items ));
+
+	/* new menu / new action
+	 * new item will be inserted just before beginning of selection
+	 * parent of the first selected row must be writable
+	 * we must have at least one writable provider
 	 */
-	new_item_enabled = ( selected_row == NULL || NA_IS_OBJECT_ITEM( selected_row ));
-	new_item_enabled = new_item_enabled && has_writables;
-	new_item_enabled = new_item_enabled && ( parent ? writable_parent : TRUE );
+	new_item_enabled = is_first_parent_writable && has_writable_providers;
 	enable_item( window, "NewMenuItem", new_item_enabled );
 	enable_item( window, "NewActionItem", new_item_enabled );
 
-	/* new profile enabled if selection is relative to only one writable action */
+	/* new profile enabled if selection is relative to only one writable action
+	 * i.e. contains profile(s) of the same action, or only contains one action
+	 * action must be writable
+	 */
+	new_profile_enabled = TRUE;
+	selected_action = NULL;
+	for( is = selected_items ; is ; is = is->next ){
+
+		if( NA_IS_OBJECT_MENU( is->data )){
+			new_profile_enabled = FALSE;
+			break;
+
+		} else if( NA_IS_OBJECT_ACTION( is->data )){
+			if( !selected_action ){
+				selected_action = NA_OBJECT( is->data );
+			} else if( selected_action != is->data ){
+				new_profile_enabled = FALSE;
+				break;
+			}
+
+		} else if( NA_IS_OBJECT_PROFILE( is->data )){
+			parent_item = NA_OBJECT( na_object_get_parent( is->data ));
+			if( !selected_action ){
+				selected_action = parent_item;
+			} else if( selected_action != parent_item ){
+				new_profile_enabled = FALSE;
+				break;
+			}
+		}
+	}
 	enable_item( window, "NewProfileItem",
-			item != NULL && !NA_IS_OBJECT_MENU( item ) && writable_item );
+			new_profile_enabled &&
+			selected_action != NULL &&
+			nact_window_is_writable_item( NACT_WINDOW( window ), NA_OBJECT_ID( selected_action )));
 
-	/* save enabled if at least one item has been modified */
-	enable_item( window, "SaveItem", has_modified || mis->level_zero_order_changed );
+	/* save enabled if at least one item has been modified
+	 * or level-zero has been resorted and is writable
+	 */
+	enable_item( window, "SaveItem",
+			has_modified_items || ( mis->level_zero_order_changed && is_level_zero_writable ));
 
 	/* quit always enabled */
 
-	/* edit menu is only enabled when the treeview has the focus
+	/* cut requires a non-empty selection
+	 * and that all parents are writable (as implies a delete operation)
 	 */
+	cut_enabled = mis->treeview_has_focus || mis->popup_handler;
+	cut_enabled &= count_selected;
+	are_parents_writable = TRUE;
+	for( is = selected_items ; is ; is = is->next ){
+		parent_item = ( NAObject * ) na_object_get_parent( is->data );
+		if( parent_item ){
+			if( !nact_window_is_writable_item( NACT_WINDOW( window ), NA_OBJECT_ID( parent_item ))){
+				are_parents_writable = FALSE;
+				break;
+			}
+		} else if( !is_level_zero_writable ){
+			are_parents_writable = FALSE;
+			break;
+		}
+	}
+	cut_enabled &= are_parents_writable;
+	enable_item( window, "CutItem", cut_enabled );
 
-	clipboard_is_empty = ( mis->clipboard_menus + mis->clipboard_actions + mis->clipboard_profiles == 0 );
-	count_selected = mis->selected_menus + mis->selected_actions + mis->selected_profiles;
-
-	/* cut/copy/duplicate/delete enabled when selection not empty */
-	/* cut/delete require a writable item */
-	cut_enabled = ( mis->treeview_has_focus || mis->popup_handler ) && count_selected > 0 && writable_item && has_writables;
-	copy_enabled = ( mis->treeview_has_focus || mis->popup_handler ) && count_selected > 0 && has_writables;
-	duplicate_enabled = ( mis->treeview_has_focus || mis->popup_handler ) && count_selected > 0 && has_writables;
-	delete_enabled = ( mis->treeview_has_focus || mis->popup_handler ) && count_selected > 0 && writable_item;
+	/* copy only requires a non-empty selection */
+	copy_enabled = mis->treeview_has_focus || mis->popup_handler;
+	copy_enabled &= count_selected;
+	enable_item( window, "CopyItem", copy_enabled );
 
 	/* paste enabled if
-	 * - simple selection
-	 * - clipboard contains only profiles, and current selection is a profile
-	 * - clipboard contains actions or menus, and current selection is a menu or an action */
-	paste_enabled = FALSE;
-	if(( mis->treeview_has_focus || mis->popup_handler ) && count_selected <= 1 ){
-		if( !clipboard_is_empty ){
-			if( mis->clipboard_profiles ){
-				paste_enabled = item && NA_IS_OBJECT_ACTION( item ) && writable_item;
-			} else {
-				paste_enabled = ( item != NULL ) && has_writables && ( parent ? writable_parent : TRUE );
+	 * - clipboard is not empty
+	 * - current selection is not multiple
+	 * - if clipboard contains only profiles,
+	 *   then current selection must be a profile or an action
+	 *   and the action must be writable
+	 * - if clipboard contains actions or menus,
+	 *   then current selection (if any) must be a menu or an action
+	 *   and its parent must be writable
+	 */
+	paste_enabled = mis->treeview_has_focus || mis->popup_handler;
+	paste_enabled &= !is_clipboard_empty;
+	paste_enabled &= count_selected <= 1;
+	if( mis->clipboard_profiles ){
+		paste_enabled &= count_selected == 1;
+		if( paste_enabled ){
+			selected_action = NA_OBJECT(
+					NA_IS_OBJECT_PROFILE( selected_items->data )
+							? na_object_get_parent( selected_items->data )
+							: selected_items->data );
+			paste_enabled &= NA_IS_OBJECT_ACTION( selected_action );
+			paste_enabled &= nact_window_is_writable_item( NACT_WINDOW( window ), NA_OBJECT_ID( selected_action ));
+		}
+	} else {
+		paste_enabled &= has_writable_providers;
+		if( count_selected ){
+			selected_item = NA_OBJECT( selected_items->data );
+			paste_enabled &= NA_IS_OBJECT_ITEM( selected_item );
+			if( paste_enabled ){
+				parent_item = ( NAObject * ) na_object_get_parent( selected_item );
+				paste_enabled &= parent_item
+						? nact_window_is_writable_item( NACT_WINDOW( window ), NA_OBJECT_ID( parent_item ))
+						: is_level_zero_writable;
 			}
+		} else {
+			paste_enabled &= is_level_zero_writable;
 		}
 	}
+	enable_item( window, "PasteItem", paste_enabled );
 
 	/* paste into enabled if
-	 * - simple selection
-	 * - clipboard has profiles and current item is an action
-	 * - or current item is a menu
-	 * do not paste into if current selection is a profile */
-	paste_into_enabled = FALSE;
-	if(( mis->treeview_has_focus || mis->popup_handler ) && count_selected <= 1 ){
-		if( mis->selected_menus + mis->selected_actions ){
-			if( !clipboard_is_empty ){
-				if( mis->clipboard_profiles ){
-					paste_into_enabled = item && NA_IS_OBJECT_ACTION( item ) && writable_item;
-				} else {
-					paste_into_enabled = item && NA_IS_OBJECT_MENU( item ) && writable_item && has_writables;
-				}
+	 * - clipboard is not empty
+	 * - current selection is not multiple
+	 * - if clipboard contains only profiles,
+	 *   then current selection must be an action
+	 *   and the action must be writable
+	 * - if clipboard contains actions or menus,
+	 *   then current selection (if any) must be a menu
+	 *   and its parent must be writable
+	 */
+	paste_into_enabled = mis->treeview_has_focus || mis->popup_handler;
+	paste_into_enabled &= !is_clipboard_empty;
+	paste_into_enabled &= count_selected <= 1;
+	if( mis->clipboard_profiles ){
+		paste_enabled &= count_selected == 1;
+		if( paste_enabled ){
+			selected_action = NA_OBJECT( selected_items->data );
+			paste_enabled &= NA_IS_OBJECT_ACTION( selected_action );
+			paste_enabled &= nact_window_is_writable_item( NACT_WINDOW( window ), NA_OBJECT_ID( selected_action ));
+		}
+	} else {
+		paste_enabled &= has_writable_providers;
+		if( count_selected ){
+			selected_item = NA_OBJECT( selected_items->data );
+			paste_enabled &= NA_IS_OBJECT_MENU( selected_item );
+			if( paste_enabled ){
+				parent_item = ( NAObject * ) na_object_get_parent( selected_item );
+				paste_enabled &= parent_item
+						? nact_window_is_writable_item( NACT_WINDOW( window ), NA_OBJECT_ID( parent_item ))
+						: is_level_zero_writable;
 			}
+		} else {
+			paste_enabled &= is_level_zero_writable;
 		}
 	}
-
-	enable_item( window, "CutItem", cut_enabled );
-	enable_item( window, "CopyItem", copy_enabled );
-	enable_item( window, "PasteItem", paste_enabled );
 	enable_item( window, "PasteIntoItem", paste_into_enabled );
+
+	/* duplicate items will be duplicated besides each one
+	 * selection must be non-empty
+	 * each parent must be writable
+	 * -> so this is the same than cut
+	 */
+	duplicate_enabled = cut_enabled;
 	enable_item( window, "DuplicateItem", duplicate_enabled );
+
+	/* delete is same that cut */
+	delete_enabled = cut_enabled;
 	enable_item( window, "DeleteItem", delete_enabled );
 
 	/* reload items always enabled */
@@ -731,7 +826,7 @@ on_update_sensitivities( NactMainWindow *window, gpointer user_data )
 	enable_item( window, "CollapseAllItem", count_list > 0 );
 
 	/* import item enabled if at least one writable provider */
-	enable_item( window, "ImportItem", has_writables );
+	enable_item( window, "ImportItem", has_writable_providers );
 
 	/* export item enabled if IActionsList store contains actions */
 	enable_item( window, "ExportItem", mis->have_exportables );
@@ -740,6 +835,8 @@ on_update_sensitivities( NactMainWindow *window, gpointer user_data )
 	enable_item( window, "HelpItem", FALSE );
 
 	/* about always enabled */
+
+	na_object_free_items_list( selected_items );
 }
 
 static void
diff --git a/nautilus-actions/nact/nact-window.c b/nautilus-actions/nact/nact-window.c
index 9d7a28b..dada4d5 100644
--- a/nautilus-actions/nact/nact-window.c
+++ b/nautilus-actions/nact/nact-window.c
@@ -197,6 +197,36 @@ nact_window_get_pivot( NactWindow *window )
 }
 
 /**
+ * nact_window_is_writable_item:
+ * @window: this #NactWindow instance.
+ * @item: the item, which may be a profile, an action or a menu.
+ *
+ * Returns: %TRUE if the item is writable, %FALSE else.
+ */
+gboolean
+nact_window_is_writable_item( NactWindow *window, const NAObjectId *item )
+{
+	gboolean writable;
+	NAObjectItem *parent;
+
+	writable = FALSE;
+
+	g_return_val_if_fail( NACT_IS_WINDOW( window ), writable );
+	g_return_val_if_fail( NA_IS_OBJECT_ID( item ), writable );
+
+	if( !window->private->dispose_has_run ){
+
+		parent = NA_IS_OBJECT_PROFILE( item ) ? na_object_get_parent( item ) : NA_OBJECT_ITEM( item );
+
+		writable =
+				!na_object_is_readonly( parent ) &&
+				nact_window_is_writable_provider( window, parent );
+	}
+
+	return( writable );
+}
+
+/**
  * nact_window_is_writable_provider:
  * @window: this #NactWindow instance.
  * @item: the current item.
@@ -204,8 +234,8 @@ nact_window_get_pivot( NactWindow *window )
  * Returns: %TRUE if the item's provider is willing to write, %FALSE else.
  *
  * If the provider item has not yet any provider, i.e. has never been
- * saved elsewhere, then we return %FALSE, assuming that we eventually
- * find at least one willing-to-write provider.
+ * saved elsewhere, then we test if we have at least one
+ * willing-to-write provider.
  */
 gboolean
 nact_window_is_writable_provider( NactWindow *window, const NAObjectItem *item )
diff --git a/nautilus-actions/nact/nact-window.h b/nautilus-actions/nact/nact-window.h
index f586d5b..08bd506 100644
--- a/nautilus-actions/nact/nact-window.h
+++ b/nautilus-actions/nact/nact-window.h
@@ -75,6 +75,7 @@ GType    nact_window_get_type( void );
 
 NAPivot *nact_window_get_pivot( NactWindow *window );
 
+gboolean nact_window_is_writable_item( NactWindow *window, const NAObjectId *item );
 gboolean nact_window_is_writable_provider( NactWindow *window, const NAObjectItem *item );
 gboolean nact_window_has_writable_providers( NactWindow *window );
 



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