[nautilus-actions] Do not delete a tree which contains a readonly item



commit 755f8b1872a0e77da0ec23a341fd4c29582388f3
Author: Pierre Wieser <pwieser trychlos org>
Date:   Fri Mar 5 22:03:51 2010 +0100

    Do not delete a tree which contains a readonly item

 ChangeLog                    |   11 ++++
 TODO                         |    2 +
 src/api/na-core-utils.h      |    1 +
 src/core/na-core-utils.c     |   22 +++++++
 src/nact/nact-main-menubar.c |  126 ++++++++++++++++++++++++++++++++++++++---
 5 files changed, 152 insertions(+), 10 deletions(-)
---
diff --git a/ChangeLog b/ChangeLog
index e3672ab..b32e0d0 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,14 @@
+2009-03-05 Pierre Wieser <pwieser trychlos org>
+
+	* src/api/na-core-utils.h:
+	* src/core/na-core-utils.c
+	(na_core_utils_slist_join_at_end): New function.
+
+	* src/api/na-iio-provider.h: Fix typo in comment.
+
+	* src/nact/nact-main-menubar.c (on_delete_activated):
+	Do not delete a tree if at least one item is not writable.
+
 2009-03-04 Pierre Wieser <pwieser trychlos org>
 
 	* src/core/na-object-action.c (instance_init):
diff --git a/TODO b/TODO
index ca871cd..9194726 100644
--- a/TODO
+++ b/TODO
@@ -170,3 +170,5 @@
 - dnd to inside of a menu, by dropping while on the menu itself
   if menu is at path 3, we get a dest of 3:0 which means first child of parent at path 3
   if menu is new (never has been written), dnd says that parent is not writable ????
+
+- implement delete_rec in nact_main_menubar
diff --git a/src/api/na-core-utils.h b/src/api/na-core-utils.h
index f5f141c..50557b5 100644
--- a/src/api/na-core-utils.h
+++ b/src/api/na-core-utils.h
@@ -58,6 +58,7 @@ GSList  *na_core_utils_slist_duplicate( GSList *list );
 void     na_core_utils_slist_dump( GSList *list );
 GSList  *na_core_utils_slist_from_split( const gchar *string, const gchar *separator );
 GSList  *na_core_utils_slist_from_array( const gchar **str_array );
+gchar   *na_core_utils_slist_join_at_end( GSList *list, const gchar *link );
 GSList  *na_core_utils_slist_remove_ascii( GSList *list, const gchar *text );
 GSList  *na_core_utils_slist_remove_utf8( GSList *list, const gchar *string );
 gchar   *na_core_utils_slist_to_text( GSList *list );
diff --git a/src/core/na-core-utils.c b/src/core/na-core-utils.c
index 700e386..e3ca145 100644
--- a/src/core/na-core-utils.c
+++ b/src/core/na-core-utils.c
@@ -287,6 +287,28 @@ na_core_utils_slist_from_array( const gchar **str_array )
 }
 
 /**
+ * na_core_utils_slist_join_at_end:
+ * @slist: the string list to join.
+ * @link: the string used to join each element.
+ *
+ * Returns: a newly allocated string which should be g_free() by the caller.
+ */
+gchar *
+na_core_utils_slist_join_at_end( GSList *slist, const gchar *link )
+{
+	GSList *is;
+	GString *str;
+
+	str = g_string_new( "" );
+
+	for( is = slist ; is ; is = is->next ){
+		g_string_append_printf( str, "%s%s", ( const gchar * ) is->data, link );
+	}
+
+	return( g_string_free( str, FALSE ));
+}
+
+/**
  * na_core_utils_slist_remove_ascii:
  * @list: the GSList to be updated.
  * @text: string to remove.
diff --git a/src/nact/nact-main-menubar.c b/src/nact/nact-main-menubar.c
index 1b55a35..15d7871 100644
--- a/src/nact/nact-main-menubar.c
+++ b/src/nact/nact-main-menubar.c
@@ -35,6 +35,7 @@
 #include <glib/gi18n.h>
 
 #include <api/na-object-api.h>
+#include <api/na-core-utils.h>
 
 #include <core/na-factory-object.h>
 #include <core/na-iprefs.h>
@@ -105,6 +106,9 @@ static void     on_paste_into_activated( GtkAction *action, NactMainWindow *wind
 static GList   *prepare_for_paste( NactMainWindow *window );
 static void     on_duplicate_activated( GtkAction *action, NactMainWindow *window );
 static void     on_delete_activated( GtkAction *action, NactMainWindow *window );
+static GList   *get_deletables( NAUpdater *updater, GList *tree, GSList **not_deletable );
+static GSList  *get_deletables_rec( NAUpdater *updater, GList *tree );
+static gchar   *add_non_deletable_msg( const NAObjectItem *item, gint reason );
 static void     update_clipboard_counters( NactMainWindow *window );
 static void     on_reload_activated( GtkAction *action, NactMainWindow *window );
 static void     on_preferences_activated( GtkAction *action, NactMainWindow *window );
@@ -779,7 +783,10 @@ on_update_sensitivities( NactMainWindow *window, gpointer user_data )
 	duplicate_enabled = cut_enabled;
 	nact_main_menubar_enable_item( window, "DuplicateItem", duplicate_enabled );
 
-	/* delete is same that cut */
+	/* delete is same that cut
+	 * but items themselves must be writable (because physically deleted)
+	 * this will be checked on delete activated
+	 */
 	delete_enabled = cut_enabled;
 	nact_main_menubar_enable_item( window, "DeleteItem", delete_enabled );
 
