[nautilus-actions] Review menu items sensitivity updates



commit 8671735146995dd1663b2d8c6e17475ebb490f31
Author: Pierre Wieser <pwieser trychlos org>
Date:   Wed Feb 2 01:10:02 2011 +0100

    Review menu items sensitivity updates
    
    + Writability status is computed once at load time (na_updater_load_items())
    + Menu items sensitivity indicators are computed at selection change
    
    + The IACTIONS_LIST_SIGNAL_LIST_COUNT_UPDATED is re-send on all_widgets_showed()
      so that we are sure that NactMenubar has connected its callbacks.

 ChangeLog                          |   27 ++++++
 src/api/na-object-api.h            |    3 +
 src/api/na-object-item.h           |    3 +
 src/core/na-object-item.c          |   98 ++++++++++++++++++++-
 src/core/na-object.c               |    6 +-
 src/core/na-updater.c              |  168 +++++++++++++++++++++++-------------
 src/core/na-updater.h              |    7 +-
 src/nact/nact-application.c        |    1 -
 src/nact/nact-iactions-list-priv.c |    1 +
 src/nact/nact-iactions-list.c      |   10 ++
 src/nact/nact-main-menubar-edit.c  |   40 ++-------
 src/nact/nact-main-menubar-file.c  |   50 +----------
 src/nact/nact-main-window.c        |   13 ++-
 src/nact/nact-menubar-priv.h       |    9 ++-
 src/nact/nact-menubar.c            |   80 +++++++++++++++--
 15 files changed, 346 insertions(+), 170 deletions(-)
---
diff --git a/ChangeLog b/ChangeLog
index 87d388b..b3dd06b 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,32 @@
 2011-02-01 Pierre Wieser <pwieser trychlos org>
 
+	Review menu items sensitivity updates
+
+	* src/api/na-object-api.h
+	(na_object_is_finally_writable, na_object_set_writability_status): New macros.
+
+	* src/api/na-object-item.h:
+	* src/core/na-object-item.c
+	(na_object_item_is_finally_writable, na_object_item_set_writability_status):
+	New functions.
+
+	* src/core/na-updater.c:
+	* src/core/na-updater.h (na_updater_load_items): New function.
+
+	* src/nact/nact-application.c (appli_main_window_new):
+	* /src/nact/nact-main-window.c (on_base_initialize_base_window):
+	No more load items when instanciating the main window, but when
+	initializing it.
+
+	* src/nact/nact-iactions-list.c (nact_iactions_list_all_widgets_showed):
+	Send the IACTIONS_LIST_SIGNAL_LIST_COUNT_UPDATED message to update the menubar.
+
+	* src/nact/nact-main-menubar-edit.c (nact_main_menubar_edit_on_update_sensitivities):
+	* src/nact/nact-main-menubar-file.c (nact_main_menubar_file_on_update_sensitivities):
+	* src/nact/nact-menubar-priv.h:
+	* src/nact/nact-menubar.c (on_iactions_list_selection_changed):
+	Rely on indicators pre-computed on selection changes.
+
 	* src/nact/nact-window.c:
 	* src/nact/nact-window.h (nact_window_has_writable_providers):
 	Removed function.
diff --git a/src/api/na-object-api.h b/src/api/na-object-api.h
index db2fef9..1c3e3c3 100644
--- a/src/api/na-object-api.h
+++ b/src/api/na-object-api.h
@@ -135,6 +135,9 @@ G_BEGIN_DECLS
 #define na_object_unref_items( tree )                   na_object_item_unref_items( tree )
 #define na_object_unref_selected_items( tree )          na_object_item_unref_items_rec( tree )
 
+#define na_object_is_finally_writable( obj, r )			na_object_item_is_finally_writable( NA_OBJECT_ITEM( obj ), ( r ))
+#define na_object_set_writability_status( obj, w, r )	na_object_item_set_writability_status( NA_OBJECT_ITEM( obj ), ( w ), ( r ))
+
 /* NAObjectAction
  */
 #define na_object_get_version( obj )                    (( gchar * ) na_ifactory_object_get_as_void( NA_IFACTORY_OBJECT( obj ), NAFO_DATA_VERSION ))
diff --git a/src/api/na-object-item.h b/src/api/na-object-item.h
index 82ec29e..495991f 100644
--- a/src/api/na-object-item.h
+++ b/src/api/na-object-item.h
@@ -110,6 +110,9 @@ void        na_object_item_unref_items_rec( GList *items );
 void        na_object_item_deals_with_version    ( NAObjectItem *item );
 void        na_object_item_rebuild_children_slist( NAObjectItem *item );
 
+gboolean    na_object_item_is_finally_writable   ( const NAObjectItem *item, guint *reason );
+void        na_object_item_set_writability_status( NAObjectItem *item, gboolean writable, guint reason );
+
 G_END_DECLS
 
 #endif /* __NAUTILUS_ACTIONS_API_NA_OBJECT_ITEM_H__ */
