Index: wp-admin/edit.php
===================================================================
--- wp-admin/edit.php	(revision 27490)
+++ wp-admin/edit.php	(working copy)
@@ -75,11 +75,13 @@
 
 	switch ( $doaction ) {
 		case 'trash':
-			$trashed = $locked = 0;
+			$trashed = $nottrashed = $locked = 0;
 
 			foreach( (array) $post_ids as $post_id ) {
-				if ( !current_user_can( 'delete_post', $post_id) )
-					wp_die( __('You are not allowed to move this item to the Trash.') );
+				if ( !current_user_can( 'delete_post', $post_id) ) {
+					$nottrashed++;
+					continue;
+				}
 
 				if ( wp_check_post_lock( $post_id ) ) {
 					$locked++;
@@ -92,28 +94,32 @@
 				$trashed++;
 			}
 
-			$sendback = add_query_arg( array('trashed' => $trashed, 'ids' => join(',', $post_ids), 'locked' => $locked ), $sendback );
+			$sendback = add_query_arg( array( 'trashed' => $trashed, 'nottrashed' => $nottrashed, 'ids' => join(',', $post_ids), 'locked' => $locked ), $sendback );
 			break;
 		case 'untrash':
-			$untrashed = 0;
+			$untrashed = $notuntrashed = 0;
 			foreach( (array) $post_ids as $post_id ) {
-				if ( !current_user_can( 'delete_post', $post_id) )
-					wp_die( __('You are not allowed to restore this item from the Trash.') );
+				if ( !current_user_can( 'delete_post', $post_id) ) {
+				    $notuntrashed++;
+				    continue;
+				}
 
 				if ( !wp_untrash_post($post_id) )
 					wp_die( __('Error in restoring from Trash.') );
 
 				$untrashed++;
 			}
-			$sendback = add_query_arg('untrashed', $untrashed, $sendback);
+			$sendback = add_query_arg( array( 'untrashed' => $untrashed, 'notuntrashed' => $notuntrashed ), $sendback );
 			break;
 		case 'delete':
-			$deleted = 0;
+			$deleted = $notdeleted = 0;
 			foreach( (array) $post_ids as $post_id ) {
 				$post_del = get_post($post_id);
 
-				if ( !current_user_can( 'delete_post', $post_id ) )
-					wp_die( __('You are not allowed to delete this item.') );
+				if ( !current_user_can( 'delete_post', $post_id ) ) {
+					$notdeleted++;
+					continue;
+				}
 
 				if ( $post_del->post_type == 'attachment' ) {
 					if ( ! wp_delete_attachment($post_id) )
@@ -124,7 +130,7 @@
 				}
 				$deleted++;
 			}
-			$sendback = add_query_arg('deleted', $deleted, $sendback);
+			$sendback = add_query_arg( array( 'deleted' => $deleted, 'notdeleted' => $notdeleted ), $sendback );
 			break;
 		case 'edit':
 			if ( isset($_REQUEST['bulk_edit']) ) {
@@ -232,6 +238,12 @@
 	'untrashed' => isset( $_REQUEST['untrashed'] ) ? absint( $_REQUEST['untrashed'] ) : 0,
 );
 
+$bulk_error_counts = array(
+  	'notdeleted'   => isset( $_REQUEST['notdeleted'] )   ? absint( $_REQUEST['notdeleted'] )   : 0,
+	'nottrashed'   => isset( $_REQUEST['nottrashed'] )   ? absint( $_REQUEST['nottrashed'] )   : 0,
+	'notuntrashed' => isset( $_REQUEST['notuntrashed'] ) ? absint( $_REQUEST['notuntrashed'] ) : 0,
+);
+
 $bulk_messages = array();
 $bulk_messages['post'] = array(
 	'updated'   => _n( '%s post updated.', '%s posts updated.', $bulk_counts['updated'] ),
@@ -248,6 +260,18 @@
 	'untrashed' => _n( '%s page restored from the Trash.', '%s pages restored from the Trash.', $bulk_counts['untrashed'] ),
 );
 
+$bulk_error_messages = array();
+$bulk_error_messages['post'] = array(
+	'notdeleted'   => _n( '%s post not permanently deleted.', '%s posts not permanently deleted.', $bulk_error_counts['notdeleted'] ),
+	'nottrashed'   => _n( '%s post not moved to the Trash.', '%s posts not moved to the Trash.', $bulk_error_counts['nottrashed'] ),
+	'notuntrashed' => _n( '%s post not restored from the Trash.', '%s posts not restored from the Trash.', $bulk_error_counts['notuntrashed'] ),
+);
+$bulk_error_messages['page'] = array(
+	'notdeleted'   => _n( '%s page not permanently deleted.', '%s pages not permanently deleted.', $bulk_error_counts['notdeleted'] ),
+	'nottrashed'   => _n( '%s page not moved to the Trash.', '%s pages not moved to the Trash.', $bulk_error_counts['nottrashed'] ),
+	'notuntrashed' => _n( '%s page not restored from the Trash.', '%s pages not restored from the Trash.', $bulk_error_counts['notuntrashed'] ),
+);
+
 /**
  * Filter the bulk action updated messages.
  *
@@ -262,6 +286,10 @@
 $bulk_messages = apply_filters( 'bulk_post_updated_messages', $bulk_messages, $bulk_counts );
 $bulk_counts = array_filter( $bulk_counts );
 
+/** This filter documented in wp-admin/edit.php */
+$bulk_error_messages = apply_filters( 'bulk_post_updated_messages', $bulk_error_messages, $bulk_error_counts );
+$bulk_error_counts = array_filter( $bulk_error_counts );
+
 require_once( ABSPATH . 'wp-admin/admin-header.php' );
 ?>
 <div class="wrap">
@@ -276,6 +304,7 @@
 <?php
 // If we have a bulk message to issue:
 $messages = array();
+$error_messages = array();
 foreach ( $bulk_counts as $message => $count ) {
 	if ( isset( $bulk_messages[ $post_type ][ $message ] ) )
 		$messages[] = sprintf( $bulk_messages[ $post_type ][ $message ], number_format_i18n( $count ) );
@@ -287,12 +316,21 @@
 		$messages[] = '<a href="' . esc_url( wp_nonce_url( "edit.php?post_type=$post_type&doaction=undo&action=untrash&ids=$ids", "bulk-posts" ) ) . '">' . __('Undo') . '</a>';
 	}
 }
+foreach ( $bulk_error_counts as $message => $count ) {
+	if ( isset( $bulk_error_messages[ $post_type ][ $message ] ) )
+		$error_messages[] = sprintf( $bulk_error_messages[ $post_type ][ $message ], number_format_i18n( $count ) );
+	elseif ( isset( $bulk_error_messages['post'][ $message ] ) )
+		$error_messages[] = sprintf( $bulk_error_messages['post'][ $message ], number_format_i18n( $count ) );
+}
 
 if ( $messages )
 	echo '<div id="message" class="updated"><p>' . join( ' ', $messages ) . '</p></div>';
+if ( $error_messages )
+    echo '<div id="errormessage" class="error"><p>' . join( ' ', $error_messages ) . '</p></div>';
 unset( $messages );
+unset( $error_messgaes );
 
-$_SERVER['REQUEST_URI'] = remove_query_arg( array( 'locked', 'skipped', 'updated', 'deleted', 'trashed', 'untrashed' ), $_SERVER['REQUEST_URI'] );
+$_SERVER['REQUEST_URI'] = remove_query_arg( array( 'locked', 'skipped', 'updated', 'deleted', 'trashed', 'untrashed', 'notdeleted', 'nottrashed', 'notuntrashed' ), $_SERVER['REQUEST_URI'] );
 ?>
 
 <?php $wp_list_table->views(); ?>
