evolution-3.6.4/widgets/table/e-tree-sorted.c

No issues found

   1 /*
   2  * This program is free software; you can redistribute it and/or
   3  * modify it under the terms of the GNU Lesser General Public
   4  * License as published by the Free Software Foundation; either
   5  * version 2 of the License, or (at your option) version 3.
   6  *
   7  * This program is distributed in the hope that it will be useful,
   8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
   9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  10  * Lesser General Public License for more details.
  11  *
  12  * You should have received a copy of the GNU Lesser General Public
  13  * License along with the program; if not, see <http://www.gnu.org/licenses/>
  14  *
  15  *
  16  * Authors:
  17  *		Chris Lahey <clahey@ximian.com>
  18  *		Chris Toshok <toshok@ximian.com>
  19  *
  20  * Adapted from the gtree code and ETableModel.
  21  *
  22  * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
  23  *
  24  */
  25 
  26 /* FIXME: Overall e-tree-sorted.c needs to be made more efficient. */
  27 
  28 #ifdef HAVE_CONFIG_H
  29 #include <config.h>
  30 #endif
  31 
  32 #include <stdio.h>
  33 #include <errno.h>
  34 #include <stdlib.h>
  35 #include <unistd.h>
  36 #include <fcntl.h>
  37 #include <string.h>
  38 
  39 #include <libxml/parser.h>
  40 #include <libxml/xmlmemory.h>
  41 
  42 #include "e-util/e-util.h"
  43 #include "libevolution-utils/e-xml-utils.h"
  44 
  45 #include "e-table-sorting-utils.h"
  46 #include "e-tree-sorted.h"
  47 
  48 /* maximum insertions between an idle event that we will do without scheduling an idle sort */
  49 #define ETS_INSERT_MAX (4)
  50 
  51 #define d(x)
  52 
  53 #define E_TREE_SORTED_GET_PRIVATE(obj) \
  54 	(G_TYPE_INSTANCE_GET_PRIVATE \
  55 	((obj), E_TYPE_TREE_SORTED, ETreeSortedPrivate))
  56 
  57 G_DEFINE_TYPE (ETreeSorted, e_tree_sorted, E_TYPE_TREE_MODEL)
  58 
  59 enum {
  60 	NODE_RESORTED,
  61 	LAST_SIGNAL
  62 };
  63 
  64 static guint signals[LAST_SIGNAL] = {0, };
  65 
  66 typedef struct ETreeSortedPath ETreeSortedPath;
  67 
  68 struct ETreeSortedPath {
  69 	ETreePath         corresponding;
  70 
  71 	/* parent/child/sibling pointers */
  72 	ETreeSortedPath  *parent;
  73 	gint              num_children;
  74 	ETreeSortedPath **children;
  75 	gint               position;
  76 	gint               orig_position;
  77 
  78 	guint             needs_resort : 1;
  79 	guint             child_needs_resort : 1;
  80 	guint             resort_all_children : 1;
  81 	guint             needs_regen_to_sort : 1;
  82 };
  83 
  84 struct _ETreeSortedPrivate {
  85 	ETreeModel      *source;
  86 	ETreeSortedPath *root;
  87 
  88 	ETableSortInfo   *sort_info;
  89 	ETableHeader     *full_header;
  90 
  91 	ETreeSortedPath  *last_access;
  92 
  93 	gint          tree_model_pre_change_id;
  94 	gint          tree_model_no_change_id;
  95 	gint          tree_model_node_changed_id;
  96 	gint          tree_model_node_data_changed_id;
  97 	gint          tree_model_node_col_changed_id;
  98 	gint          tree_model_node_inserted_id;
  99 	gint          tree_model_node_removed_id;
 100 	gint          tree_model_node_deleted_id;
 101 	gint          tree_model_node_request_collapse_id;
 102 
 103 	gint          sort_info_changed_id;
 104 	gint          sort_idle_id;
 105 	gint          insert_idle_id;
 106 	gint          insert_count;
 107 
 108 	guint        in_resort_idle : 1;
 109 	guint        nested_resort_idle : 1;
 110 };
 111 
 112 enum {
 113 	ARG_0,
 114 
 115 	ARG_SORT_INFO
 116 };
 117 
 118 static void ets_sort_info_changed (ETableSortInfo *sort_info, ETreeSorted *ets);
 119 static void resort_node (ETreeSorted *ets, ETreeSortedPath *path, gboolean resort_all_children, gboolean needs_regen, gboolean send_signals);
 120 static void mark_path_needs_resort (ETreeSorted *ets, ETreeSortedPath *path, gboolean needs_rebuild, gboolean resort_all_children);
 121 static void schedule_resort (ETreeSorted *ets, ETreeSortedPath *path, gboolean needs_regen, gboolean resort_all_children);
 122 static void free_path (ETreeSortedPath *path);
 123 static void generate_children (ETreeSorted *ets, ETreeSortedPath *path);
 124 static void regenerate_children (ETreeSorted *ets, ETreeSortedPath *path);
 125 
 126 /* idle callbacks */
 127 
 128 static gboolean
 129 ets_sort_idle (gpointer user_data)
 130 {
 131 	ETreeSorted *ets = user_data;
 132 	if (ets->priv->in_resort_idle) {
 133 		ets->priv->nested_resort_idle = TRUE;
 134 		return FALSE;
 135 	}
 136 	ets->priv->in_resort_idle = TRUE;
 137 	if (ets->priv->root) {
 138 		do {
 139 			ets->priv->nested_resort_idle = FALSE;
 140 			resort_node (ets, ets->priv->root, FALSE, FALSE, TRUE);
 141 		} while (ets->priv->nested_resort_idle);
 142 	}
 143 	ets->priv->in_resort_idle = FALSE;
 144 	ets->priv->sort_idle_id = 0;
 145 	return FALSE;
 146 }
 147 
 148 #define ETS_SORT_IDLE_ACTIVATED(ets) ((ets)->priv->sort_idle_id != 0)
 149 
 150 inline static void
 151 ets_stop_sort_idle (ETreeSorted *ets)
 152 {
 153 	if (ets->priv->sort_idle_id) {
 154 		g_source_remove (ets->priv->sort_idle_id);
 155 		ets->priv->sort_idle_id = 0;
 156 	}
 157 }
 158 
 159 static gboolean
 160 ets_insert_idle (ETreeSorted *ets)
 161 {
 162 	ets->priv->insert_count = 0;
 163 	ets->priv->insert_idle_id = 0;
 164 	return FALSE;
 165 }
 166 
 167 /* Helper functions */
 168 
 169 #define CHECK_AROUND_LAST_ACCESS
 170 
 171 static inline ETreeSortedPath *
 172 check_last_access (ETreeSorted *ets,
 173                    ETreePath corresponding)
 174 {
 175 #ifdef CHECK_AROUND_LAST_ACCESS
 176 	ETreeSortedPath *parent;
 177 #endif
 178 
 179 	if (ets->priv->last_access == NULL)
 180 		return NULL;
 181 
 182 	if (ets->priv->last_access == corresponding) {
 183 		d (g_print ("Found last access %p at %p.", ets->priv->last_access, ets->priv->last_access));
 184 		return ets->priv->last_access;
 185 	}
 186 
 187 #ifdef CHECK_AROUND_LAST_ACCESS
 188 	parent = ets->priv->last_access->parent;
 189 	if (parent && parent->children) {
 190 		gint position = ets->priv->last_access->position;
 191 		gint end = MIN (parent->num_children, position + 10);
 192 		gint start = MAX (0, position - 10);
 193 		gint initial = MAX (MIN (position, end), start);
 194 		gint i;
 195 
 196 		for (i = initial; i < end; i++) {
 197 			if (parent->children[i] && parent->children[i]->corresponding == corresponding) {
 198 				d (g_print ("Found last access %p at %p.", ets->priv->last_access, parent->children[i]));
 199 				return parent->children[i];
 200 			}
 201 		}
 202 
 203 		for (i = initial - 1; i >= start; i--) {
 204 			if (parent->children[i] && parent->children[i]->corresponding == corresponding) {
 205 				d (g_print ("Found last access %p at %p.", ets->priv->last_access, parent->children[i]));
 206 				return parent->children[i];
 207 			}
 208 		}
 209 	}
 210 #endif
 211 	return NULL;
 212 }
 213 
 214 static ETreeSortedPath *
 215 find_path (ETreeSorted *ets,
 216            ETreePath corresponding)
 217 {
 218 	gint depth;
 219 	ETreePath *sequence;
 220 	gint i;
 221 	ETreeSortedPath *path;
 222 	ETreeSortedPath *check_last;
 223 
 224 	if (corresponding == NULL)
 225 		return NULL;
 226 
 227 	check_last = check_last_access (ets, corresponding);
 228 	if (check_last) {
 229 		d (g_print (" (find_path)\n"));
 230 		return check_last;
 231 	}
 232 
 233 	depth = e_tree_model_node_depth (ets->priv->source, corresponding);
 234 
 235 	sequence = g_new (ETreePath, depth + 1);
 236 
 237 	sequence[0] = corresponding;
 238 
 239 	for (i = 0; i < depth; i++)
 240 		sequence[i + 1] = e_tree_model_node_get_parent (ets->priv->source, sequence[i]);
 241 
 242 	path = ets->priv->root;
 243 
 244 	for (i = depth - 1; i >= 0 && path != NULL; i--) {
 245 		gint j;
 246 
 247 		if (path->num_children == -1) {
 248 			path = NULL;
 249 			break;
 250 		}
 251 
 252 		for (j = 0; j < path->num_children; j++) {
 253 			if (path->children[j]->corresponding == sequence[i]) {
 254 				break;
 255 			}
 256 		}
 257 
 258 		if (j < path->num_children) {
 259 			path = path->children[j];
 260 		} else {
 261 			path = NULL;
 262 		}
 263 	}
 264 	g_free (sequence);
 265 
 266 	d (g_print ("Didn't find last access %p.  Setting to %p. (find_path)\n", ets->priv->last_access, path));
 267 	ets->priv->last_access = path;
 268 
 269 	return path;
 270 }
 271 
 272 static ETreeSortedPath *
 273 find_child_path (ETreeSorted *ets,
 274                  ETreeSortedPath *parent,
 275                  ETreePath corresponding)
 276 {
 277 	gint i;
 278 
 279 	if (corresponding == NULL)
 280 		return NULL;
 281 
 282 	if (parent->num_children == -1) {
 283 		return NULL;
 284 	}
 285 
 286 	for (i = 0; i < parent->num_children; i++)
 287 		if (parent->children[i]->corresponding == corresponding)
 288 			return parent->children[i];
 289 
 290 	return NULL;
 291 }
 292 
 293 static ETreeSortedPath *
 294 find_or_create_path (ETreeSorted *ets,
 295                      ETreePath corresponding)
 296 {
 297 	gint depth;
 298 	ETreePath *sequence;
 299 	gint i;
 300 	ETreeSortedPath *path;
 301 	ETreeSortedPath *check_last;
 302 
 303 	if (corresponding == NULL)
 304 		return NULL;
 305 
 306 	check_last = check_last_access (ets, corresponding);
 307 	if (check_last) {
 308 		d (g_print (" (find_or_create_path)\n"));
 309 		return check_last;
 310 	}
 311 
 312 	depth = e_tree_model_node_depth (ets->priv->source, corresponding);
 313 
 314 	sequence = g_new (ETreePath, depth + 1);
 315 
 316 	sequence[0] = corresponding;
 317 
 318 	for (i = 0; i < depth; i++)
 319 		sequence[i + 1] = e_tree_model_node_get_parent (ets->priv->source, sequence[i]);
 320 
 321 	path = ets->priv->root;
 322 
 323 	for (i = depth - 1; i >= 0 && path != NULL; i--) {
 324 		gint j;
 325 
 326 		if (path->num_children == -1) {
 327 			generate_children (ets, path);
 328 		}
 329 
 330 		for (j = 0; j < path->num_children; j++) {
 331 			if (path->children[j]->corresponding == sequence[i]) {
 332 				break;
 333 			}
 334 		}
 335 
 336 		if (j < path->num_children) {
 337 			path = path->children[j];
 338 		} else {
 339 			path = NULL;
 340 		}
 341 	}
 342 	g_free (sequence);
 343 
 344 	d (g_print ("Didn't find last access %p.  Setting to %p. (find_or_create_path)\n", ets->priv->last_access, path));
 345 	ets->priv->last_access = path;
 346 
 347 	return path;
 348 }
 349 
 350 static void
 351 free_children (ETreeSortedPath *path)
 352 {
 353 	gint i;
 354 
 355 	if (path == NULL)
 356 		return;
 357 
 358 	for (i = 0; i < path->num_children; i++) {
 359 		free_path (path->children[i]);
 360 	}
 361 
 362 	g_free (path->children);
 363 	path->children = NULL;
 364 	path->num_children = -1;
 365 }
 366 
 367 static void
 368 free_path (ETreeSortedPath *path)
 369 {
 370 	free_children (path);
 371 	g_slice_free (ETreeSortedPath, path);
 372 }
 373 
 374 static ETreeSortedPath *
 375 new_path (ETreeSortedPath *parent,
 376           ETreePath corresponding)
 377 {
 378 	ETreeSortedPath *path;
 379 
 380 	path = g_slice_new0 (ETreeSortedPath);
 381 
 382 	path->corresponding = corresponding;
 383 	path->parent = parent;
 384 	path->num_children = -1;
 385 	path->children = NULL;
 386 	path->position = -1;
 387 	path->orig_position = -1;
 388 	path->child_needs_resort = 0;
 389 	path->resort_all_children = 0;
 390 	path->needs_resort = 0;
 391 	path->needs_regen_to_sort = 0;
 392 
 393 	return path;
 394 }
 395 
 396 static gboolean
 397 reposition_path (ETreeSorted *ets,
 398                  ETreeSortedPath *path)
 399 {
 400 	gint new_index;
 401 	gint old_index = path->position;
 402 	ETreeSortedPath *parent = path->parent;
 403 	gboolean changed = FALSE;
 404 	if (parent) {
 405 		if (ets->priv->sort_idle_id == 0) {
 406 			if (ets->priv->insert_count > ETS_INSERT_MAX) {
 407 				/* schedule a sort, and append instead */
 408 				schedule_resort (ets, parent, TRUE, FALSE);
 409 			} else {
 410 				/* make sure we have an idle handler to reset the count every now and then */
 411 				if (ets->priv->insert_idle_id == 0) {
 412 					ets->priv->insert_idle_id = g_idle_add_full (40, (GSourceFunc) ets_insert_idle, ets, NULL);
 413 				}
 414 
 415 				new_index = e_table_sorting_utils_tree_check_position
 416 					(E_TREE_MODEL (ets),
 417 					 ets->priv->sort_info,
 418 					 ets->priv->full_header,
 419 					 (ETreePath *) parent->children,
 420 					 parent->num_children,
 421 					 old_index);
 422 
 423 				if (new_index > old_index) {
 424 					gint i;
 425 					ets->priv->insert_count++;
 426 					memmove (parent->children + old_index, parent->children + old_index + 1, sizeof (ETreePath) * (new_index - old_index));
 427 					parent->children[new_index] = path;
 428 					for (i = old_index; i <= new_index; i++)
 429 						parent->children[i]->position = i;
 430 					changed = TRUE;
 431 					e_tree_model_node_changed (E_TREE_MODEL (ets), parent);
 432 					e_tree_sorted_node_resorted (ets, parent);
 433 				} else if (new_index < old_index) {
 434 					gint i;
 435 					ets->priv->insert_count++;
 436 					memmove (parent->children + new_index + 1, parent->children + new_index, sizeof (ETreePath) * (old_index - new_index));
 437 					parent->children[new_index] = path;
 438 					for (i = new_index; i <= old_index; i++)
 439 						parent->children[i]->position = i;
 440 					changed = TRUE;
 441 					e_tree_model_node_changed (E_TREE_MODEL (ets), parent);
 442 					e_tree_sorted_node_resorted (ets, parent);
 443 				}
 444 			}
 445 		} else
 446 			mark_path_needs_resort (ets, parent, TRUE, FALSE);
 447 	}
 448 	return changed;
 449 }
 450 
 451 static void
 452 regenerate_children (ETreeSorted *ets,
 453                      ETreeSortedPath *path)
 454 {
 455 	ETreeSortedPath **children;
 456 	gint i;
 457 
 458 	children = g_new (ETreeSortedPath *, path->num_children);
 459 	for (i = 0; i < path->num_children; i++)
 460 		children[path->children[i]->orig_position] = path->children[i];
 461 	g_free (path->children);
 462 	path->children = children;
 463 }
 464 
 465 static void
 466 generate_children (ETreeSorted *ets,
 467                    ETreeSortedPath *path)
 468 {
 469 	ETreePath child;
 470 	gint i;
 471 	gint count;
 472 
 473 	free_children (path);
 474 
 475 	count = 0;
 476 	for (child = e_tree_model_node_get_first_child (ets->priv->source, path->corresponding);
 477 	     child;
 478 	     child = e_tree_model_node_get_next (ets->priv->source, child)) {
 479 		count++;
 480 	}
 481 
 482 	path->num_children = count;
 483 	path->children = g_new (ETreeSortedPath *, count);
 484 	for (child = e_tree_model_node_get_first_child (ets->priv->source, path->corresponding), i = 0;
 485 	     child;
 486 	     child = e_tree_model_node_get_next (ets->priv->source, child), i++) {
 487 		path->children[i] = new_path (path, child);
 488 		path->children[i]->position = i;
 489 		path->children[i]->orig_position = i;
 490 	}
 491 	if (path->num_children > 0)
 492 		schedule_resort (ets, path, FALSE, TRUE);
 493 }
 494 
 495 static void
 496 resort_node (ETreeSorted *ets,
 497              ETreeSortedPath *path,
 498              gboolean resort_all_children,
 499              gboolean needs_regen,
 500              gboolean send_signals)
 501 {
 502 	gboolean needs_resort;
 503 	if (path) {
 504 		needs_resort = path->needs_resort || resort_all_children;
 505 		needs_regen = path->needs_regen_to_sort || needs_regen;
 506 		if (path->num_children > 0) {
 507 			if (needs_resort && send_signals)
 508 				e_tree_model_pre_change (E_TREE_MODEL (ets));
 509 			if (needs_resort) {
 510 				gint i;
 511 				d (g_print ("Start sort of node %p\n", path));
 512 				if (needs_regen)
 513 					regenerate_children (ets, path);
 514 				d (g_print ("Regened sort of node %p\n", path));
 515 				e_table_sorting_utils_tree_sort (
 516 					E_TREE_MODEL (ets),
 517 					ets->priv->sort_info,
 518 					ets->priv->full_header,
 519 					(ETreePath *) path->children,
 520 					path->num_children);
 521 				d (g_print ("Renumbering sort of node %p\n", path));
 522 				for (i = 0; i < path->num_children; i++) {
 523 					path->children[i]->position = i;
 524 				}
 525 				d (g_print ("End sort of node %p\n", path));
 526 			}
 527 			if (path->resort_all_children)
 528 				resort_all_children = TRUE;
 529 			if ((resort_all_children || path->child_needs_resort) && path->num_children >= 0) {
 530 				gint i;
 531 				for (i = 0; i < path->num_children; i++) {
 532 					resort_node (ets, path->children[i], resort_all_children, needs_regen, send_signals && !needs_resort);
 533 				}
 534 				path->child_needs_resort = 0;
 535 			}
 536 		}
 537 		path->needs_resort = 0;
 538 		path->child_needs_resort = 0;
 539 		path->needs_regen_to_sort = 0;
 540 		path->resort_all_children = 0;
 541 		if (needs_resort && send_signals && path->num_children > 0) {
 542 			e_tree_model_node_changed (E_TREE_MODEL (ets), path);
 543 			e_tree_sorted_node_resorted (ets, path);
 544 		}
 545 	}
 546 }
 547 
 548 static void
 549 mark_path_child_needs_resort (ETreeSorted *ets,
 550                               ETreeSortedPath *path)
 551 {
 552 	if (path == NULL)
 553 		return;
 554 	if (!path->child_needs_resort) {
 555 		path->child_needs_resort = 1;
 556 		mark_path_child_needs_resort (ets, path->parent);
 557 	}
 558 }
 559 
 560 static void
 561 mark_path_needs_resort (ETreeSorted *ets,
 562                         ETreeSortedPath *path,
 563                         gboolean needs_regen,
 564                         gboolean resort_all_children)
 565 {
 566 	if (path == NULL)
 567 		return;
 568 	if (path->num_children == 0)
 569 		return;
 570 	path->needs_resort = 1;
 571 	path->needs_regen_to_sort = needs_regen;
 572 	path->resort_all_children = resort_all_children;
 573 	mark_path_child_needs_resort (ets, path->parent);
 574 }
 575 
 576 static void
 577 schedule_resort (ETreeSorted *ets,
 578                  ETreeSortedPath *path,
 579                  gboolean needs_regen,
 580                  gboolean resort_all_children)
 581 {
 582 	ets->priv->insert_count = 0;
 583 	if (ets->priv->insert_idle_id != 0) {
 584 		g_source_remove (ets->priv->insert_idle_id);
 585 		ets->priv->insert_idle_id = 0;
 586 	}
 587 
 588 	if (path == NULL)
 589 		return;
 590 	if (path->num_children == 0)
 591 		return;
 592 
 593 	mark_path_needs_resort (ets, path, needs_regen, resort_all_children);
 594 	if (ets->priv->sort_idle_id == 0) {
 595 		ets->priv->sort_idle_id = g_idle_add_full (50, (GSourceFunc) ets_sort_idle, ets, NULL);
 596 	} else if (ets->priv->in_resort_idle) {
 597 		ets->priv->nested_resort_idle = TRUE;
 598 	}
 599 }
 600 
 601 /* virtual methods */
 602 
 603 static void
 604 ets_dispose (GObject *object)
 605 {
 606 	ETreeSortedPrivate *priv;
 607 
 608 	priv = E_TREE_SORTED_GET_PRIVATE (object);
 609 
 610 	if (priv->source) {
 611 		g_signal_handler_disconnect (
 612 			priv->source, priv->tree_model_pre_change_id);
 613 		g_signal_handler_disconnect (
 614 			priv->source, priv->tree_model_no_change_id);
 615 		g_signal_handler_disconnect (
 616 			priv->source, priv->tree_model_node_changed_id);
 617 		g_signal_handler_disconnect (
 618 			priv->source, priv->tree_model_node_data_changed_id);
 619 		g_signal_handler_disconnect (
 620 			priv->source, priv->tree_model_node_col_changed_id);
 621 		g_signal_handler_disconnect (
 622 			priv->source, priv->tree_model_node_inserted_id);
 623 		g_signal_handler_disconnect (
 624 			priv->source, priv->tree_model_node_removed_id);
 625 		g_signal_handler_disconnect (
 626 			priv->source, priv->tree_model_node_deleted_id);
 627 		g_signal_handler_disconnect (
 628 			priv->source, priv->tree_model_node_request_collapse_id);
 629 
 630 		g_object_unref (priv->source);
 631 		priv->source = NULL;
 632 
 633 		priv->tree_model_pre_change_id = 0;
 634 		priv->tree_model_no_change_id = 0;
 635 		priv->tree_model_node_changed_id = 0;
 636 		priv->tree_model_node_data_changed_id = 0;
 637 		priv->tree_model_node_col_changed_id = 0;
 638 		priv->tree_model_node_inserted_id = 0;
 639 		priv->tree_model_node_removed_id = 0;
 640 		priv->tree_model_node_deleted_id = 0;
 641 		priv->tree_model_node_request_collapse_id = 0;
 642 	}
 643 
 644 	if (priv->sort_info) {
 645 		g_signal_handler_disconnect (
 646 			priv->sort_info, priv->sort_info_changed_id);
 647 		priv->sort_info_changed_id = 0;
 648 
 649 		g_object_unref (priv->sort_info);
 650 		priv->sort_info = NULL;
 651 	}
 652 
 653 	ets_stop_sort_idle (E_TREE_SORTED (object));
 654 
 655 	if (priv->insert_idle_id) {
 656 		g_source_remove (priv->insert_idle_id);
 657 		priv->insert_idle_id = 0;
 658 	}
 659 
 660 	if (priv->full_header) {
 661 		g_object_unref (priv->full_header);
 662 		priv->full_header = NULL;
 663 	}
 664 
 665 	/* Chain up to parent's dispose() method. */
 666 	G_OBJECT_CLASS (e_tree_sorted_parent_class)->dispose (object);
 667 }
 668 
 669 static void
 670 ets_finalize (GObject *object)
 671 {
 672 	ETreeSortedPrivate *priv;
 673 
 674 	priv = E_TREE_SORTED_GET_PRIVATE (object);
 675 
 676 	if (priv->root)
 677 		free_path (priv->root);
 678 
 679 	/* Chain up to parent's finalize() method. */
 680 	G_OBJECT_CLASS (e_tree_sorted_parent_class)->finalize (object);
 681 }
 682 
 683 static ETreePath
 684 ets_get_root (ETreeModel *etm)
 685 {
 686 	ETreeSortedPrivate *priv = E_TREE_SORTED (etm)->priv;
 687 	if (priv->root == NULL) {
 688 		ETreeSorted *ets = E_TREE_SORTED (etm);
 689 		ETreePath corresponding = e_tree_model_get_root (ets->priv->source);
 690 
 691 		if (corresponding) {
 692 			priv->root = new_path (NULL, corresponding);
 693 		}
 694 	}
 695 	if (priv->root && priv->root->num_children == -1) {
 696 		generate_children (E_TREE_SORTED (etm), priv->root);
 697 	}
 698 
 699 	return priv->root;
 700 }
 701 
 702 static ETreePath
 703 ets_get_parent (ETreeModel *etm,
 704                 ETreePath node)
 705 {
 706 	ETreeSortedPath *path = node;
 707 	return path->parent;
 708 }
 709 
 710 static ETreePath
 711 ets_get_first_child (ETreeModel *etm,
 712                      ETreePath node)
 713 {
 714 	ETreeSortedPath *path = node;
 715 	ETreeSorted *ets = E_TREE_SORTED (etm);
 716 
 717 	if (path->num_children == -1)
 718 		generate_children (ets, path);
 719 
 720 	if (path->num_children > 0)
 721 		return path->children[0];
 722 	else
 723 		return NULL;
 724 }
 725 
 726 static ETreePath
 727 ets_get_last_child (ETreeModel *etm,
 728                     ETreePath node)
 729 {
 730 	ETreeSortedPath *path = node;
 731 	ETreeSorted *ets = E_TREE_SORTED (etm);
 732 
 733 	if (path->num_children == -1)
 734 		generate_children (ets, path);
 735 
 736 	if (path->num_children > 0)
 737 		return path->children[path->num_children - 1];
 738 	else
 739 		return NULL;
 740 }
 741 
 742 static ETreePath
 743 ets_get_next (ETreeModel *etm,
 744               ETreePath node)
 745 {
 746 	ETreeSortedPath *path = node;
 747 	ETreeSortedPath *parent = path->parent;
 748 	if (parent) {
 749 		if (parent->num_children > path->position + 1)
 750 			return parent->children[path->position + 1];
 751 		else
 752 			return NULL;
 753 	} else
 754 		  return NULL;
 755 }
 756 
 757 static ETreePath
 758 ets_get_prev (ETreeModel *etm,
 759               ETreePath node)
 760 {
 761 	ETreeSortedPath *path = node;
 762 	ETreeSortedPath *parent = path->parent;
 763 	if (parent) {
 764 		if (path->position - 1 >= 0)
 765 			return parent->children[path->position - 1];
 766 		else
 767 			return NULL;
 768 	} else
 769 		  return NULL;
 770 }
 771 
 772 static gboolean
 773 ets_is_root (ETreeModel *etm,
 774              ETreePath node)
 775 {
 776 	ETreeSortedPath *path = node;
 777 	ETreeSorted *ets = E_TREE_SORTED (etm);
 778 
 779 	return e_tree_model_node_is_root (ets->priv->source, path->corresponding);
 780 }
 781 
 782 static gboolean
 783 ets_is_expandable (ETreeModel *etm,
 784                    ETreePath node)
 785 {
 786 	ETreeSortedPath *path = node;
 787 	ETreeSorted *ets = E_TREE_SORTED (etm);
 788 	gboolean expandable = e_tree_model_node_is_expandable (ets->priv->source, path->corresponding);
 789 
 790 	if (path->num_children == -1) {
 791 		generate_children (ets, node);
 792 	}
 793 
 794 	return expandable;
 795 }
 796 
 797 static guint
 798 ets_get_children (ETreeModel *etm,
 799                   ETreePath node,
 800                   ETreePath **nodes)
 801 {
 802 	ETreeSortedPath *path = node;
 803 	guint n_children;
 804 
 805 	if (path->num_children == -1) {
 806 		generate_children (E_TREE_SORTED (etm), node);
 807 	}
 808 
 809 	n_children = path->num_children;
 810 
 811 	if (nodes) {
 812 		gint i;
 813 
 814 		(*nodes) = g_malloc (sizeof (ETreePath) * n_children);
 815 		for (i = 0; i < n_children; i++) {
 816 			(*nodes)[i] = path->children[i];
 817 		}
 818 	}
 819 
 820 	return n_children;
 821 }
 822 
 823 static guint
 824 ets_depth (ETreeModel *etm,
 825            ETreePath node)
 826 {
 827 	ETreeSortedPath *path = node;
 828 	ETreeSorted *ets = E_TREE_SORTED (etm);
 829 
 830 	return e_tree_model_node_depth (ets->priv->source, path->corresponding);
 831 }
 832 
 833 static GdkPixbuf *
 834 ets_icon_at (ETreeModel *etm,
 835              ETreePath node)
 836 {
 837 	ETreeSortedPath *path = node;
 838 	ETreeSorted *ets = E_TREE_SORTED (etm);
 839 
 840 	return e_tree_model_icon_at (ets->priv->source, path->corresponding);
 841 }
 842 
 843 static gboolean
 844 ets_get_expanded_default (ETreeModel *etm)
 845 {
 846 	ETreeSorted *ets = E_TREE_SORTED (etm);
 847 
 848 	return e_tree_model_get_expanded_default (ets->priv->source);
 849 }
 850 
 851 static gint
 852 ets_column_count (ETreeModel *etm)
 853 {
 854 	ETreeSorted *ets = E_TREE_SORTED (etm);
 855 
 856 	return e_tree_model_column_count (ets->priv->source);
 857 }
 858 
 859 static gboolean
 860 ets_has_save_id (ETreeModel *etm)
 861 {
 862 	return TRUE;
 863 }
 864 
 865 static gchar *
 866 ets_get_save_id (ETreeModel *etm,
 867                  ETreePath node)
 868 {
 869 	ETreeSorted *ets = E_TREE_SORTED (etm);
 870 	ETreeSortedPath *path = node;
 871 
 872 	if (e_tree_model_has_save_id (ets->priv->source))
 873 		return e_tree_model_get_save_id (ets->priv->source, path->corresponding);
 874 	else
 875 		return g_strdup_printf ("%p", path->corresponding);
 876 }
 877 
 878 static gboolean
 879 ets_has_get_node_by_id (ETreeModel *etm)
 880 {
 881 	ETreeSorted *ets = E_TREE_SORTED (etm);
 882 	return e_tree_model_has_get_node_by_id (ets->priv->source);
 883 }
 884 
 885 static ETreePath
 886 ets_get_node_by_id (ETreeModel *etm,
 887                     const gchar *save_id)
 888 {
 889 	ETreeSorted *ets = E_TREE_SORTED (etm);
 890 	ETreePath node;
 891 
 892 	node = e_tree_model_get_node_by_id (ets->priv->source, save_id);
 893 
 894 	return find_path (ets, node);
 895 }
 896 
 897 static gboolean
 898 ets_has_change_pending (ETreeModel *etm)
 899 {
 900 	ETreeSorted *ets = E_TREE_SORTED (etm);
 901 
 902 	return ets->priv->sort_idle_id != 0;
 903 }
 904 
 905 static gpointer
 906 ets_value_at (ETreeModel *etm,
 907               ETreePath node,
 908               gint col)
 909 {
 910 	ETreeSorted *ets = E_TREE_SORTED (etm);
 911 	ETreeSortedPath *path = node;
 912 
 913 	return e_tree_model_value_at (ets->priv->source, path->corresponding, col);
 914 }
 915 
 916 static void
 917 ets_set_value_at (ETreeModel *etm,
 918                   ETreePath node,
 919                   gint col,
 920                   gconstpointer val)
 921 {
 922 	ETreeSorted *ets = E_TREE_SORTED (etm);
 923 	ETreeSortedPath *path = node;
 924 
 925 	e_tree_model_set_value_at (ets->priv->source, path->corresponding, col, val);
 926 }
 927 
 928 static gboolean
 929 ets_is_editable (ETreeModel *etm,
 930                  ETreePath node,
 931                  gint col)
 932 {
 933 	ETreeSorted *ets = E_TREE_SORTED (etm);
 934 	ETreeSortedPath *path = node;
 935 
 936 	return e_tree_model_node_is_editable (ets->priv->source, path->corresponding, col);
 937 }
 938 
 939 /* The default for ets_duplicate_value is to return the raw value. */
 940 static gpointer
 941 ets_duplicate_value (ETreeModel *etm,
 942                      gint col,
 943                      gconstpointer value)
 944 {
 945 	ETreeSorted *ets = E_TREE_SORTED (etm);
 946 
 947 	return e_tree_model_duplicate_value (ets->priv->source, col, value);
 948 }
 949 
 950 static void
 951 ets_free_value (ETreeModel *etm,
 952                 gint col,
 953                 gpointer value)
 954 {
 955 	ETreeSorted *ets = E_TREE_SORTED (etm);
 956 
 957 	e_tree_model_free_value (ets->priv->source, col, value);
 958 }
 959 
 960 static gpointer
 961 ets_initialize_value (ETreeModel *etm,
 962                       gint col)
 963 {
 964 	ETreeSorted *ets = E_TREE_SORTED (etm);
 965 
 966 	return e_tree_model_initialize_value (ets->priv->source, col);
 967 }
 968 
 969 static gboolean
 970 ets_value_is_empty (ETreeModel *etm,
 971                     gint col,
 972                     gconstpointer value)
 973 {
 974 	ETreeSorted *ets = E_TREE_SORTED (etm);
 975 
 976 	return e_tree_model_value_is_empty (ets->priv->source, col, value);
 977 }
 978 
 979 static gchar *
 980 ets_value_to_string (ETreeModel *etm,
 981                      gint col,
 982                      gconstpointer value)
 983 {
 984 	ETreeSorted *ets = E_TREE_SORTED (etm);
 985 
 986 	return e_tree_model_value_to_string (ets->priv->source, col, value);
 987 }
 988 
 989 /* Proxy functions */
 990 
 991 static void
 992 ets_proxy_pre_change (ETreeModel *etm,
 993                       ETreeSorted *ets)
 994 {
 995 	e_tree_model_pre_change (E_TREE_MODEL (ets));
 996 }
 997 
 998 static void
 999 ets_proxy_no_change (ETreeModel *etm,
1000                      ETreeSorted *ets)
1001 {
1002 	e_tree_model_no_change (E_TREE_MODEL (ets));
1003 }
1004 
1005 static void
1006 ets_proxy_node_changed (ETreeModel *etm,
1007                         ETreePath node,
1008                         ETreeSorted *ets)
1009 {
1010 	ets->priv->last_access = NULL;
1011 	d (g_print ("Setting last access %p. (ets_proxy_node_changed)\n", ets->priv->last_access));
1012 
1013 	if (e_tree_model_node_is_root (ets->priv->source, node)) {
1014 		ets_stop_sort_idle (ets);
1015 
1016 		if (ets->priv->root) {
1017 			free_path (ets->priv->root);
1018 		}
1019 		ets->priv->root = new_path (NULL, node);
1020 		e_tree_model_node_changed (E_TREE_MODEL (ets), ets->priv->root);
1021 		return;
1022 	} else {
1023 		ETreeSortedPath *path = find_path (ets, node);
1024 
1025 		if (path) {
1026 			free_children (path);
1027 			if (!reposition_path (ets, path)) {
1028 				e_tree_model_node_changed (E_TREE_MODEL (ets), path);
1029 			} else {
1030 				e_tree_model_no_change (E_TREE_MODEL (ets));
1031 			}
1032 		} else {
1033 			e_tree_model_no_change (E_TREE_MODEL (ets));
1034 		}
1035 	}
1036 }
1037 
1038 static void
1039 ets_proxy_node_data_changed (ETreeModel *etm,
1040                              ETreePath node,
1041                              ETreeSorted *ets)
1042 {
1043 	ETreeSortedPath *path = find_path (ets, node);
1044 
1045 	if (path) {
1046 		if (!reposition_path (ets, path))
1047 			e_tree_model_node_data_changed (E_TREE_MODEL (ets), path);
1048 		else
1049 			e_tree_model_no_change (E_TREE_MODEL (ets));
1050 	} else
1051 		e_tree_model_no_change (E_TREE_MODEL (ets));
1052 }
1053 
1054 static void
1055 ets_proxy_node_col_changed (ETreeModel *etm,
1056                             ETreePath node,
1057                             gint col,
1058                             ETreeSorted *ets)
1059 {
1060 	ETreeSortedPath *path = find_path (ets, node);
1061 
1062 	if (path) {
1063 		gboolean changed = FALSE;
1064 		if (e_table_sorting_utils_affects_sort (ets->priv->sort_info, ets->priv->full_header, col))
1065 			changed = reposition_path (ets, path);
1066 		if (!changed)
1067 			e_tree_model_node_col_changed (E_TREE_MODEL (ets), path, col);
1068 		else
1069 			e_tree_model_no_change (E_TREE_MODEL (ets));
1070 	} else
1071 		e_tree_model_no_change (E_TREE_MODEL (ets));
1072 }
1073 
1074 static void
1075 ets_proxy_node_inserted (ETreeModel *etm,
1076                          ETreePath parent,
1077                          ETreePath child,
1078                          ETreeSorted *ets)
1079 {
1080 	ETreeSortedPath *parent_path = find_path (ets, parent);
1081 
1082 	if (parent_path && parent_path->num_children != -1) {
1083 		gint i;
1084 		gint j;
1085 		ETreeSortedPath *path;
1086 		gint position = parent_path->num_children;
1087 		ETreePath counter;
1088 
1089 		for (counter = e_tree_model_node_get_next (etm, child);
1090 		     counter;
1091 		     counter = e_tree_model_node_get_next (etm, counter))
1092 			position--;
1093 
1094 		if (position != parent_path->num_children) {
1095 			for (i = 0; i < parent_path->num_children; i++) {
1096 				if (parent_path->children[i]->orig_position >= position)
1097 					parent_path->children[i]->orig_position++;
1098 			}
1099 		}
1100 
1101 		i = parent_path->num_children;
1102 		path = new_path (parent_path, child);
1103 		path->orig_position = position;
1104 		if (!ETS_SORT_IDLE_ACTIVATED (ets)) {
1105 			ets->priv->insert_count++;
1106 			if (ets->priv->insert_count > ETS_INSERT_MAX) {
1107 				/* schedule a sort, and append instead */
1108 				schedule_resort (ets, parent_path, TRUE, FALSE);
1109 			} else {
1110 				/* make sure we have an idle handler to reset the count every now and then */
1111 				if (ets->priv->insert_idle_id == 0) {
1112 					ets->priv->insert_idle_id = g_idle_add_full (40, (GSourceFunc) ets_insert_idle, ets, NULL);
1113 				}
1114 				i = e_table_sorting_utils_tree_insert
1115 					(ets->priv->source,
1116 					 ets->priv->sort_info,
1117 					 ets->priv->full_header,
1118 					 (ETreePath *) parent_path->children,
1119 					 parent_path->num_children,
1120 					 path);
1121 			}
1122 		} else {
1123 			mark_path_needs_resort (ets, parent_path, TRUE, FALSE);
1124 		}
1125 		parent_path->num_children++;
1126 		parent_path->children = g_renew (ETreeSortedPath *, parent_path->children, parent_path->num_children);
1127 		memmove (parent_path->children + i + 1, parent_path->children + i, (parent_path->num_children - 1 - i) * sizeof (gint));
1128 		parent_path->children[i] = path;
1129 		for (j = i; j < parent_path->num_children; j++) {
1130 			parent_path->children[j]->position = j;
1131 		}
1132 		e_tree_model_node_inserted (E_TREE_MODEL (ets), parent_path, parent_path->children[i]);
1133 	} else if (ets->priv->root == NULL && parent == NULL) {
1134 		if (child) {
1135 			ets->priv->root = new_path (NULL, child);
1136 			e_tree_model_node_inserted (E_TREE_MODEL (ets), NULL, ets->priv->root);
1137 		} else {
1138 			e_tree_model_no_change (E_TREE_MODEL (ets));
1139 		}
1140 	} else {
1141 		e_tree_model_no_change (E_TREE_MODEL (ets));
1142 	}
1143 }
1144 
1145 static void
1146 ets_proxy_node_removed (ETreeModel *etm,
1147                         ETreePath parent,
1148                         ETreePath child,
1149                         gint old_position,
1150                         ETreeSorted *ets)
1151 {
1152 	ETreeSortedPath *parent_path = find_path (ets, parent);
1153 	ETreeSortedPath *path;
1154 
1155 	if (parent_path)
1156 		path = find_child_path (ets, parent_path, child);
1157 	else
1158 		path = find_path (ets, child);
1159 
1160 	d (g_print ("Setting last access %p. (ets_proxy_node_removed)\n ", ets->priv->last_access));
1161 	ets->priv->last_access = NULL;
1162 
1163 	if (path && parent_path && parent_path->num_children != -1) {
1164 		gint i;
1165 		for (i = 0; i < parent_path->num_children; i++) {
1166 			if (parent_path->children[i]->orig_position > old_position)
1167 				parent_path->children[i]->orig_position--;
1168 		}
1169 
1170 		i = path->position;
1171 
1172 		parent_path->num_children--;
1173 		memmove (parent_path->children + i, parent_path->children + i + 1, sizeof (ETreeSortedPath *) * (parent_path->num_children - i));
1174 		for (; i < parent_path->num_children; i++) {
1175 			parent_path->children[i]->position = i;
1176 		}
1177 		e_tree_model_node_removed (E_TREE_MODEL (ets), parent_path, path, path->position);
1178 		free_path (path);
1179 	} else if (path && path == ets->priv->root) {
1180 		ets->priv->root = NULL;
1181 		e_tree_model_node_removed (E_TREE_MODEL (ets), NULL, path, -1);
1182 		free_path (path);
1183 	}
1184 }
1185 
1186 static void
1187 ets_proxy_node_deleted (ETreeModel *etm,
1188                         ETreePath child,
1189                         ETreeSorted *ets)
1190 {
1191 	e_tree_model_node_deleted (E_TREE_MODEL (ets), NULL);
1192 }
1193 
1194 static void
1195 ets_proxy_node_request_collapse (ETreeModel *etm,
1196                                  ETreePath node,
1197                                  ETreeSorted *ets)
1198 {
1199 	ETreeSortedPath *path = find_path (ets, node);
1200 	if (path) {
1201 		e_tree_model_node_request_collapse (E_TREE_MODEL (ets), path);
1202 	}
1203 }
1204 
1205 static void
1206 ets_sort_info_changed (ETableSortInfo *sort_info,
1207                        ETreeSorted *ets)
1208 {
1209 	schedule_resort (ets, ets->priv->root, TRUE, TRUE);
1210 }
1211 
1212 /* Initialization and creation */
1213 
1214 static void
1215 e_tree_sorted_class_init (ETreeSortedClass *class)
1216 {
1217 	GObjectClass *object_class;
1218 	ETreeModelClass *tree_model_class;
1219 
1220 	g_type_class_add_private (class, sizeof (ETreeSortedPrivate));
1221 
1222 	object_class = G_OBJECT_CLASS (class);
1223 	object_class->dispose = ets_dispose;
1224 	object_class->finalize = ets_finalize;
1225 
1226 	tree_model_class = E_TREE_MODEL_CLASS (class);
1227 	tree_model_class->get_root = ets_get_root;
1228 	tree_model_class->get_parent = ets_get_parent;
1229 	tree_model_class->get_first_child = ets_get_first_child;
1230 	tree_model_class->get_last_child = ets_get_last_child;
1231 	tree_model_class->get_prev = ets_get_prev;
1232 	tree_model_class->get_next = ets_get_next;
1233 
1234 	tree_model_class->is_root = ets_is_root;
1235 	tree_model_class->is_expandable = ets_is_expandable;
1236 	tree_model_class->get_children = ets_get_children;
1237 	tree_model_class->depth = ets_depth;
1238 
1239 	tree_model_class->icon_at = ets_icon_at;
1240 
1241 	tree_model_class->get_expanded_default = ets_get_expanded_default;
1242 	tree_model_class->column_count = ets_column_count;
1243 
1244 	tree_model_class->has_save_id = ets_has_save_id;
1245 	tree_model_class->get_save_id = ets_get_save_id;
1246 
1247 	tree_model_class->has_get_node_by_id = ets_has_get_node_by_id;
1248 	tree_model_class->get_node_by_id = ets_get_node_by_id;
1249 
1250 	tree_model_class->has_change_pending = ets_has_change_pending;
1251 
1252 	tree_model_class->value_at = ets_value_at;
1253 	tree_model_class->set_value_at = ets_set_value_at;
1254 	tree_model_class->is_editable = ets_is_editable;
1255 
1256 	tree_model_class->duplicate_value = ets_duplicate_value;
1257 	tree_model_class->free_value = ets_free_value;
1258 	tree_model_class->initialize_value = ets_initialize_value;
1259 	tree_model_class->value_is_empty = ets_value_is_empty;
1260 	tree_model_class->value_to_string = ets_value_to_string;
1261 
1262 	signals[NODE_RESORTED] = g_signal_new (
1263 		"node_resorted",
1264 		G_TYPE_FROM_CLASS (object_class),
1265 		G_SIGNAL_RUN_LAST,
1266 		G_STRUCT_OFFSET (ETreeSortedClass, node_resorted),
1267 		(GSignalAccumulator) NULL, NULL,
1268 		g_cclosure_marshal_VOID__POINTER,
1269 		G_TYPE_NONE, 1,
1270 		G_TYPE_POINTER);
1271 }
1272 
1273 static void
1274 e_tree_sorted_init (ETreeSorted *ets)
1275 {
1276 	ets->priv = E_TREE_SORTED_GET_PRIVATE (ets);
1277 }
1278 
1279 /**
1280  * e_tree_sorted_construct:
1281  * @etree:
1282  *
1283  *
1284  **/
1285 void
1286 e_tree_sorted_construct (ETreeSorted *ets,
1287                          ETreeModel *source,
1288                          ETableHeader *full_header,
1289                          ETableSortInfo *sort_info)
1290 {
1291 	ets->priv->source                              = source;
1292 	if (source)
1293 		g_object_ref (source);
1294 
1295 	ets->priv->full_header                         = full_header;
1296 	if (full_header)
1297 		g_object_ref (full_header);
1298 
1299 	e_tree_sorted_set_sort_info (ets, sort_info);
1300 
1301 	ets->priv->tree_model_pre_change_id = g_signal_connect (
1302 		source, "pre_change",
1303 		G_CALLBACK (ets_proxy_pre_change), ets);
1304 	ets->priv->tree_model_no_change_id = g_signal_connect (
1305 		source, "no_change",
1306 		G_CALLBACK (ets_proxy_no_change), ets);
1307 	ets->priv->tree_model_node_changed_id = g_signal_connect (
1308 		source, "node_changed",
1309 		G_CALLBACK (ets_proxy_node_changed), ets);
1310 	ets->priv->tree_model_node_data_changed_id = g_signal_connect (
1311 		source, "node_data_changed",
1312 		G_CALLBACK (ets_proxy_node_data_changed), ets);
1313 	ets->priv->tree_model_node_col_changed_id = g_signal_connect (
1314 		source, "node_col_changed",
1315 		G_CALLBACK (ets_proxy_node_col_changed), ets);
1316 	ets->priv->tree_model_node_inserted_id = g_signal_connect (
1317 		source, "node_inserted",
1318 		G_CALLBACK (ets_proxy_node_inserted), ets);
1319 	ets->priv->tree_model_node_removed_id = g_signal_connect (
1320 		source, "node_removed",
1321 		G_CALLBACK (ets_proxy_node_removed), ets);
1322 	ets->priv->tree_model_node_deleted_id = g_signal_connect (
1323 		source, "node_deleted",
1324 		G_CALLBACK (ets_proxy_node_deleted), ets);
1325 	ets->priv->tree_model_node_request_collapse_id = g_signal_connect (
1326 		source, "node_request_collapse",
1327 		G_CALLBACK (ets_proxy_node_request_collapse), ets);
1328 
1329 }
1330 
1331 /**
1332  * e_tree_sorted_new
1333  *
1334  * FIXME docs here.
1335  *
1336  * return values: a newly constructed ETreeSorted.
1337  */
1338 ETreeSorted *
1339 e_tree_sorted_new (ETreeModel *source,
1340                    ETableHeader *full_header,
1341                    ETableSortInfo *sort_info)
1342 {
1343 	ETreeSorted *ets = g_object_new (E_TYPE_TREE_SORTED, NULL);
1344 
1345 	e_tree_sorted_construct (ets, source, full_header, sort_info);
1346 
1347 	return ets;
1348 }
1349 
1350 ETreePath
1351 e_tree_sorted_view_to_model_path (ETreeSorted *ets,
1352                                   ETreePath view_path)
1353 {
1354 	ETreeSortedPath *path = view_path;
1355 	if (path) {
1356 		ets->priv->last_access = path;
1357 		d (g_print ("Setting last access %p. (e_tree_sorted_view_to_model_path)\n", ets->priv->last_access));
1358 		return path->corresponding;
1359 	} else
1360 		return NULL;
1361 }
1362 
1363 ETreePath
1364 e_tree_sorted_model_to_view_path (ETreeSorted *ets,
1365                                   ETreePath model_path)
1366 {
1367 	return find_or_create_path (ets, model_path);
1368 }
1369 
1370 gint
1371 e_tree_sorted_orig_position (ETreeSorted *ets,
1372                              ETreePath path)
1373 {
1374 	ETreeSortedPath *sorted_path = path;
1375 	return sorted_path->orig_position;
1376 }
1377 
1378 gint
1379 e_tree_sorted_node_num_children (ETreeSorted *ets,
1380                                  ETreePath path)
1381 {
1382 	ETreeSortedPath *sorted_path = path;
1383 
1384 	if (sorted_path->num_children == -1) {
1385 		generate_children (ets, sorted_path);
1386 	}
1387 
1388 	return sorted_path->num_children;
1389 }
1390 
1391 void
1392 e_tree_sorted_node_resorted (ETreeSorted *sorted,
1393                              ETreePath node)
1394 {
1395 	g_return_if_fail (sorted != NULL);
1396 	g_return_if_fail (E_IS_TREE_SORTED (sorted));
1397 
1398 	g_signal_emit (sorted, signals[NODE_RESORTED], 0, node);
1399 }
1400 
1401 void
1402 e_tree_sorted_set_sort_info (ETreeSorted *ets,
1403                              ETableSortInfo *sort_info)
1404 {
1405 
1406 	g_return_if_fail (ets != NULL);
1407 
1408 	if (ets->priv->sort_info) {
1409 		if (ets->priv->sort_info_changed_id != 0)
1410 			g_signal_handler_disconnect (
1411 				ets->priv->sort_info,
1412 				ets->priv->sort_info_changed_id);
1413 		ets->priv->sort_info_changed_id = 0;
1414 		g_object_unref (ets->priv->sort_info);
1415 	}
1416 
1417 	ets->priv->sort_info = sort_info;
1418 	if (sort_info) {
1419 		g_object_ref (sort_info);
1420 		ets->priv->sort_info_changed_id = g_signal_connect (
1421 			ets->priv->sort_info, "sort_info_changed",
1422 			G_CALLBACK (ets_sort_info_changed), ets);
1423 	}
1424 
1425 	if (ets->priv->root)
1426 		schedule_resort (ets, ets->priv->root, TRUE, TRUE);
1427 }
1428 
1429 ETableSortInfo *
1430 e_tree_sorted_get_sort_info (ETreeSorted *ets)
1431 {
1432 	return ets->priv->sort_info;
1433 }