diff --git a/src/core/na-object-item.c b/src/core/na-object-item.c
index 12f2319..5b365bd 100644
--- a/src/core/na-object-item.c
+++ b/src/core/na-object-item.c
@@ -57,9 +57,16 @@ struct _NAObjectItemPrivate {
 	/* dynamically set when reading the item from the I/O storage
 	 * subsystem; may be reset from FALSE to TRUE if a write operation
 	 * has returned an error.
-	 * defaults to FALSE for snew, not yet written to a provider, item
+	 * defaults to FALSE for new, not yet written to a provider, item
 	 */
 	gboolean   readonly;
+
+	/* set at load time
+	 * takes into account the above 'readonly' status as well as the i/o
+	 * provider writability status - does not consider the level-zero case
+	 */
+	gboolean   writable;
+	guint      reason;
 };
 
 static NAObjectIdClass *st_parent_class = NULL;
@@ -71,6 +78,7 @@ static void   instance_dispose( GObject *object );
 static void   instance_finalize( GObject *object );
 
 static void   object_copy( NAObject*target, const NAObject *source, gboolean recursive );
+static void   object_dump( const NAObject *object );
 
 static gchar *object_id_new_id( const NAObjectId *item, const NAObjectId *new_parent );
 
@@ -130,7 +138,7 @@ class_init( NAObjectItemClass *klass )
 	object_class->finalize = instance_finalize;
 
 	naobject_class = NA_OBJECT_CLASS( klass );
-	naobject_class->dump = NULL;
+	naobject_class->dump = object_dump;
 	naobject_class->copy = object_copy;
 	naobject_class->are_equal = NULL;
 	naobject_class->is_valid = NULL;
@@ -202,15 +210,18 @@ object_copy( NAObject *target, const NAObject *source, gboolean recursive )
 {
 	static const gchar *thisfn = "na_object_item_object_copy";
 	void *provider;
+	NAObjectItem *dest, *src;
 
 	g_return_if_fail( NA_IS_OBJECT_ITEM( target ));
 	g_return_if_fail( NA_IS_OBJECT_ITEM( source ));
 
-	if( !NA_OBJECT_ITEM( target )->private->dispose_has_run &&
-		!NA_OBJECT_ITEM( source )->private->dispose_has_run ){
+	dest = NA_OBJECT_ITEM( target );
+	src = NA_OBJECT_ITEM( source );
+
+	if( !dest->private->dispose_has_run && !src->private->dispose_has_run ){
 
 		if( recursive ){
-			copy_children( NA_OBJECT_ITEM( target ), NA_OBJECT_ITEM( source ));
+			copy_children( dest, src );
 		}
 
 		provider = na_object_get_provider( source );
@@ -226,6 +237,29 @@ object_copy( NAObject *target, const NAObject *source, gboolean recursive )
 				na_io_provider_duplicate_data( NA_IO_PROVIDER( provider ), NA_OBJECT_ITEM( target ), NA_OBJECT_ITEM( source ), NULL );
 			}
 		}
+
+		dest->private->readonly = src->private->readonly;
+		dest->private->writable = src->private->writable;
+		dest->private->reason = src->private->reason;
+	}
+}
+
+static void
+object_dump( const NAObject *object )
+{
+	static const gchar *thisfn = "na_object_item_object_dump";
+	NAObjectItem *item;
+
+	g_return_if_fail( NA_IS_OBJECT_ITEM( object ));
+
+	item = NA_OBJECT_ITEM( object );
+
+	if( !item->private->dispose_has_run ){
+
+		g_debug( "%s: provider_data=%p", thisfn, ( void * ) item->private->provider_data );
+		g_debug( "%s:      readonly=%s", thisfn, item->private->readonly ? "True":"False" );
+		g_debug( "%s:      writable=%s", thisfn, item->private->writable ? "True":"False" );
+		g_debug( "%s:        reason=%u", thisfn, item->private->reason );
 	}
 }
 
@@ -813,3 +847,57 @@ copy_children( NAObjectItem *target, const NAObjectItem *source )
 	tgt_children = g_list_reverse( tgt_children );
 	na_object_set_items( target, tgt_children );
 }