@@ -1235,29 +1242,128 @@ on_duplicate_activated( GtkAction *gtk_action, NactMainWindow *window )
  * - (main) add selected items to main list of deleted,
  *          moving newref from list_from_tree to main_list_of_deleted
  * - (tree) select next row (if any, or previous if any, or none)
+ *
+ * note that we get from selection a list of trees, but we don't have
+ * yet ensured that each element of this tree is actually deletable
+ * each branch of this list must be recursively deletable in order
+ * this branch itself be deleted
  */
 static void
 on_delete_activated( GtkAction *gtk_action, NactMainWindow *window )
 {
 	static const gchar *thisfn = "nact_main_menubar_on_delete_activated";
+	NactApplication *application;
+	NAUpdater *updater;
 	GList *items;
-	GList *it;
+	GList *to_delete;
+	GSList *non_deletables;
 
 	g_debug( "%s: gtk_action=%p, window=%p", thisfn, ( void * ) gtk_action, ( void * ) window );
 	g_return_if_fail( GTK_IS_ACTION( gtk_action ));
 	g_return_if_fail( NACT_IS_MAIN_WINDOW( window ));
 
+	application = NACT_APPLICATION( base_window_get_application( BASE_WINDOW( window )));
+	updater = nact_application_get_updater( application );
 	items = nact_iactions_list_bis_get_selected_items( NACT_IACTIONS_LIST( window ));
-	for( it = items ; it ; it = it->next ){
-		g_debug( "%s: item=%p (%s)", thisfn, ( void * ) it->data, G_OBJECT_TYPE_NAME( it->data ));
+
+	non_deletables = NULL;
+	to_delete = get_deletables( updater, items, &non_deletables );
+
+	if( non_deletables ){
+		gchar *second = na_core_utils_slist_join_at_end( non_deletables, "\n" );
+		base_window_error_dlg(
+				BASE_WINDOW( window ),
+				GTK_MESSAGE_INFO,
+				_( "Not all items have been deleted as following ones are not modifiable:" ),
+				second );
+		g_free( second );
+		na_core_utils_slist_free( non_deletables );
 	}
-	nact_main_window_move_to_deleted( window, items );
-	nact_iactions_list_bis_delete( NACT_IACTIONS_LIST( window ), items );
 
-	/* do not unref selected items as the list has been concatenated
-	 * to main_deleted
-	 */
-	/*g_list_free( items );*/
+	if( to_delete ){
+		nact_main_window_move_to_deleted( window, to_delete );
+		nact_iactions_list_bis_delete( NACT_IACTIONS_LIST( window ), to_delete );
+	}
+
+	na_object_unref_selected_items( items );
+}
+
+static GList *
+get_deletables( NAUpdater *updater, GList *selected, GSList **non_deletables )
+{
+	GList *to_delete;
+	GList *it;
+	GList *subitems;
+	GSList *sub_deletables;
+	gint reason;
+
+	to_delete = NULL;
+	for( it = selected ; it ; it = it->next ){
+
+		if( !na_updater_is_item_writable( updater, NA_OBJECT_ITEM( it->data ), &reason )){
+			*non_deletables = g_slist_prepend(
+					*non_deletables, add_non_deletable_msg( NA_OBJECT_ITEM( it->data ), reason ));
+			continue;
+		}
+
+		if( NA_IS_OBJECT_MENU( it->data )){
+			subitems = na_object_get_items( it->data );
+			sub_deletables = get_deletables_rec( updater, subitems );
+
+			if( sub_deletables ){
+				*non_deletables = g_slist_concat( *non_deletables, sub_deletables );
+				continue;
+			}
+		}
+
+		to_delete = g_list_prepend( to_delete, it->data );
+	}
+
+	return( to_delete );
+}
+
+static GSList *
+get_deletables_rec( NAUpdater *updater, GList *tree )
+{
+	GSList *msgs;
+	GList *it;
+	GList *subitems;
+	gint reason;
+
+	msgs = NULL;
+	for( it = tree ; it ; it = it->next ){
+
+		if( !na_updater_is_item_writable( updater, NA_OBJECT_ITEM( it->data ), &reason )){
+			msgs = g_slist_prepend(
+					msgs, add_non_deletable_msg( NA_OBJECT_ITEM( it->data ), reason ));
+			continue;
+		}
+
+		if( NA_IS_OBJECT_MENU( it->data )){
+			subitems = na_object_get_items( it->data );
+			msgs = g_slist_concat( msgs, get_deletables_rec( updater, subitems ));
+		}
+	}
+
+	return( msgs );
+}
+
+static gchar *
+add_non_deletable_msg( const NAObjectItem *item, gint reason )
+{
+	gchar *msg;
+	gchar *label;
+	gchar *reason_str;
+
+	label = na_object_get_label( item );
+	reason_str = na_io_provider_get_readonly_tooltip( reason );
+
+	msg = g_strdup_printf( "%s: %s", label, reason_str );
+
+	g_free( reason_str );
+	g_free( label );
+
+	return( msg );
 }
 
 /*



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