Index: wp-admin/includes/template.php
===================================================================
--- wp-admin/includes/template.php	(revision 17572)
+++ wp-admin/includes/template.php	(working copy)
@@ -90,26 +90,26 @@
 		'taxonomy' => 'category',
 		'checked_ontop' => true
 	);
+
 	extract( wp_parse_args($args, $defaults), EXTR_SKIP );
 
-	if ( empty($walker) || !is_a($walker, 'Walker') )
+	if ( empty($walker) || !is_a($walker, 'Walker') )  
 		$walker = new Walker_Category_Checklist;
 
 	$descendants_and_self = (int) $descendants_and_self;
-
 	$args = array('taxonomy' => $taxonomy);
-
 	$tax = get_taxonomy($taxonomy);
 	$args['disabled'] = !current_user_can($tax->cap->assign_terms);
 
 	if ( is_array( $selected_cats ) )
 		$args['selected_cats'] = $selected_cats;
-	elseif ( $post_id )
+	elseif ( $post_id ) 
 		$args['selected_cats'] = wp_get_object_terms($post_id, $taxonomy, array_merge($args, array('fields' => 'ids')));
 	else
 		$args['selected_cats'] = array();
 
 	if ( is_array( $popular_cats ) )
+
 		$args['popular_cats'] = $popular_cats;
 	else
 		$args['popular_cats'] = get_terms( $taxonomy, array( 'fields' => 'ids', 'orderby' => 'count', 'order' => 'DESC', 'number' => 10, 'hierarchical' => false ) );
@@ -122,23 +122,60 @@
 		$categories = (array) get_terms($taxonomy, array('get' => 'all'));
 	}
 
-	if ( $checked_ontop ) {
-		// Post process $categories rather than adding an exclude to the get_terms() query to keep the query the same across all posts (for any query cache)
-		$checked_categories = array();
-		$keys = array_keys( $categories );
+	// checked has three values: 0 means not checked at all, 1 means checked, and 2 means one ore more of its children are checked. 
+	foreach( $categories as $cat ) {
+		$cat->checked = 0;
+	}
 
-		foreach( $keys as $k ) {
-			if ( in_array( $categories[$k]->term_id, $args['selected_cats'] ) ) {
-				$checked_categories[] = $categories[$k];
-				unset( $categories[$k] );
+	$current_cat;
+	foreach( $args['selected_cats'] as $sc ) {
+		foreach( $categories as $cat ) {
+			if($cat->term_id == $sc) {
+				$current_cat = $cat;
 			}
 		}
 
-		// Put checked cats on top
-		echo call_user_func_array(array(&$walker, 'walk'), array($checked_categories, 0, $args));
+		$current_cat->checked = 1;
+
+		while($current_cat->parent != 0) {
+			foreach( $categories as $cat ) {
+				if($cat->term_id == $current_cat->parent) {
+					$current_cat = $cat;
+					$current_cat->checked = 2;
+				}
+			}
+		}
 	}
-	// Then the rest of them
-	echo call_user_func_array(array(&$walker, 'walk'), array($categories, 0, $args));
+
+	$final_categories = array();
+
+	foreach( $categories as $catk => $cat ) {
+		if ($cat->parent == 0 && $cat->checked == 1) {
+			$final_categories[] = $cat;
+			unset( $categories[$catk] );
+		}
+	}
+
+	foreach( $categories as $catk => $cat ) {
+		if ($cat->parent == 0 && $cat->checked == 2) {
+			$final_categories[] = $cat;
+			unset( $categories[$catk] );
+		}
+	}
+
+	foreach( $categories as $catk => $cat ) {
+		if ($cat->parent == 0) {
+			$final_categories[] = $cat;
+			unset( $categories[$catk] );
+		}
+	}
+
+	foreach( $categories as $catk => $cat ) {
+		$final_categories[] = $cat;
+		unset( $categories[$catk]);
+	}
+
+	echo call_user_func_array(array(&$walker, 'walk'), array($final_categories, 0, $args));
 }
 
 /**