+
+/**
+ * na_object_item_is_finally_writable:
+ * @item: this #NAObjectItem -derived object.
+ * @reason: if not %NULL, a pointer to a guint which will hold the reason code.
+ *
+ * Returns: the writability status of the @item.
+ *
+ * Since: 3.1.0
+ */
+gboolean
+na_object_item_is_finally_writable( const NAObjectItem *item, guint *reason )
+{
+	gboolean writable;
+
+	if( reason ){
+		*reason = NA_IIO_PROVIDER_STATUS_UNDETERMINED;
+	}
+	g_return_val_if_fail( NA_IS_OBJECT_ITEM( item ), FALSE );
+
+	writable = FALSE;
+
+	if( !item->private->dispose_has_run ){
+
+		writable = item->private->writable;
+		if( reason ){
+			*reason = item->private->reason;
+		}
+	}
+
+	return( writable );
+}
+
+/**
+ * na_object_item_set_writability_status:
+ * @item: this #NAObjectItem -derived object.
+ * @writable: whether the item is finally writable.
+ * @reason: the reason code.
+ *
+ * Set the writability status of the @item.
+ *
+ * Since: 3.1.0
+ */
+void
+na_object_item_set_writability_status( NAObjectItem *item, gboolean writable, guint reason )
+{
+	g_return_if_fail( NA_IS_OBJECT_ITEM( item ));
+
+	if( !item->private->dispose_has_run ){
+
+		item->private->writable = writable;
+		item->private->reason = reason;
+	}
+}
diff --git a/src/core/na-object.c b/src/core/na-object.c
index 1e61045..5c73b11 100644
--- a/src/core/na-object.c
+++ b/src/core/na-object.c
@@ -538,7 +538,7 @@ object_copy_iter( GObjectClass *class, const NAObject *source, CopyIter *data )
 void
 na_object_object_dump( const NAObject *object )
 {
-	GList *childs, *ic;
+	GList *children, *ic;
 
 	g_return_if_fail( NA_IS_OBJECT( object ));
 
@@ -548,8 +548,8 @@ na_object_object_dump( const NAObject *object )
 
 		if( NA_IS_OBJECT_ITEM( object )){
 
-			childs = na_object_get_items( object );
-			for( ic = childs ; ic ; ic = ic->next ){
+			children = na_object_get_items( object );
+			for( ic = children ; ic ; ic = ic->next ){
 
 				na_object_dump( ic->data );
 			}
diff --git a/src/core/na-updater.c b/src/core/na-updater.c
index 5bd0d55..a86d1fc 100644
--- a/src/core/na-updater.c
+++ b/src/core/na-updater.c
@@ -62,6 +62,7 @@ static void     instance_dispose( GObject *object );
 static void     instance_finalize( GObject *object );
 
 static gboolean is_level_zero_writable( const NAUpdater *updater );
+static void     set_writability_status( NAObjectItem *item, const NAUpdater *updater );
 
 GType
 na_updater_get_type( void )
@@ -199,6 +200,84 @@ na_updater_new( void )
 }
 
 /*
+ * na_updater_is_item_writable:
+ * @updater: this #NAUpdater object.
+ * @item: the #NAObjectItem to be written.
+ * @reason: the reason for why @item may not be writable.
+ *
+ * Returns: %TRUE: if @item is actually writable, given the current
+ * status of its provider, %FALSE else.
+ *
+ * For an item be actually writable:
+ * - the item must not be itself in a read-only store, which has been
+ *   checked when first reading it
+ * - the provider must be willing (resp. able) to write
+ * - the provider must not has been locked by the admin, nor by the user
+ *
+ * Note that this function does not consider if the item is to be written
+ * at the level zero of the tree, which may be a mandatory preference
+ * (i.e. locked by an admin), and so make this item unwritable.
+ */
+gboolean
+na_updater_is_item_writable( const NAUpdater *updater, const NAObjectItem *item, guint *reason )
+{
+	gboolean writable;
+	NAIOProvider *provider;
+
+	g_return_val_if_fail( NA_IS_UPDATER( updater ), FALSE );
+	g_return_val_if_fail( NA_IS_OBJECT_ITEM( item ), FALSE );
+
+	writable = FALSE;
+	if( reason ){
+		*reason = NA_IIO_PROVIDER_STATUS_UNDETERMINED;
+	}
+
+	if( !updater->private->dispose_has_run ){
+
+		writable = TRUE;
+		if( reason ){
+			*reason = NA_IIO_PROVIDER_STATUS_WRITABLE;
+		}
+
+		/* Writability status of the item has been determined at load time
+		 * (cf. e.g. io-desktop/nadp-reader.c:read_done_item_is_writable()).
+		 * Though I'm plenty conscious that this status is subject to many
+		 * changes during the life of the item (e.g. by modifying permissions
+		 * on the underlying store), it is just simpler to not reevaluate
+		 * this status each time we need it
+		 */
+		if( writable ){
+			if( na_object_is_readonly( item )){
+				writable = FALSE;
+				if( reason ){
+					*reason = NA_IIO_PROVIDER_STATUS_ITEM_READONLY;
+				}
+			}
+		}
+
+		if( writable ){
+			provider = na_object_get_provider( item );
+			if( provider ){
+				writable = na_io_provider_is_finally_writable( provider, reason );
+
+			/* the get_writable_provider() api already takes above checks
+			 */
+			} else {
+				provider = na_io_provider_find_writable_io_provider( NA_PIVOT( updater ));
+				if( !provider ){
+					writable = FALSE;
+					if( reason ){
+						*reason = NA_IIO_PROVIDER_STATUS_NO_PROVIDER_FOUND;
+					}
+				}
+			}
+		}
+	}
+
+	return( writable );
+}
+
+/*
  * na_updater_is_level_zero_writable:
  * @updater: the #NAUpdater application object.
  *
@@ -338,81 +417,48 @@ na_updater_remove_item( NAUpdater *updater, NAObject *item )
 }
 
 /*
- * na_updater_is_item_writable:
- * @updater: this #NAUpdater object.
- * @item: the #NAObjectItem to be written.
- * @reason: the reason for why @item may not be writable.
+ * na_updater_load_items:
+ * @updater: this #NAUpdater instance.
  *
- * Returns: %TRUE: if @item is actually writable, given the current
- * status of its provider, %FALSE else.
+ * Loads the items, updating simultaneously their writability status.
  *
- * For an item be actually writable:
- * - the item must not be itself in a read-only store, which has been
- *   checked when first reading it
- * - the provider must be willing (resp. able) to write
- * - the provider must not has been locked by the admin, nor by the user
+ * Returns: a pointer (not a ref) on the loaded tree.
  *
- * Note that this function does not consider if the item is to be written
- * at the level zero of the tree, which may be a mandatory preference
- * (i.e. locked by an admin), and so make this item unwritable.
+ * Since: 3.1.0
  */
-gboolean
-na_updater_is_item_writable( const NAUpdater *updater, const NAObjectItem *item, guint *reason )
+GList *
+na_updater_load_items( NAUpdater *updater )
 {
-	gboolean writable;
-	NAIOProvider *provider;
+	GList *tree;
 
-	g_return_val_if_fail( NA_IS_UPDATER( updater ), FALSE );
-	g_return_val_if_fail( NA_IS_OBJECT_ITEM( item ), FALSE );
+	g_return_val_if_fail( NA_IS_UPDATER( updater ), NULL );
 
-	writable = FALSE;
-	if( reason ){
-		*reason = NA_IIO_PROVIDER_STATUS_UNDETERMINED;
-	}
+	tree = NULL;
 
 	if( !updater->private->dispose_has_run ){
 
-		writable = TRUE;
-		if( reason ){
-			*reason = NA_IIO_PROVIDER_STATUS_WRITABLE;
-		}
+		na_pivot_load_items( NA_PIVOT( updater ));
+		tree = na_pivot_get_items( NA_PIVOT( updater ));
+		g_list_foreach( tree, ( GFunc ) set_writability_status, ( gpointer ) updater );
+	}
 
-		/* Writability status of the item has been determined at load time
-		 * (cf. e.g. io-desktop/nadp-reader.c:read_done_item_is_writable()).
-		 * Though I'm plenty conscious that this status is subject to many
-		 * changes during the life of the item (e.g. by modifying permissions
-		 * on the underlying store), it is just simpler to not reevaluate
-		 * this status each time we need it
-		 */
-		if( writable ){
-			if( na_object_is_readonly( item )){
-				writable = FALSE;
-				if( reason ){
-					*reason = NA_IIO_PROVIDER_STATUS_ITEM_READONLY;
-				}
-			}
-		}
+	return( tree );
+}
 
-		if( writable ){
-			provider = na_object_get_provider( item );
-			if( provider ){
-				writable = na_io_provider_is_finally_writable( provider, reason );
+static void
+set_writability_status( NAObjectItem *item, const NAUpdater *updater )
+{
+	gboolean writable;
+	guint reason;
+	GList *children;
 
-			/* the get_writable_provider() api already takes above checks
-			 */
-			} else {
-				provider = na_io_provider_find_writable_io_provider( NA_PIVOT( updater ));
-				if( !provider ){
-					writable = FALSE;
-					if( reason ){
-						*reason = NA_IIO_PROVIDER_STATUS_NO_PROVIDER_FOUND;
-					}
-				}
-			}
-		}
-	}
+	writable = na_updater_is_item_writable( updater, item, &reason );
+	na_object_set_writability_status( item, writable, reason );
 
-	return( writable );
+	if( NA_IS_OBJECT_MENU( item )){
+		children = na_object_get_items( item );
+		g_list_foreach( children, ( GFunc ) set_writability_status, ( gpointer ) updater );
+	}
 }
 
 /*
diff --git a/src/core/na-updater.h b/src/core/na-updater.h
index 534a7c1..0c1bb44 100644
--- a/src/core/na-updater.h
+++ b/src/core/na-updater.h
@@ -74,6 +74,7 @@ NAUpdater *na_updater_new( void );
 
 /* writability status
  */
+gboolean   na_updater_is_item_writable      ( const NAUpdater *updater, const NAObjectItem *item, guint *reason );
 gboolean   na_updater_is_level_zero_writable( const NAUpdater *updater );
 
 /* update the tree in memory
@@ -84,9 +85,9 @@ void       na_updater_remove_item( NAUpdater *updater, NAObject *item );
 
 /* read from / write to the physical storage subsystem
  */
-gboolean   na_updater_is_item_writable( const NAUpdater *updater, const NAObjectItem *item, guint *reason );
-guint      na_updater_write_item      ( const NAUpdater *updater, NAObjectItem *item, GSList **messages );
-guint      na_updater_delete_item     ( const NAUpdater *updater, const NAObjectItem *item, GSList **messages );
+GList     *na_updater_load_items ( NAUpdater *updater );
+guint      na_updater_write_item ( const NAUpdater *updater, NAObjectItem *item, GSList **messages );
+guint      na_updater_delete_item( const NAUpdater *updater, const NAObjectItem *item, GSList **messages );
 
 G_END_DECLS
 
diff --git a/src/nact/nact-application.c b/src/nact/nact-application.c
index d7c4d54..15bf835 100644
--- a/src/nact/nact-application.c
+++ b/src/nact/nact-application.c
@@ -349,7 +349,6 @@ appli_main_window_new( const BaseApplication *application, int *code )
 
 	appli->private->updater = na_updater_new();
 	na_pivot_set_loadable( NA_PIVOT( appli->private->updater ), PIVOT_LOAD_ALL );
-	na_pivot_load_items( NA_PIVOT( appli->private->updater ));
 
 	main_window = nact_main_window_new( appli );
 
diff --git a/src/nact/nact-iactions-list-priv.c b/src/nact/nact-iactions-list-priv.c
index eaadabf..dc63960 100644
--- a/src/nact/nact-iactions-list-priv.c
+++ b/src/nact/nact-iactions-list-priv.c
@@ -86,6 +86,7 @@ nact_iactions_list_priv_get_instance_data( NactIActionsList *instance )
 void
 nact_iactions_list_priv_send_list_count_updated_signal( NactIActionsList *instance, IActionsListInstanceData *ialid )
 {
+	g_debug( "nact_iactions_list_priv_send_list_count_updated_signal: emitting signal %s", IACTIONS_LIST_SIGNAL_LIST_COUNT_UPDATED );
 	g_signal_emit_by_name( instance,
 							IACTIONS_LIST_SIGNAL_LIST_COUNT_UPDATED,
 							ialid->menus, ialid->actions, ialid->profiles );
diff --git a/src/nact/nact-iactions-list.c b/src/nact/nact-iactions-list.c
index f87fdef..4c36153 100644
--- a/src/nact/nact-iactions-list.c
+++ b/src/nact/nact-iactions-list.c
@@ -509,12 +509,21 @@ void
 nact_iactions_list_all_widgets_showed( NactIActionsList *instance )
 {
 	static const gchar *thisfn = "nact_iactions_list_all_widgets_showed";
+	gboolean profiles_are_displayed;
+	IActionsListInstanceData *ialid;
 
 	g_debug( "%s: instance=%p", thisfn, ( void * ) instance );
 	g_return_if_fail( NACT_IS_IACTIONS_LIST( instance ));
 
 	if( st_iactions_list_initialized && !st_iactions_list_finalized ){
 
+		ialid = nact_iactions_list_priv_get_instance_data( instance );
+		profiles_are_displayed = are_profiles_displayed( instance, ialid );
+
+		if( profiles_are_displayed ){
+			nact_iactions_list_priv_send_list_count_updated_signal( instance, ialid );
+		}
+
 		nact_iactions_list_bis_select_first_row( instance );
 	}
 }
@@ -669,6 +678,7 @@ nact_iactions_list_fill( NactIActionsList *instance, GList *items )
 
 		ialid = nact_iactions_list_priv_get_instance_data( instance );
 		profiles_are_displayed = are_profiles_displayed( instance, ialid );
+		g_debug( "%s: profiles_are_displayed:%s", thisfn, profiles_are_displayed ? "True":"False" );
 
 		ialid->selection_changed_allowed = FALSE;
 		nact_tree_model_fill( model, items, profiles_are_displayed );
diff --git a/src/nact/nact-main-menubar-edit.c b/src/nact/nact-main-menubar-edit.c
index 76fc766..d8bbe9d 100644
--- a/src/nact/nact-main-menubar-edit.c
+++ b/src/nact/nact-main-menubar-edit.c
@@ -69,34 +69,20 @@ nact_main_menubar_edit_on_update_sensitivities( NactMenubar *bar )
 	gboolean paste_into_enabled;
 	gboolean duplicate_enabled;
 	gboolean delete_enabled;
-	GList *is;
 	NAObject *parent_item;
 	NAObject *selected_action;
 	NAObject *selected_item;
-	gboolean are_parents_writable;
 	gboolean is_clipboard_empty;
 
 	is_clipboard_empty = ( bar->private->clipboard_menus + bar->private->clipboard_actions + bar->private->clipboard_profiles == 0 );
 
 	/* cut requires a non-empty selection
+	 * and that the selection is writable
 	 * and that all parents are writable (as implies a delete operation)
 	 */
 	cut_enabled = bar->private->treeview_has_focus || bar->private->popup_handler;
 	cut_enabled &= bar->private->count_selected > 0;
-	are_parents_writable = TRUE;
-	for( is = bar->private->selected_items ; is ; is = is->next ){
-		parent_item = ( NAObject * ) na_object_get_parent( is->data );
-		if( parent_item ){
-			if( !na_updater_is_item_writable( bar->private->updater, NA_OBJECT_ITEM( parent_item ), NULL )){
-				are_parents_writable = FALSE;
-				break;
-			}
-		} else if( !bar->private->is_level_zero_writable ){
-			are_parents_writable = FALSE;
-			break;
-		}
-	}
-	cut_enabled &= are_parents_writable;
+	cut_enabled &= bar->private->are_parents_writable;
 	nact_menubar_enable_item( bar, "CutItem", cut_enabled );
 
 	/* copy only requires a non-empty selection */
@@ -119,25 +105,11 @@ nact_main_menubar_edit_on_update_sensitivities( NactMenubar *bar )
 	paste_enabled &= bar->private->count_selected <= 1;
 	if( bar->private->clipboard_profiles ){
 		paste_enabled &= bar->private->count_selected == 1;
-		if( paste_enabled ){
-			selected_action = NA_OBJECT(
-					NA_IS_OBJECT_PROFILE( bar->private->selected_items->data )
-							? na_object_get_parent( bar->private->selected_items->data )
-							: bar->private->selected_items->data );
-			paste_enabled &= NA_IS_OBJECT_ACTION( selected_action );
-			paste_enabled &= na_updater_is_item_writable( bar->private->updater, NA_OBJECT_ITEM( selected_action ), NULL );
-		}
+		paste_enabled &= bar->private->is_action_writable;
 	} else {
 		paste_enabled &= bar->private->has_writable_providers;
 		if( bar->private->count_selected ){
-			selected_item = NA_OBJECT( bar->private->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
-						? na_updater_is_item_writable( bar->private->updater, NA_OBJECT_ITEM( parent_item ), NULL )
-						: bar->private->is_level_zero_writable;
-			}
+			paste_enabled &= bar->private->is_parent_writable;
 		} else {
 			paste_enabled &= bar->private->is_level_zero_writable;
 		}
@@ -162,7 +134,7 @@ nact_main_menubar_edit_on_update_sensitivities( NactMenubar *bar )
 		if( paste_into_enabled ){
 			selected_action = NA_OBJECT( bar->private->selected_items->data );
 			paste_into_enabled &= NA_IS_OBJECT_ACTION( selected_action );
-			paste_into_enabled &= na_updater_is_item_writable( bar->private->updater, NA_OBJECT_ITEM( selected_action ), NULL );
+			paste_into_enabled &= na_object_is_finally_writable( selected_action, NULL );
 		}
 	} else {
 		paste_into_enabled &= bar->private->has_writable_providers;
@@ -172,7 +144,7 @@ nact_main_menubar_edit_on_update_sensitivities( NactMenubar *bar )
 			if( paste_into_enabled ){
 				parent_item = ( NAObject * ) na_object_get_parent( selected_item );
 				paste_into_enabled &= parent_item
-						? na_updater_is_item_writable( bar->private->updater, NA_OBJECT_ITEM( parent_item ), NULL )
+						? na_object_is_finally_writable( parent_item, NULL )
 						: bar->private->is_level_zero_writable;
 			}
 		} else {
diff --git a/src/nact/nact-main-menubar-file.c b/src/nact/nact-main-menubar-file.c
index c2e37bb..0d0c850 100644
--- a/src/nact/nact-main-menubar-file.c
+++ b/src/nact/nact-main-menubar-file.c
@@ -75,25 +75,7 @@ nact_main_menubar_file_on_update_sensitivities( NactMenubar *bar )
 {
 	static const gchar *thisfn = "nact_main_menubar_file_on_update_sensitivities";
 	gboolean new_item_enabled;
-	gboolean new_profile_enabled;
-	NAObject *first_parent;
-	NAObject *selected_action;
-	NAObject *parent_item;
-	gboolean is_first_parent_writable;
 	gboolean has_modified_items;
-	GList *is;
-	NactApplication *application;
-	NAUpdater *updater;
-
-	application = NACT_APPLICATION( base_window_get_application( bar->private->window ));
-	updater = nact_application_get_updater( application );
-
-	first_parent = bar->private->selected_items && g_list_length( bar->private->selected_items )
-			? ( NAObject * ) na_object_get_parent( bar->private->selected_items->data )
-			: NULL;
-	is_first_parent_writable = first_parent
-			? na_updater_is_item_writable( bar->private->updater, NA_OBJECT_ITEM( first_parent ), NULL )
-			: bar->private->is_level_zero_writable;
 
 	has_modified_items = nact_main_window_has_modified_items( NACT_MAIN_WINDOW( bar->private->window ));
 	g_debug( "%s: has_modified_items=%s", thisfn, has_modified_items ? "True":"False" );
@@ -103,7 +85,7 @@ nact_main_menubar_file_on_update_sensitivities( NactMenubar *bar )
 	 * parent of the first selected row must be writable
 	 * we must have at least one writable provider
 	 */
-	new_item_enabled = is_first_parent_writable && bar->private->has_writable_providers;
+	new_item_enabled = bar->private->is_parent_writable && bar->private->has_writable_providers;
 	nact_menubar_enable_item( bar, "NewMenuItem", new_item_enabled );
 	nact_menubar_enable_item( bar, "NewActionItem", new_item_enabled );
 
@@ -111,36 +93,8 @@ nact_main_menubar_file_on_update_sensitivities( NactMenubar *bar )
 	 * 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 = bar->private->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;
-			}
-		}
-	}
 	nact_menubar_enable_item( bar, "NewProfileItem",
-			new_profile_enabled &&
-			selected_action != NULL &&
-			na_updater_is_item_writable( bar->private->updater, NA_OBJECT_ITEM( selected_action ), NULL ));
+			bar->private->enable_new_profile && bar->private->is_action_writable );
 
 	/* save enabled if at least one item has been modified
 	 * or level-zero has been resorted and is writable
diff --git a/src/nact/nact-main-window.c b/src/nact/nact-main-window.c
index db0c161..8ee2f64 100644
--- a/src/nact/nact-main-window.c
+++ b/src/nact/nact-main-window.c
@@ -880,9 +880,6 @@ on_base_initialize_base_window( NactMainWindow *window, gpointer user_data )
 		base_window_signal_connect( BASE_WINDOW( window ),
 				G_OBJECT( window ), IACTIONS_LIST_SIGNAL_SELECTION_CHANGED, G_CALLBACK( on_iactions_list_selection_changed ));
 
-		tree = na_pivot_get_items( NA_PIVOT( updater ));
-		g_debug( "%s: pivot_tree=%p", thisfn, ( void * ) tree );
-
 		nact_iaction_tab_runtime_init_toplevel( NACT_IACTION_TAB( window ));
 		nact_icommand_tab_runtime_init_toplevel( NACT_ICOMMAND_TAB( window ));
 		nact_ibasenames_tab_runtime_init_toplevel( NACT_IBASENAMES_TAB( window ));
@@ -898,7 +895,12 @@ on_base_initialize_base_window( NactMainWindow *window, gpointer user_data )
 
 		/* fill the IActionsList at last so that all signals are connected
 		 */
