I would use the hook before_delete_post
as the last layer of protection against deletion (using @tf's solution, and which is the correct Answer).
And first remove the "Delete" options from sight. The following hides the Bulk Actions and the Empty Trash button, and removes the Delete Permanently row action.

With this code:
add_action( 'admin_head-edit.php', 'hide_delete_css_wpse_92155' );
add_filter( 'post_row_actions', 'hide_row_action_wpse_92155', 10, 2 );
add_filter( 'page_row_actions', 'hide_row_action_wpse_92155', 10, 2 );
function hide_delete_css_wpse_92155()
{
if( isset( $_REQUEST['post_status'] ) && 'trash' == $_REQUEST['post_status'] )
{
echo "<style>
.alignleft.actions:first-child, #delete_all {
display: none;
}
</style>";
}
}
function hide_row_action_wpse_92155( $actions, $post )
{
if( isset( $_REQUEST['post_status'] ) && 'trash' == $_REQUEST['post_status'] )
unset( $actions['delete'] );
return $actions;
}
This is the result:

Note of interest
There is no hook cpt_row_actions
. The hooks page_row_actions
and post_row_actions
are applied if the post type is hierarchical or not, respectively.