+		tree = na_updater_load_items( updater );
+		g_debug( "%s: pivot_tree=%p", thisfn, ( void * ) tree );
 		nact_iactions_list_runtime_init_toplevel( NACT_IACTIONS_LIST( window ), tree );
+
+		/* other initializations
+		 */
 		nact_sort_buttons_runtime_init( window );
 
 		/* this to update the title when an item is modified
@@ -1570,6 +1572,7 @@ reload( NactMainWindow *window )
 	static const gchar *thisfn = "nact_main_window_reload";
 	NactApplication *application;
 	NAUpdater *updater;
+	GList *tree;
 
 	g_debug( "%s: window=%p", thisfn, ( void * ) window );
 	g_return_if_fail( NACT_IS_MAIN_WINDOW( window ));
@@ -1584,8 +1587,8 @@ reload( NactMainWindow *window )
 
 		application = NACT_APPLICATION( base_window_get_application( BASE_WINDOW( window )));
 		updater = nact_application_get_updater( application );
-		na_pivot_load_items( NA_PIVOT( updater ));
-		nact_iactions_list_fill( NACT_IACTIONS_LIST( window ), na_pivot_get_items( NA_PIVOT( updater )));
+		tree = na_updater_load_items( updater );
+		nact_iactions_list_fill( NACT_IACTIONS_LIST( window ), tree );
 		nact_iactions_list_bis_select_first_row( NACT_IACTIONS_LIST( window ));
 	}
 }
diff --git a/src/nact/nact-menubar-priv.h b/src/nact/nact-menubar-priv.h
index 9d35738..2c3acee 100644
--- a/src/nact/nact-menubar-priv.h
+++ b/src/nact/nact-menubar-priv.h
@@ -62,7 +62,13 @@ struct _NactMenubarPrivate {
 	gboolean        is_level_zero_writable;
 	gboolean        has_writable_providers;
 
-	gboolean        is_parent_writable;
+	/* set when the selection changes
+	 */
+	guint           count_selected;
+	gboolean        is_parent_writable;		/* new menu/new action/paste menu or action */
+	gboolean        enable_new_profile;		/* new profile/paste a profile */
+	gboolean        is_action_writable;
+	gboolean        are_parents_writable;	/* cut/delete */
 
 	/* *** */
 	gint            selected_menus;
@@ -80,7 +86,6 @@ struct _NactMenubarPrivate {
 	gboolean        level_zero_order_changed;
 	gulong          popup_handler;
 
-	guint           count_selected;
 	GList          *selected_items;
 	/* *** */
 };
diff --git a/src/nact/nact-menubar.c b/src/nact/nact-menubar.c
index 52a5481..31d5acc 100644
--- a/src/nact/nact-menubar.c
+++ b/src/nact/nact-menubar.c
@@ -689,29 +689,93 @@ on_iactions_list_count_updated( NactMainWindow *window, gint menus, gint actions
 
 /*
  * when the selection changes in the tree view, see what is selected
- * - check if the parent of the first selected item is writable
- *   (File:New menu/New action)
  */
 static void
 on_iactions_list_selection_changed( NactMainWindow *window, GList *selected )
 {
+	static const gchar *thisfn = "nact_menubar_on_iactions_list_selection_changed";
 	NAObject *first;
+	NAObject *selected_action;
+	GList *is;
 
 	BAR_WINDOW_VOID( window );
 
-	g_debug( "nact_main_menubar_on_iactions_list_selection_changed: selected=%p (count=%d)",
-			( void * ) selected, g_list_length( selected ));
+	g_debug( "%s: selected=%p (count=%d)", thisfn, ( void * ) selected, g_list_length( selected ));
+
+	bar->private->count_selected = g_list_length( selected );
 
 	if( selected ){
+		/* check if the parent of the first selected item is writable
+		 * (File: New menu/New action)
+		 * (Edit: Paste menu or action)
+		 */
 		first = ( NAObject *) selected->data;
 		if( first ){
 			if( NA_IS_OBJECT_PROFILE( first )){
 				first = NA_OBJECT( na_object_get_parent( first ));
 			}
-			first = NA_OBJECT( na_object_get_parent( first ));
-#if 0
-			bar->private->is_parent_writable = first ? na_object_is_writable( first ) : is_level_zero_writable();
-#endif
+			first = ( NAObject * ) na_object_get_parent( first );
+			bar->private->is_parent_writable = first ? na_object_is_finally_writable( first, NULL ) : bar->private->is_level_zero_writable;
+		}
+		/* check is only an action is selected, or only profile(s) of a same action
+		 * (File: New profile)
+		 * (Edit: Paste a profile)
+		 */
+		bar->private->enable_new_profile = TRUE;
+		selected_action = NULL;
+		for( is = selected ; is ; is = is->next ){
+
+			if( NA_IS_OBJECT_MENU( is->data )){
+				bar->private->enable_new_profile = FALSE;
+				break;
+
+			} else if( NA_IS_OBJECT_ACTION( is->data )){
+				if( !selected_action ){
+					selected_action = NA_OBJECT( is->data );
+				} else {
+					bar->private->enable_new_profile = FALSE;
+					break;
+				}
+
+			} else if( NA_IS_OBJECT_PROFILE( is->data )){
+				first = NA_OBJECT( na_object_get_parent( is->data ));
+				if( !selected_action ){
+					selected_action = first;
+				} else if( selected_action != first ){
+					bar->private->enable_new_profile = FALSE;
+					break;
+				}
+			}
+		}
+		if( !selected_action ){
+			bar->private->enable_new_profile = FALSE;
+		} else {
+			bar->private->is_action_writable = na_object_is_finally_writable( selected_action, NULL );
+		}
+		/* check that selection is not empty and that each selected item is writable
+		 * and that all parents are writable
+		 * if some selection is at level zero, then it must be writable
+		 * (Edit: Cut/Delete)
+		 */
+		bar->private->are_parents_writable = TRUE;
+		for( is = selected ; is ; is = is->next ){
+			gchar *label = na_object_get_label( is->data );
+			gboolean writable = na_object_is_finally_writable( is->data, NULL );
+			g_debug( "%s: label=%s, writable=%s", thisfn, label, writable ? "True":"False" );
+			if( !na_object_is_finally_writable( is->data, NULL )){
+				bar->private->are_parents_writable = FALSE;
+				break;
+			}
+			first = ( NAObject * ) na_object_get_parent( is->data );
+			if( first ){
+				if( !na_object_is_finally_writable( first, NULL )){
+					bar->private->are_parents_writable = FALSE;
+					break;
+				}
+			} else if( !bar->private->is_level_zero_writable ){
+				bar->private->are_parents_writable = FALSE;
+				break;
+			}
 		}
 	}
 



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