gtksctree.c (56122B)
1 /* 2 * Claws Mail -- a GTK based, lightweight, and fast e-mail client 3 * Parts of this file: 4 * Copyright (C) 1999-2012 Hiroyuki Yamamoto and the Claws Mail team 5 * 6 * Parts of this file from gtk/gtkctree.c and gtk/gtkclist.c: 7 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball, Josh MacDonald, 8 * Copyright (C) 1997-1998 Jay Painter <jpaint@serv.net><jpaint@gimp.org> 9 * 10 * Parts of this file from gtkflist.c: 11 * Copyright (C) 1999 The Free Software Foundation 12 * Author: Federico Mena <federico@nuclecu.unam.mx> 13 * 14 * This program is free software; you can redistribute it and/or modify 15 * it under the terms of the GNU General Public License as published by 16 * the Free Software Foundation; either version 3 of the License, or 17 * (at your option) any later version. 18 * 19 * This program is distributed in the hope that it will be useful, 20 * but WITHOUT ANY WARRANTY; without even the implied warranty of 21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 22 * GNU General Public License for more details. 23 * 24 * You should have received a copy of the GNU General Public License 25 * along with this program. If not, see <http://www.gnu.org/licenses/>. 26 * 27 */ 28 29 #include <stdlib.h> 30 31 #include "gtksctree.h" 32 #include "claws-marshal.h" 33 #include "prefs_common.h" 34 #include "utils.h" 35 #include "gtkutils.h" 36 37 #define CLIST_UNFROZEN(clist) (((GtkCMCList*) (clist))->freeze_count == 0) 38 #define CLIST_REFRESH(clist) G_STMT_START { \ 39 if (CLIST_UNFROZEN (clist)) \ 40 GTK_CMCLIST_GET_CLASS (clist)->refresh ((GtkCMCList*) (clist)); \ 41 } G_STMT_END 42 #define CELL_SPACING 1 43 #define CLIST_OPTIMUM_SIZE 64 44 #define COLUMN_INSET 3 45 #define PM_SIZE 8 46 #define TAB_SIZE (PM_SIZE + 6) 47 #define ROW_TOP_YPIXEL(clist, row) (((clist)->row_height * (row)) + \ 48 (((row) + 1) * CELL_SPACING) + \ 49 (clist)->voffset) 50 #define ROW_FROM_YPIXEL(clist, y) (((y) - (clist)->voffset) / \ 51 ((clist)->row_height + CELL_SPACING)) 52 #define COLUMN_LEFT_XPIXEL(clist, col) ((clist)->column[(col)].area.x \ 53 + (clist)->hoffset) 54 #define COLUMN_LEFT(clist, column) ((clist)->column[(column)].area.x) 55 56 enum { 57 ROW_POPUP_MENU, 58 EMPTY_POPUP_MENU, 59 OPEN_ROW, 60 START_DRAG, 61 LAST_SIGNAL 62 }; 63 64 static void gtk_sctree_class_init (GtkSCTreeClass *class); 65 static void gtk_sctree_init (GtkSCTree *sctree); 66 67 static gint gtk_sctree_button_press (GtkWidget *widget, GdkEventButton *event); 68 static gint gtk_sctree_button_release (GtkWidget *widget, GdkEventButton *event); 69 static gint gtk_sctree_motion (GtkWidget *widget, GdkEventMotion *event); 70 static void gtk_sctree_drag_begin (GtkWidget *widget, GdkDragContext *context); 71 static void gtk_sctree_drag_end (GtkWidget *widget, GdkDragContext *context); 72 static void gtk_sctree_drag_data_get (GtkWidget *widget, GdkDragContext *context, 73 GtkSelectionData *data, guint info, guint time); 74 static void gtk_sctree_drag_leave (GtkWidget *widget, GdkDragContext *context, guint time); 75 static gboolean gtk_sctree_drag_motion (GtkWidget *widget, GdkDragContext *context, 76 gint x, gint y, guint time); 77 static gboolean gtk_sctree_drag_drop (GtkWidget *widget, GdkDragContext *context, 78 gint x, gint y, guint time); 79 static void gtk_sctree_drag_data_received (GtkWidget *widget, GdkDragContext *context, 80 gint x, gint y, GtkSelectionData *data, 81 guint info, guint time); 82 83 static void gtk_sctree_clear (GtkCMCList *clist); 84 static void gtk_sctree_real_unselect_all (GtkCMCList *clist); 85 86 static void stree_sort (GtkCMCTree *ctree, GtkCMCTreeNode *node, gpointer data); 87 void gtk_sctree_sort_node (GtkCMCTree *ctree, GtkCMCTreeNode *node); 88 void gtk_sctree_sort_recursive (GtkCMCTree *ctree, GtkCMCTreeNode *node); 89 90 static void gtk_sctree_link (GtkCMCTree *ctree, 91 GtkCMCTreeNode *node, 92 GtkCMCTreeNode *parent, 93 GtkCMCTreeNode *sibling, 94 gboolean update_focus_row); 95 96 static void gtk_sctree_unlink (GtkCMCTree *ctree, 97 GtkCMCTreeNode *node, 98 gboolean update_focus_row); 99 100 static void stree_update_level (GtkCMCTree *ctree, 101 GtkCMCTreeNode *node, 102 gpointer data); 103 104 static GtkCMCTreeNode * gtk_sctree_last_visible (GtkCMCTree *ctree, 105 GtkCMCTreeNode *node); 106 static void gtk_sctree_real_tree_expand (GtkCMCTree *ctree, 107 GtkCMCTreeNode *node); 108 static void gtk_sctree_real_tree_collapse (GtkCMCTree *ctree, 109 GtkCMCTreeNode *node); 110 static void 111 sreal_tree_move (GtkCMCTree *ctree, 112 GtkCMCTreeNode *node, 113 GtkCMCTreeNode *new_parent, 114 GtkCMCTreeNode *new_sibling); 115 116 static GtkCMCTreeClass *parent_class; 117 118 static guint sctree_signals[LAST_SIGNAL]; 119 120 /** 121 * gtk_sctree_get_type: 122 * @void: 123 * 124 * Creates the GtkSCTree class and its type information 125 * 126 * Return value: The type ID for GtkSCTreeClass 127 **/ 128 GType 129 gtk_sctree_get_type (void) 130 { 131 static GType sctree_type = 0; 132 133 if (!sctree_type) { 134 GTypeInfo sctree_info = { 135 sizeof (GtkSCTreeClass), 136 137 (GBaseInitFunc) NULL, 138 (GBaseFinalizeFunc) NULL, 139 140 (GClassInitFunc) gtk_sctree_class_init, 141 (GClassFinalizeFunc) NULL, 142 NULL, /* class_data */ 143 144 sizeof (GtkSCTree), 145 0, /* n_preallocs */ 146 (GInstanceInitFunc) gtk_sctree_init, 147 148 (const GTypeValueTable *) NULL /* value table */ 149 }; 150 151 sctree_type = g_type_register_static (GTK_TYPE_CMCTREE, "GtkSCTree", &sctree_info, (GTypeFlags)0); 152 } 153 154 return sctree_type; 155 } 156 157 static void 158 gtk_sctree_change_focus_row_expansion (GtkCMCTree *ctree, 159 GtkCMCTreeExpansionType action) 160 { 161 GtkCMCList *clist; 162 GtkCMCTreeNode *node; 163 164 cm_return_if_fail (GTK_IS_CMCTREE (ctree)); 165 166 clist = GTK_CMCLIST (ctree); 167 168 if (gtkut_pointer_is_grabbed (GTK_WIDGET (ctree)) && 169 gtk_widget_has_grab (GTK_WIDGET(ctree))) 170 return; 171 172 if (!(node = 173 GTK_CMCTREE_NODE (g_list_nth (clist->row_list, clist->focus_row))) || 174 GTK_CMCTREE_ROW (node)->is_leaf || !(GTK_CMCTREE_ROW (node)->children)) 175 return; 176 177 switch (action) 178 { 179 case GTK_CMCTREE_EXPANSION_EXPAND: 180 if (GTK_SCTREE(ctree)->always_expand_recursively) 181 gtk_cmctree_expand_recursive (ctree, node); 182 else 183 gtk_cmctree_expand (ctree, node); 184 185 break; 186 case GTK_CMCTREE_EXPANSION_EXPAND_RECURSIVE: 187 gtk_cmctree_expand_recursive (ctree, node); 188 break; 189 case GTK_CMCTREE_EXPANSION_COLLAPSE: 190 gtk_cmctree_collapse (ctree, node); 191 break; 192 case GTK_CMCTREE_EXPANSION_COLLAPSE_RECURSIVE: 193 gtk_cmctree_collapse_recursive (ctree, node); 194 break; 195 case GTK_CMCTREE_EXPANSION_TOGGLE: 196 if (GTK_SCTREE(ctree)->always_expand_recursively) 197 gtk_cmctree_toggle_expansion_recursive (ctree, node); 198 else 199 gtk_cmctree_toggle_expansion (ctree, node); 200 break; 201 case GTK_CMCTREE_EXPANSION_TOGGLE_RECURSIVE: 202 gtk_cmctree_toggle_expansion_recursive (ctree, node); 203 break; 204 } 205 } 206 207 static void gtk_sctree_finalize(GObject *object) 208 { 209 GtkSCTree *sctree = GTK_SCTREE(object); 210 g_free(sctree->use_markup); 211 sctree->use_markup = NULL; 212 G_OBJECT_CLASS (parent_class)->finalize (object); 213 } 214 215 /* Standard class initialization function */ 216 static void 217 gtk_sctree_class_init (GtkSCTreeClass *klass) 218 { 219 GObjectClass *gobject_class = G_OBJECT_CLASS (klass); 220 GtkWidgetClass *widget_class; 221 GtkCMCListClass *clist_class; 222 GtkCMCTreeClass *ctree_class; 223 224 widget_class = (GtkWidgetClass *) klass; 225 clist_class = (GtkCMCListClass *) klass; 226 ctree_class = (GtkCMCTreeClass *) klass; 227 228 parent_class = g_type_class_peek (gtk_cmctree_get_type ()); 229 230 sctree_signals[ROW_POPUP_MENU] = 231 g_signal_new ("row_popup_menu", 232 G_TYPE_FROM_CLASS (klass), 233 G_SIGNAL_RUN_FIRST, 234 G_STRUCT_OFFSET (GtkSCTreeClass, row_popup_menu), 235 NULL, NULL, 236 claws_marshal_VOID__POINTER, 237 G_TYPE_NONE, 1, 238 GDK_TYPE_EVENT); 239 sctree_signals[EMPTY_POPUP_MENU] = 240 g_signal_new ("empty_popup_menu", 241 G_TYPE_FROM_CLASS (klass), 242 G_SIGNAL_RUN_FIRST, 243 G_STRUCT_OFFSET (GtkSCTreeClass, empty_popup_menu), 244 NULL, NULL, 245 claws_marshal_VOID__POINTER, 246 G_TYPE_NONE, 1, 247 GDK_TYPE_EVENT); 248 sctree_signals[OPEN_ROW] = 249 g_signal_new ("open_row", 250 G_TYPE_FROM_CLASS (klass), 251 G_SIGNAL_RUN_FIRST, 252 G_STRUCT_OFFSET (GtkSCTreeClass, open_row), 253 NULL, NULL, 254 g_cclosure_marshal_VOID__VOID, 255 G_TYPE_NONE, 0); 256 sctree_signals[START_DRAG] = 257 g_signal_new ("start_drag", 258 G_TYPE_FROM_CLASS (klass), 259 G_SIGNAL_RUN_FIRST, 260 G_STRUCT_OFFSET (GtkSCTreeClass, start_drag), 261 NULL, NULL, 262 claws_marshal_VOID__INT_POINTER, 263 G_TYPE_NONE, 2, 264 G_TYPE_INT, 265 GDK_TYPE_EVENT); 266 267 /* gtk_object_class_add_signals (object_class, sctree_signals, LAST_SIGNAL); */ 268 269 clist_class->clear = gtk_sctree_clear; 270 clist_class->unselect_all = gtk_sctree_real_unselect_all; 271 ctree_class->tree_collapse = gtk_sctree_real_tree_collapse; 272 ctree_class->tree_expand = gtk_sctree_real_tree_expand; 273 ctree_class->tree_move = sreal_tree_move; 274 ctree_class->change_focus_row_expansion = gtk_sctree_change_focus_row_expansion; 275 276 widget_class->button_press_event = gtk_sctree_button_press; 277 widget_class->button_release_event = gtk_sctree_button_release; 278 widget_class->motion_notify_event = gtk_sctree_motion; 279 widget_class->drag_begin = gtk_sctree_drag_begin; 280 widget_class->drag_end = gtk_sctree_drag_end; 281 widget_class->drag_data_get = gtk_sctree_drag_data_get; 282 widget_class->drag_leave = gtk_sctree_drag_leave; 283 widget_class->drag_motion = gtk_sctree_drag_motion; 284 widget_class->drag_drop = gtk_sctree_drag_drop; 285 widget_class->drag_data_received = gtk_sctree_drag_data_received; 286 287 gobject_class->finalize = gtk_sctree_finalize; 288 } 289 290 /* Standard object initialization function */ 291 static void 292 gtk_sctree_init (GtkSCTree *sctree) 293 { 294 sctree->anchor_row = NULL; 295 296 /* GtkCMCTree does not specify pointer motion by default */ 297 gtk_widget_add_events (GTK_WIDGET (sctree), GDK_POINTER_MOTION_MASK); 298 gtk_widget_add_events (GTK_WIDGET (sctree), GDK_POINTER_MOTION_MASK); 299 } 300 301 /* Get information the specified row is selected. */ 302 303 static gboolean 304 row_is_selected(GtkSCTree *sctree, gint row) 305 { 306 GtkCMCListRow *clist_row; 307 clist_row = g_list_nth (GTK_CMCLIST(sctree)->row_list, row)->data; 308 return clist_row ? clist_row->state == GTK_STATE_SELECTED : FALSE; 309 } 310 311 /* Selects the rows between the anchor to the specified row, inclusive. */ 312 static void 313 select_range (GtkSCTree *sctree, gint row) 314 { 315 gint prev_row; 316 gint min, max; 317 gint i; 318 GList *node; 319 if (sctree->anchor_row == NULL) { 320 prev_row = row; 321 sctree->anchor_row = gtk_cmctree_node_nth(GTK_CMCTREE(sctree), row); 322 } else 323 prev_row = g_list_position(GTK_CMCLIST(sctree)->row_list, 324 (GList *)sctree->anchor_row); 325 326 if (row < prev_row) { 327 min = row; 328 max = prev_row; 329 GTK_CMCLIST(sctree)->focus_row = min; 330 } else { 331 min = prev_row; 332 max = row; 333 } 334 sctree->selecting_range++; 335 336 if (max < min) { 337 int t = min; 338 min = max; 339 max = t; 340 } 341 342 if (max - min > 10) 343 gtk_cmclist_freeze(GTK_CMCLIST(sctree)); 344 345 node = g_list_nth((GTK_CMCLIST(sctree))->row_list, min); 346 for (i = min; i < max; i++) { 347 if (node && GTK_CMCTREE_ROW (node)->row.selectable) { 348 g_signal_emit_by_name(G_OBJECT(sctree), "tree_select_row", 349 node, -1); 350 } 351 node = node->next; 352 } 353 if (max - min > 10) 354 gtk_cmclist_thaw(GTK_CMCLIST(sctree)); 355 356 357 sctree->selecting_range--; 358 gtk_cmclist_select_row (GTK_CMCLIST (sctree), max, -1); 359 } 360 361 /* Handles row selection according to the specified modifier state */ 362 /* in certain cases, we arrive here from a function knowing the GtkCMCTreeNode, and having 363 * already slowly found row using g_list_position. In which case, _node will be non-NULL 364 * to avoid this function having to slowly find it with g_list_nth. */ 365 static void 366 select_row (GtkSCTree *sctree, gint row, gint col, guint state, GtkCMCTreeNode *_node) 367 { 368 gboolean range, additive; 369 cm_return_if_fail (sctree != NULL); 370 cm_return_if_fail (GTK_IS_SCTREE (sctree)); 371 372 range = ((state & GDK_SHIFT_MASK) != 0) && 373 (GTK_CMCLIST(sctree)->selection_mode != GTK_SELECTION_SINGLE) && 374 (GTK_CMCLIST(sctree)->selection_mode != GTK_SELECTION_BROWSE); 375 additive = ((state & GDK_CONTROL_MASK) != 0) && 376 (GTK_CMCLIST(sctree)->selection_mode != GTK_SELECTION_SINGLE) && 377 (GTK_CMCLIST(sctree)->selection_mode != GTK_SELECTION_BROWSE); 378 379 if (!range && !additive && sctree->force_additive_sel) 380 additive = TRUE; 381 382 GTK_CMCLIST(sctree)->focus_row = row; 383 384 if (!additive) { 385 gtk_cmclist_unselect_all (GTK_CMCLIST (sctree)); 386 } 387 388 if (!range) { 389 GtkCMCTreeNode *node; 390 391 node = _node ? _node : gtk_cmctree_node_nth (GTK_CMCTREE(sctree), row); 392 393 /*No need to manage overlapped list*/ 394 if (additive) { 395 if (row_is_selected(sctree, row)) 396 gtk_cmclist_unselect_row (GTK_CMCLIST (sctree), row, col); 397 else 398 g_signal_emit_by_name 399 (G_OBJECT (sctree), 400 "tree_select_row", node, col); 401 } else { 402 g_signal_emit_by_name 403 (G_OBJECT (sctree), 404 "tree_select_row", node, col); 405 } 406 sctree->anchor_row = node; 407 } else 408 select_range (sctree, row); 409 } 410 411 static gboolean 412 sctree_is_hot_spot (GtkSCTree *sctree, 413 GtkCMCTreeNode *node, 414 gint row, 415 gint x, 416 gint y) 417 { 418 GtkCMCTreeRow *tree_row; 419 GtkCMCList *clist; 420 GtkCMCTree *ctree; 421 gint xl, xmax; 422 gint yu; 423 gint hotspot_size; 424 425 cm_return_val_if_fail (GTK_IS_SCTREE (sctree), FALSE); 426 cm_return_val_if_fail (node != NULL, FALSE); 427 428 clist = GTK_CMCLIST (sctree); 429 ctree = GTK_CMCTREE (sctree); 430 431 if (!clist->column[ctree->tree_column].visible || 432 ctree->expander_style == GTK_CMCTREE_EXPANDER_NONE) 433 return FALSE; 434 435 tree_row = GTK_CMCTREE_ROW (node); 436 if (!tree_row->children) 437 return FALSE; 438 439 hotspot_size = clist->row_height-2; 440 if (hotspot_size > clist->column[ctree->tree_column].area.width - 2) 441 hotspot_size = clist->column[ctree->tree_column].area.width - 2; 442 443 if (!GTK_CMCLIST_ROW_HEIGHT_SET(GTK_CMCLIST(clist))) 444 yu = (ROW_TOP_YPIXEL (clist, row) + (clist->row_height - hotspot_size) / 2 - 445 (clist->row_height - 1) % 2); 446 else 447 yu = (ROW_TOP_YPIXEL (clist, row) + (clist->row_height/2 - hotspot_size) / 2 - 448 (clist->row_height/2 - 1) % 2); 449 450 if (clist->column[ctree->tree_column].justification == GTK_JUSTIFY_RIGHT) 451 xl = clist->column[ctree->tree_column].area.x + 452 clist->column[ctree->tree_column].area.width - 1 + clist->hoffset - 453 (tree_row->level - 1) * ctree->tree_indent - hotspot_size; 454 else 455 xl = clist->column[ctree->tree_column].area.x + clist->hoffset + 456 (tree_row->level - 1) * ctree->tree_indent; 457 458 xmax = xl + hotspot_size; 459 return (x >= xl && x <= xmax && y >= yu && y <= yu + hotspot_size); 460 } 461 462 gboolean 463 gtk_sctree_is_hot_spot (GtkSCTree *ctree, 464 gint x, 465 gint y) 466 { 467 GtkCMCTreeNode *node; 468 gint column; 469 gint row; 470 471 cm_return_val_if_fail (GTK_IS_SCTREE (ctree), FALSE); 472 473 if (gtk_cmclist_get_selection_info (GTK_CMCLIST (ctree), x, y, &row, &column)) 474 if ((node = GTK_CMCTREE_NODE(g_list_nth (GTK_CMCLIST (ctree)->row_list, row)))) 475 return sctree_is_hot_spot (ctree, node, row, x, y); 476 477 return FALSE; 478 } 479 480 /* Our handler for button_press events. We override all of GtkCMCList's broken 481 * behavior. 482 */ 483 static gint 484 gtk_sctree_button_press (GtkWidget *widget, GdkEventButton *event) 485 { 486 GtkSCTree *sctree; 487 GtkCMCList *clist; 488 gboolean on_row; 489 gint row; 490 gint col; 491 gint retval; 492 493 cm_return_val_if_fail (widget != NULL, FALSE); 494 cm_return_val_if_fail (GTK_IS_SCTREE (widget), FALSE); 495 cm_return_val_if_fail (event != NULL, FALSE); 496 497 sctree = GTK_SCTREE (widget); 498 clist = GTK_CMCLIST (widget); 499 retval = FALSE; 500 501 if (event->window != clist->clist_window) 502 return (* GTK_WIDGET_CLASS (parent_class)->button_press_event) (widget, event); 503 504 on_row = gtk_cmclist_get_selection_info (clist, event->x, event->y, &row, &col); 505 506 if (on_row && !gtk_widget_has_focus(widget)) 507 gtk_widget_grab_focus (widget); 508 509 if (gtk_sctree_is_hot_spot (GTK_SCTREE(sctree), event->x, event->y)) { 510 GtkCMCTreeNode *node = gtk_cmctree_node_nth(GTK_CMCTREE(sctree), row); 511 if (GTK_CMCTREE_ROW (node)->expanded) 512 gtk_cmctree_collapse(GTK_CMCTREE(sctree), node); 513 else if (GTK_SCTREE(sctree)->always_expand_recursively) 514 gtk_cmctree_expand_recursive (GTK_CMCTREE(sctree), node); 515 else 516 gtk_cmctree_expand(GTK_CMCTREE(sctree), node); 517 return TRUE; 518 } 519 520 switch (event->type) { 521 case GDK_BUTTON_PRESS: 522 if (event->button == 1 || event->button == 2) { 523 if (event->button == 2) 524 event->state &= ~(GDK_SHIFT_MASK | GDK_CONTROL_MASK); 525 if (on_row) { 526 /* Save the mouse info for DnD */ 527 sctree->dnd_press_button = event->button; 528 sctree->dnd_press_x = event->x; 529 sctree->dnd_press_y = event->y; 530 531 /* Handle selection */ 532 if ((row_is_selected (sctree, row) 533 && !(event->state & (GDK_CONTROL_MASK | GDK_SHIFT_MASK))) 534 || ((event->state & GDK_CONTROL_MASK) 535 && !(event->state & GDK_SHIFT_MASK))) { 536 sctree->dnd_select_pending = TRUE; 537 sctree->dnd_select_pending_state = event->state; 538 sctree->dnd_select_pending_row = row; 539 } else { 540 select_row (sctree, row, col, event->state, NULL); 541 } 542 } else { 543 gtk_cmclist_unselect_all (clist); 544 } 545 546 retval = TRUE; 547 } else if (event->button == 3) { 548 /* Emit *_popup_menu signal*/ 549 if (on_row) { 550 if (!row_is_selected(sctree,row)) 551 select_row (sctree, row, col, 0, NULL); 552 g_signal_emit (G_OBJECT (sctree), 553 sctree_signals[ROW_POPUP_MENU], 554 0, event); 555 } else { 556 gtk_cmclist_unselect_all(clist); 557 g_signal_emit (G_OBJECT (sctree), 558 sctree_signals[EMPTY_POPUP_MENU], 559 0, event); 560 } 561 retval = TRUE; 562 } 563 564 break; 565 566 case GDK_2BUTTON_PRESS: 567 if (event->button != 1) 568 break; 569 570 sctree->dnd_select_pending = FALSE; 571 sctree->dnd_select_pending_state = 0; 572 573 if (on_row) 574 g_signal_emit (G_OBJECT (sctree), 575 sctree_signals[OPEN_ROW], 0); 576 577 retval = TRUE; 578 break; 579 580 default: 581 break; 582 } 583 584 return retval; 585 } 586 587 /* Our handler for button_release events. We override all of GtkCMCList's broken 588 * behavior. 589 */ 590 static gint 591 gtk_sctree_button_release (GtkWidget *widget, GdkEventButton *event) 592 { 593 GtkSCTree *sctree; 594 GtkCMCList *clist; 595 gint on_row; 596 gint row, col; 597 gint retval; 598 599 cm_return_val_if_fail (widget != NULL, FALSE); 600 cm_return_val_if_fail (GTK_IS_SCTREE (widget), FALSE); 601 cm_return_val_if_fail (event != NULL, FALSE); 602 603 sctree = GTK_SCTREE (widget); 604 clist = GTK_CMCLIST (widget); 605 retval = FALSE; 606 607 if (event->window != clist->clist_window) 608 return (* GTK_WIDGET_CLASS (parent_class)->button_release_event) (widget, event); 609 610 on_row = gtk_cmclist_get_selection_info (clist, event->x, event->y, &row, &col); 611 612 if (!(event->button == 1 || event->button == 2)) 613 return FALSE; 614 615 sctree->dnd_press_button = 0; 616 sctree->dnd_press_x = 0; 617 sctree->dnd_press_y = 0; 618 619 if (on_row) { 620 if (sctree->dnd_select_pending) { 621 select_row (sctree, row, col, sctree->dnd_select_pending_state, NULL); 622 sctree->dnd_select_pending = FALSE; 623 sctree->dnd_select_pending_state = 0; 624 } 625 626 retval = TRUE; 627 } 628 629 return retval; 630 } 631 632 /* Our handler for motion_notify events. We override all of GtkCMCList's broken 633 * behavior. 634 */ 635 static gint 636 gtk_sctree_motion (GtkWidget *widget, GdkEventMotion *event) 637 { 638 GtkSCTree *sctree; 639 GtkCMCList *clist; 640 641 cm_return_val_if_fail (widget != NULL, FALSE); 642 cm_return_val_if_fail (GTK_IS_SCTREE (widget), FALSE); 643 cm_return_val_if_fail (event != NULL, FALSE); 644 645 sctree = GTK_SCTREE (widget); 646 clist = GTK_CMCLIST (widget); 647 648 if (event->window != clist->clist_window) 649 return (* GTK_WIDGET_CLASS (parent_class)->motion_notify_event) (widget, event); 650 651 if (!((sctree->dnd_press_button == 1 && (event->state & GDK_BUTTON1_MASK)) 652 || (sctree->dnd_press_button == 2 && (event->state & GDK_BUTTON2_MASK)))) 653 return FALSE; 654 655 /* This is the same threshold value that is used in gtkdnd.c */ 656 int threshold = 3; 657 if (MAX (ABS (sctree->dnd_press_x - event->x), 658 ABS (sctree->dnd_press_y - event->y)) <= threshold) 659 return FALSE; 660 661 /* Handle any pending selections */ 662 663 if (sctree->dnd_select_pending) { 664 if (!row_is_selected(sctree,sctree->dnd_select_pending_row)) 665 select_row (sctree, 666 sctree->dnd_select_pending_row, 667 -1, 668 sctree->dnd_select_pending_state, 669 NULL); 670 671 sctree->dnd_select_pending = FALSE; 672 sctree->dnd_select_pending_state = 0; 673 } 674 675 g_signal_emit (G_OBJECT (sctree), 676 sctree_signals[START_DRAG], 677 0, 678 sctree->dnd_press_button, 679 event); 680 return TRUE; 681 } 682 683 /* We override the drag_begin signal to do nothing */ 684 static void 685 gtk_sctree_drag_begin (GtkWidget *widget, GdkDragContext *context) 686 { 687 /* nothing */ 688 } 689 690 /* We override the drag_end signal to do nothing */ 691 static void 692 gtk_sctree_drag_end (GtkWidget *widget, GdkDragContext *context) 693 { 694 /* nothing */ 695 } 696 697 /* We override the drag_data_get signal to do nothing */ 698 static void 699 gtk_sctree_drag_data_get (GtkWidget *widget, GdkDragContext *context, 700 GtkSelectionData *data, guint info, guint time) 701 { 702 /* nothing */ 703 } 704 705 /* We override the drag_leave signal to do nothing */ 706 static void 707 gtk_sctree_drag_leave (GtkWidget *widget, GdkDragContext *context, guint time) 708 { 709 /* nothing */ 710 } 711 712 /* We override the drag_motion signal to do nothing */ 713 static gboolean 714 gtk_sctree_drag_motion (GtkWidget *widget, GdkDragContext *context, 715 gint x, gint y, guint time) 716 { 717 return FALSE; 718 } 719 720 /* We override the drag_drop signal to do nothing */ 721 static gboolean 722 gtk_sctree_drag_drop (GtkWidget *widget, GdkDragContext *context, 723 gint x, gint y, guint time) 724 { 725 return FALSE; 726 } 727 728 /* We override the drag_data_received signal to do nothing */ 729 static void 730 gtk_sctree_drag_data_received (GtkWidget *widget, GdkDragContext *context, 731 gint x, gint y, GtkSelectionData *data, 732 guint info, guint time) 733 { 734 /* nothing */ 735 } 736 737 /* Our handler for the clear signal of the clist. We have to reset the anchor 738 * to null. 739 */ 740 static void 741 gtk_sctree_clear (GtkCMCList *clist) 742 { 743 GtkSCTree *sctree; 744 745 cm_return_if_fail (clist != NULL); 746 cm_return_if_fail (GTK_IS_SCTREE (clist)); 747 748 sctree = GTK_SCTREE (clist); 749 sctree->anchor_row = NULL; 750 751 if (((GtkCMCListClass *)parent_class)->clear) 752 (* ((GtkCMCListClass *)parent_class)->clear) (clist); 753 } 754 755 static void 756 gtk_sctree_real_unselect_all (GtkCMCList *clist) 757 { 758 GtkSCTree *sctree; 759 gboolean should_freeze = FALSE; 760 761 cm_return_if_fail (clist != NULL); 762 cm_return_if_fail (GTK_IS_SCTREE (clist)); 763 764 sctree = GTK_SCTREE (clist); 765 766 if (sc_g_list_bigger(GTK_CMCLIST(sctree)->selection, 10)) { 767 should_freeze = TRUE; 768 sctree->selecting_range++; 769 gtk_cmclist_freeze (GTK_CMCLIST (sctree)); 770 } 771 772 if (((GtkCMCListClass *)parent_class)->unselect_all) 773 (* ((GtkCMCListClass *)parent_class)->unselect_all) (clist); 774 775 if (should_freeze) { 776 gtk_cmclist_thaw (GTK_CMCLIST (sctree)); 777 sctree->selecting_range--; 778 } 779 } 780 781 static void 782 gtk_sctree_column_auto_resize (GtkCMCList *clist, 783 GtkCMCListRow *clist_row, 784 gint column, 785 gint old_width) 786 { 787 /* resize column if needed for auto_resize */ 788 GtkRequisition requisition; 789 790 if (!clist->column[column].auto_resize || 791 GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist)) 792 return; 793 794 if (clist_row) 795 GTK_CMCLIST_GET_CLASS (clist)->cell_size_request (clist, clist_row, 796 column, &requisition); 797 else 798 requisition.width = 0; 799 800 if (requisition.width > clist->column[column].width) 801 gtk_cmclist_set_column_width (clist, column, requisition.width); 802 else if (requisition.width < old_width && 803 old_width == clist->column[column].width) 804 { 805 GList *list; 806 GtkRequisition button_req; 807 gint new_width; 808 809 /* run a "gtk_cmclist_optimal_column_width" but break, if 810 * the column doesn't shrink */ 811 if (GTK_CMCLIST_SHOW_TITLES (clist) && clist->column[column].button) 812 { 813 gtk_widget_get_requisition (clist->column[column].button, &button_req); 814 new_width = (button_req.width - 815 (CELL_SPACING + (2 * COLUMN_INSET))); 816 } 817 else 818 new_width = 0; 819 820 for (list = clist->row_list; list; list = list->next) 821 { 822 GTK_CMCLIST_GET_CLASS (clist)->cell_size_request 823 (clist, GTK_CMCLIST_ROW (list), column, &requisition); 824 new_width = MAX (new_width, requisition.width); 825 if (new_width == clist->column[column].width) 826 break; 827 } 828 if (new_width < clist->column[column].width) 829 gtk_cmclist_set_column_width (clist, column, new_width); 830 } 831 } 832 833 static void 834 gtk_sctree_auto_resize_columns (GtkCMCList *clist) 835 { 836 gint i; 837 838 if (GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist)) 839 return; 840 841 for (i = 0; i < clist->columns; i++) 842 gtk_sctree_column_auto_resize (clist, NULL, i, clist->column[i].width); 843 } 844 845 static void 846 gtk_sctree_real_tree_collapse (GtkCMCTree *ctree, 847 GtkCMCTreeNode *node) 848 { 849 GtkCMCList *clist; 850 GtkCMCTreeNode *work; 851 GtkRequisition requisition; 852 gboolean visible; 853 gint level; 854 855 cm_return_if_fail (GTK_IS_CMCTREE (ctree)); 856 857 if (!node || !GTK_CMCTREE_ROW (node)->expanded || 858 GTK_CMCTREE_ROW (node)->is_leaf) 859 return; 860 861 clist = GTK_CMCLIST (ctree); 862 863 GTK_CMCLIST_GET_CLASS (clist)->resync_selection (clist, NULL); 864 865 GTK_CMCTREE_ROW (node)->expanded = FALSE; 866 level = GTK_CMCTREE_ROW (node)->level; 867 868 visible = gtk_cmctree_is_viewable (ctree, node); 869 /* get cell width if tree_column is auto resized */ 870 if (visible && clist->column[ctree->tree_column].auto_resize && 871 !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist)) 872 GTK_CMCLIST_GET_CLASS (clist)->cell_size_request 873 (clist, >K_CMCTREE_ROW (node)->row, ctree->tree_column, &requisition); 874 875 /* unref/unset opened pixbuf */ 876 if (GTK_CMCELL_PIXTEXT 877 (GTK_CMCTREE_ROW (node)->row.cell[ctree->tree_column])->pixbuf) 878 { 879 g_object_unref 880 (GTK_CMCELL_PIXTEXT 881 (GTK_CMCTREE_ROW (node)->row.cell[ctree->tree_column])->pixbuf); 882 883 GTK_CMCELL_PIXTEXT 884 (GTK_CMCTREE_ROW (node)->row.cell[ctree->tree_column])->pixbuf = NULL; 885 } 886 887 /* set/ref closed pixbuf */ 888 if (GTK_CMCTREE_ROW (node)->pixbuf_closed) 889 { 890 GTK_CMCELL_PIXTEXT 891 (GTK_CMCTREE_ROW (node)->row.cell[ctree->tree_column])->pixbuf = 892 g_object_ref (GTK_CMCTREE_ROW (node)->pixbuf_closed); 893 } 894 895 work = GTK_CMCTREE_ROW (node)->children; 896 if (work) 897 { 898 gint tmp = 0; 899 gint row; 900 GList *list; 901 902 while (work && GTK_CMCTREE_ROW (work)->level > level) 903 { 904 work = GTK_CMCTREE_NODE_NEXT (work); 905 tmp++; 906 } 907 908 if (work) 909 { 910 list = (GList *)node; 911 list->next = (GList *)work; 912 list = (GList *)GTK_CMCTREE_NODE_PREV (work); 913 list->next = NULL; 914 list = (GList *)work; 915 list->prev = (GList *)node; 916 } 917 else 918 { 919 list = (GList *)node; 920 list->next = NULL; 921 clist->row_list_end = (GList *)node; 922 } 923 924 if (visible) 925 { 926 /* resize auto_resize columns if needed */ 927 gtk_sctree_auto_resize_columns (clist); 928 929 if (!GTK_SCTREE(clist)->sorting) { 930 row = g_list_position (clist->row_list, (GList *)node); 931 if (row < clist->focus_row) 932 clist->focus_row -= tmp; 933 } 934 clist->rows -= tmp; 935 CLIST_REFRESH (clist); 936 } 937 } 938 else if (visible && clist->column[ctree->tree_column].auto_resize && 939 !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist)) 940 /* resize tree_column if needed */ 941 gtk_sctree_column_auto_resize (clist, >K_CMCTREE_ROW (node)->row, ctree->tree_column, 942 requisition.width); 943 944 } 945 946 947 GtkWidget *gtk_sctree_new_with_titles (gint columns, gint tree_column, 948 gchar *titles[]) 949 { 950 GtkWidget *widget; 951 952 cm_return_val_if_fail (columns > 0, NULL); 953 cm_return_val_if_fail (tree_column >= 0, NULL); 954 955 if (tree_column >= columns) { 956 g_warning("wrong tree column"); 957 tree_column = 0; 958 } 959 960 widget = gtk_widget_new (TYPE_GTK_SCTREE, 961 "n_columns", columns, 962 "tree_column", tree_column, 963 NULL); 964 if (titles) { 965 GtkCMCList *clist = GTK_CMCLIST (widget); 966 guint i; 967 968 for (i = 0; i < columns; i++) 969 gtk_cmclist_set_column_title (clist, i, titles[i]); 970 gtk_cmclist_column_titles_show (clist); 971 } 972 973 GTK_SCTREE(widget)->show_stripes = TRUE; 974 GTK_SCTREE(widget)->always_expand_recursively = TRUE; 975 GTK_SCTREE(widget)->force_additive_sel = FALSE; 976 977 GTK_SCTREE(widget)->use_markup = g_new0(gboolean, columns); 978 979 return widget; 980 } 981 982 void gtk_sctree_set_use_markup (GtkSCTree *sctree, 983 int column, 984 gboolean markup) 985 { 986 gint columns = 0; 987 GValue value = { 0 }; 988 989 cm_return_if_fail(GTK_IS_SCTREE(sctree)); 990 991 g_value_init (&value, G_TYPE_INT); 992 g_object_get_property (G_OBJECT (sctree), "n-columns", &value); 993 columns = g_value_get_int (&value); 994 g_value_unset (&value); 995 996 cm_return_if_fail(column < columns); 997 998 sctree->use_markup[column] = markup; 999 } 1000 1001 void gtk_sctree_select (GtkSCTree *sctree, GtkCMCTreeNode *node) 1002 { 1003 select_row(sctree, 1004 g_list_position(GTK_CMCLIST(sctree)->row_list, (GList *)node), 1005 -1, 0, node); 1006 } 1007 1008 void gtk_sctree_select_with_state (GtkSCTree *sctree, GtkCMCTreeNode *node, int state) 1009 { 1010 select_row(sctree, 1011 g_list_position(GTK_CMCLIST(sctree)->row_list, (GList *)node), 1012 -1, state, node); 1013 } 1014 1015 void gtk_sctree_unselect_all (GtkSCTree *sctree) 1016 { 1017 gtk_cmclist_unselect_all(GTK_CMCLIST(sctree)); 1018 sctree->anchor_row = NULL; 1019 } 1020 1021 void gtk_sctree_set_anchor_row (GtkSCTree *sctree, GtkCMCTreeNode *node) 1022 { 1023 sctree->anchor_row = node; 1024 } 1025 1026 void gtk_sctree_remove_node (GtkSCTree *sctree, GtkCMCTreeNode *node) 1027 { 1028 if (sctree->anchor_row == node) 1029 sctree->anchor_row = NULL; 1030 gtk_cmctree_remove_node(GTK_CMCTREE(sctree), node); 1031 } 1032 1033 void gtk_sctree_set_stripes(GtkSCTree *sctree, gboolean show_stripes) 1034 { 1035 sctree->show_stripes = show_stripes; 1036 } 1037 1038 void gtk_sctree_set_recursive_expand(GtkSCTree *sctree, gboolean rec_exp) 1039 { 1040 sctree->always_expand_recursively = rec_exp; 1041 } 1042 1043 /*********************************************************** 1044 * Tree sorting functions * 1045 ***********************************************************/ 1046 1047 static void sink(GtkCMCList *clist, GPtrArray *numbers, gint root, gint bottom) 1048 { 1049 gint j, k ; 1050 GtkCMCTreeNode *temp; 1051 1052 j = 2 * root; 1053 k = j + 1; 1054 1055 /* find the maximum element of numbers[root], 1056 numbers[2*root] and numbers[2*root+1] */ 1057 if (j <= bottom) { 1058 if (clist->compare( clist, GTK_CMCTREE_ROW (g_ptr_array_index(numbers, root)), 1059 GTK_CMCTREE_ROW(g_ptr_array_index( numbers, j))) >= 0) 1060 j = root; 1061 if (k <= bottom) 1062 if (clist->compare( clist, GTK_CMCTREE_ROW (g_ptr_array_index(numbers, k)), 1063 GTK_CMCTREE_ROW (g_ptr_array_index( numbers, j))) > 0) 1064 j = k; 1065 /* if numbers[root] wasn't the maximum element then 1066 sink again */ 1067 if (root != j) { 1068 temp = g_ptr_array_index( numbers,root); 1069 g_ptr_array_index( numbers, root) = g_ptr_array_index( numbers, j); 1070 g_ptr_array_index( numbers, j) = temp; 1071 sink( clist, numbers, j, bottom); 1072 } 1073 } 1074 } 1075 1076 static void heap_sort(GtkCMCList *clist, GPtrArray *numbers, gint array_size) 1077 { 1078 gint i; 1079 GtkCMCTreeNode *temp; 1080 1081 /* build the Heap */ 1082 for (i = (array_size / 2); i >= 1; i--) 1083 sink( clist, numbers, i, array_size); 1084 /* output the Heap */ 1085 for (i = array_size; i >= 2; i--) { 1086 temp = g_ptr_array_index( numbers, 1); 1087 g_ptr_array_index( numbers, 1) = g_ptr_array_index( numbers, i); 1088 g_ptr_array_index( numbers, i) = temp; 1089 sink( clist, numbers, 1, i-1); 1090 } 1091 } 1092 1093 static void 1094 stree_sort (GtkCMCTree *ctree, 1095 GtkCMCTreeNode *node, 1096 gpointer data) 1097 { 1098 GtkCMCTreeNode *list_start, *work, *next; 1099 GPtrArray *row_array, *viewable_array; 1100 GtkCMCList *clist; 1101 gint i; 1102 1103 clist = GTK_CMCLIST (ctree); 1104 1105 if (node) 1106 work = GTK_CMCTREE_ROW (node)->children; 1107 else 1108 work = GTK_CMCTREE_NODE (clist->row_list); 1109 1110 row_array = g_ptr_array_new(); 1111 viewable_array = g_ptr_array_new(); 1112 1113 if (work) { 1114 g_ptr_array_add( row_array, NULL); 1115 while (work) { 1116 /* add all rows to row_array */ 1117 g_ptr_array_add( row_array, work); 1118 if (GTK_CMCTREE_ROW (work)->parent && gtk_cmctree_is_viewable( ctree, work)) 1119 g_ptr_array_add( viewable_array, GTK_CMCTREE_ROW (work)->parent); 1120 next = GTK_CMCTREE_ROW (work)->sibling; 1121 gtk_sctree_unlink( ctree, work, FALSE); 1122 work = next; 1123 } 1124 1125 heap_sort( clist, row_array, (row_array->len)-1); 1126 1127 if (node) 1128 list_start = GTK_CMCTREE_ROW (node)->children; 1129 else 1130 list_start = GTK_CMCTREE_NODE (clist->row_list); 1131 1132 if (clist->sort_type == GTK_SORT_ASCENDING) { 1133 for (i=(row_array->len)-1; i>=1; i--) { 1134 work = g_ptr_array_index( row_array, i); 1135 gtk_sctree_link( ctree, work, node, list_start, FALSE); 1136 list_start = work; 1137 /* insert work at the beginning of the list */ 1138 } 1139 } else { 1140 for (i=1; i<row_array->len; i++) { 1141 work = g_ptr_array_index( row_array, i); 1142 gtk_sctree_link( ctree, work, node, list_start, FALSE); 1143 list_start = work; 1144 /* insert work at the beginning of the list */ 1145 } 1146 } 1147 1148 for (i=0; i<viewable_array->len; i++) { 1149 gtk_cmctree_expand( ctree, g_ptr_array_index( viewable_array, i)); 1150 } 1151 1152 } 1153 g_ptr_array_free( row_array, TRUE); 1154 g_ptr_array_free( viewable_array, TRUE); 1155 } 1156 1157 void 1158 gtk_sctree_sort_recursive (GtkCMCTree *ctree, 1159 GtkCMCTreeNode *node) 1160 { 1161 GtkCMCList *clist; 1162 GtkCMCTreeNode *focus_node = NULL; 1163 1164 cm_return_if_fail (ctree != NULL); 1165 cm_return_if_fail (GTK_IS_CMCTREE (ctree)); 1166 1167 clist = GTK_CMCLIST (ctree); 1168 1169 gtk_cmclist_freeze (clist); 1170 1171 if (clist->selection_mode == GTK_SELECTION_MULTIPLE) { 1172 GTK_CMCLIST_GET_CLASS (clist)->resync_selection (clist, NULL); 1173 1174 g_list_free (clist->undo_selection); 1175 g_list_free (clist->undo_unselection); 1176 clist->undo_selection = NULL; 1177 clist->undo_unselection = NULL; 1178 } 1179 1180 if (!node || (node && gtk_cmctree_is_viewable (ctree, node))) 1181 focus_node = GTK_CMCTREE_NODE (g_list_nth (clist->row_list, clist->focus_row)); 1182 1183 GTK_SCTREE(ctree)->sorting = TRUE; 1184 1185 gtk_cmctree_post_recursive (ctree, node, GTK_CMCTREE_FUNC (stree_sort), NULL); 1186 1187 if (!node) 1188 stree_sort (ctree, NULL, NULL); 1189 1190 GTK_SCTREE(ctree)->sorting = FALSE; 1191 1192 if (focus_node) { 1193 clist->focus_row = g_list_position (clist->row_list,(GList *)focus_node); 1194 clist->undo_anchor = clist->focus_row; 1195 } 1196 1197 gtk_cmclist_thaw (clist); 1198 } 1199 1200 void 1201 gtk_sctree_sort_node (GtkCMCTree *ctree, 1202 GtkCMCTreeNode *node) 1203 { 1204 GtkCMCList *clist; 1205 GtkCMCTreeNode *focus_node = NULL; 1206 1207 cm_return_if_fail (ctree != NULL); 1208 cm_return_if_fail (GTK_IS_CMCTREE (ctree)); 1209 1210 clist = GTK_CMCLIST (ctree); 1211 1212 gtk_cmclist_freeze (clist); 1213 1214 if (clist->selection_mode == GTK_SELECTION_MULTIPLE) { 1215 GTK_CMCLIST_GET_CLASS (clist)->resync_selection (clist, NULL); 1216 1217 g_list_free (clist->undo_selection); 1218 g_list_free (clist->undo_unselection); 1219 clist->undo_selection = NULL; 1220 clist->undo_unselection = NULL; 1221 } 1222 1223 if (!node || (node && gtk_cmctree_is_viewable (ctree, node))) 1224 focus_node = GTK_CMCTREE_NODE (g_list_nth (clist->row_list, clist->focus_row)); 1225 1226 GTK_SCTREE(ctree)->sorting = TRUE; 1227 1228 stree_sort (ctree, node, NULL); 1229 1230 GTK_SCTREE(ctree)->sorting = FALSE; 1231 1232 if (focus_node) { 1233 clist->focus_row = g_list_position (clist->row_list,(GList *)focus_node); 1234 clist->undo_anchor = clist->focus_row; 1235 } 1236 1237 gtk_cmclist_thaw (clist); 1238 } 1239 1240 /************************************************************************/ 1241 1242 static void 1243 gtk_sctree_unlink (GtkCMCTree *ctree, 1244 GtkCMCTreeNode *node, 1245 gboolean update_focus_row) 1246 { 1247 GtkCMCList *clist; 1248 gint rows; 1249 gint level; 1250 gint visible; 1251 GtkCMCTreeNode *work; 1252 GtkCMCTreeNode *parent; 1253 GList *list; 1254 1255 cm_return_if_fail (ctree != NULL); 1256 cm_return_if_fail (GTK_IS_CMCTREE (ctree)); 1257 cm_return_if_fail (node != NULL); 1258 1259 clist = GTK_CMCLIST (ctree); 1260 1261 if (update_focus_row && clist->selection_mode == GTK_SELECTION_MULTIPLE) { 1262 GTK_CMCLIST_GET_CLASS (clist)->resync_selection (clist, NULL); 1263 1264 g_list_free (clist->undo_selection); 1265 g_list_free (clist->undo_unselection); 1266 clist->undo_selection = NULL; 1267 clist->undo_unselection = NULL; 1268 } 1269 1270 visible = gtk_cmctree_is_viewable (ctree, node); 1271 1272 /* clist->row_list_end unlinked ? */ 1273 if (visible && (GTK_CMCTREE_NODE_NEXT (node) == NULL || 1274 (GTK_CMCTREE_ROW (node)->children && gtk_cmctree_is_ancestor (ctree, node, 1275 GTK_CMCTREE_NODE (clist->row_list_end))))) 1276 clist->row_list_end = (GList *) (GTK_CMCTREE_NODE_PREV (node)); 1277 1278 /* update list */ 1279 rows = 0; 1280 level = GTK_CMCTREE_ROW (node)->level; 1281 work = GTK_CMCTREE_NODE_NEXT (node); 1282 while (work && GTK_CMCTREE_ROW (work)->level > level) { 1283 work = GTK_CMCTREE_NODE_NEXT (work); 1284 rows++; 1285 } 1286 1287 if (visible) { 1288 clist->rows -= (rows + 1); 1289 1290 if (update_focus_row) { 1291 gint pos; 1292 pos = g_list_position (clist->row_list, (GList *)node); 1293 if (pos + rows < clist->focus_row) 1294 clist->focus_row -= (rows + 1); 1295 else if (pos <= clist->focus_row) { 1296 if (!GTK_CMCTREE_ROW (node)->sibling) 1297 clist->focus_row = MAX (pos - 1, 0); 1298 else 1299 clist->focus_row = pos; 1300 1301 clist->focus_row = MIN (clist->focus_row, clist->rows - 1); 1302 } 1303 clist->undo_anchor = clist->focus_row; 1304 } 1305 } 1306 1307 if (work) { 1308 list = (GList *)GTK_CMCTREE_NODE_PREV (work); 1309 list->next = NULL; 1310 list = (GList *)work; 1311 list->prev = (GList *)GTK_CMCTREE_NODE_PREV (node); 1312 } 1313 1314 if (GTK_CMCTREE_NODE_PREV (node) && 1315 GTK_CMCTREE_NODE_NEXT (GTK_CMCTREE_NODE_PREV (node)) == node) { 1316 list = (GList *)GTK_CMCTREE_NODE_PREV (node); 1317 list->next = (GList *)work; 1318 } 1319 1320 /* update tree */ 1321 parent = GTK_CMCTREE_ROW (node)->parent; 1322 if (parent) { 1323 if (GTK_CMCTREE_ROW (parent)->children == node) { 1324 GTK_CMCTREE_ROW (parent)->children = GTK_CMCTREE_ROW (node)->sibling; 1325 } 1326 else { 1327 GtkCMCTreeNode *sibling; 1328 1329 sibling = GTK_CMCTREE_ROW (parent)->children; 1330 while (GTK_CMCTREE_ROW (sibling)->sibling != node) 1331 sibling = GTK_CMCTREE_ROW (sibling)->sibling; 1332 GTK_CMCTREE_ROW (sibling)->sibling = GTK_CMCTREE_ROW (node)->sibling; 1333 } 1334 } 1335 else { 1336 if (clist->row_list == (GList *)node) 1337 clist->row_list = (GList *) (GTK_CMCTREE_ROW (node)->sibling); 1338 else { 1339 GtkCMCTreeNode *sibling; 1340 1341 sibling = GTK_CMCTREE_NODE (clist->row_list); 1342 while (GTK_CMCTREE_ROW (sibling)->sibling != node) 1343 sibling = GTK_CMCTREE_ROW (sibling)->sibling; 1344 GTK_CMCTREE_ROW (sibling)->sibling = GTK_CMCTREE_ROW (node)->sibling; 1345 } 1346 } 1347 } 1348 1349 static void 1350 gtk_sctree_link (GtkCMCTree *ctree, 1351 GtkCMCTreeNode *node, 1352 GtkCMCTreeNode *parent, 1353 GtkCMCTreeNode *sibling, 1354 gboolean update_focus_row) 1355 { 1356 GtkCMCList *clist; 1357 GList *list_end; 1358 GList *list; 1359 GList *work; 1360 gboolean visible = FALSE; 1361 gint rows = 0; 1362 1363 if (sibling) 1364 cm_return_if_fail (GTK_CMCTREE_ROW (sibling)->parent == parent); 1365 cm_return_if_fail (node != NULL); 1366 cm_return_if_fail (node != sibling); 1367 cm_return_if_fail (node != parent); 1368 1369 clist = GTK_CMCLIST (ctree); 1370 1371 if (update_focus_row && clist->selection_mode == GTK_SELECTION_MULTIPLE) { 1372 GTK_CMCLIST_GET_CLASS (clist)->resync_selection (clist, NULL); 1373 1374 g_list_free (clist->undo_selection); 1375 g_list_free (clist->undo_unselection); 1376 clist->undo_selection = NULL; 1377 clist->undo_unselection = NULL; 1378 } 1379 1380 for (rows = 1, list_end = (GList *)node; list_end->next; 1381 list_end = list_end->next) 1382 rows++; 1383 1384 GTK_CMCTREE_ROW (node)->parent = parent; 1385 GTK_CMCTREE_ROW (node)->sibling = sibling; 1386 1387 if (!parent || (parent && (gtk_cmctree_is_viewable (ctree, parent) && 1388 GTK_CMCTREE_ROW (parent)->expanded))) { 1389 visible = TRUE; 1390 clist->rows += rows; 1391 } 1392 1393 if (parent) 1394 work = (GList *)(GTK_CMCTREE_ROW (parent)->children); 1395 else 1396 work = clist->row_list; 1397 1398 if (sibling) { 1399 if (work != (GList *)sibling) { 1400 while (GTK_CMCTREE_ROW (work)->sibling != sibling) 1401 work = (GList *)(GTK_CMCTREE_ROW (work)->sibling); 1402 GTK_CMCTREE_ROW (work)->sibling = node; 1403 } 1404 1405 if (sibling == GTK_CMCTREE_NODE (clist->row_list)) 1406 clist->row_list = (GList *) node; 1407 if (GTK_CMCTREE_NODE_PREV (sibling) && 1408 GTK_CMCTREE_NODE_NEXT (GTK_CMCTREE_NODE_PREV (sibling)) == sibling) { 1409 list = (GList *)GTK_CMCTREE_NODE_PREV (sibling); 1410 list->next = (GList *)node; 1411 } 1412 1413 list = (GList *)node; 1414 list->prev = (GList *)GTK_CMCTREE_NODE_PREV (sibling); 1415 list_end->next = (GList *)sibling; 1416 list = (GList *)sibling; 1417 list->prev = list_end; 1418 if (parent && GTK_CMCTREE_ROW (parent)->children == sibling) 1419 GTK_CMCTREE_ROW (parent)->children = node; 1420 } 1421 else { 1422 if (work) { 1423 /* find sibling */ 1424 while (GTK_CMCTREE_ROW (work)->sibling) 1425 work = (GList *)(GTK_CMCTREE_ROW (work)->sibling); 1426 GTK_CMCTREE_ROW (work)->sibling = node; 1427 1428 /* find last visible child of sibling */ 1429 work = (GList *) gtk_sctree_last_visible (ctree, 1430 GTK_CMCTREE_NODE (work)); 1431 1432 list_end->next = work->next; 1433 if (work->next) 1434 work->next->prev = list_end; 1435 work->next = (GList *)node; 1436 list = (GList *)node; 1437 list->prev = work; 1438 } 1439 else { 1440 if (parent) { 1441 GTK_CMCTREE_ROW (parent)->children = node; 1442 list = (GList *)node; 1443 list->prev = (GList *)parent; 1444 if (GTK_CMCTREE_ROW (parent)->expanded) { 1445 list_end->next = (GList *)GTK_CMCTREE_NODE_NEXT (parent); 1446 if (GTK_CMCTREE_NODE_NEXT(parent)) { 1447 list = (GList *)GTK_CMCTREE_NODE_NEXT (parent); 1448 list->prev = list_end; 1449 } 1450 list = (GList *)parent; 1451 list->next = (GList *)node; 1452 } 1453 else 1454 list_end->next = NULL; 1455 } 1456 else { 1457 clist->row_list = (GList *)node; 1458 list = (GList *)node; 1459 list->prev = NULL; 1460 list_end->next = NULL; 1461 } 1462 } 1463 } 1464 1465 gtk_cmctree_pre_recursive (ctree, node, stree_update_level, NULL); 1466 1467 if (clist->row_list_end == NULL || 1468 clist->row_list_end->next == (GList *)node) 1469 clist->row_list_end = list_end; 1470 1471 if (visible && update_focus_row) { 1472 gint pos; 1473 pos = g_list_position (clist->row_list, (GList *)node); 1474 1475 if (pos <= clist->focus_row) { 1476 clist->focus_row += rows; 1477 clist->undo_anchor = clist->focus_row; 1478 } 1479 } 1480 } 1481 1482 static void 1483 stree_update_level (GtkCMCTree *ctree, 1484 GtkCMCTreeNode *node, 1485 gpointer data) 1486 { 1487 if (!node) 1488 return; 1489 1490 if (GTK_CMCTREE_ROW (node)->parent) 1491 GTK_CMCTREE_ROW (node)->level = 1492 GTK_CMCTREE_ROW (GTK_CMCTREE_ROW (node)->parent)->level + 1; 1493 else 1494 GTK_CMCTREE_ROW (node)->level = 1; 1495 } 1496 1497 static GtkCMCTreeNode * 1498 gtk_sctree_last_visible (GtkCMCTree *ctree, 1499 GtkCMCTreeNode *node) 1500 { 1501 GtkCMCTreeNode *work; 1502 1503 if (!node) 1504 return NULL; 1505 1506 work = GTK_CMCTREE_ROW (node)->children; 1507 1508 if (!work || !GTK_CMCTREE_ROW (node)->expanded) 1509 return node; 1510 1511 while (GTK_CMCTREE_ROW (work)->sibling) 1512 work = GTK_CMCTREE_ROW (work)->sibling; 1513 1514 return gtk_sctree_last_visible (ctree, work); 1515 } 1516 1517 static void 1518 sset_node_info (GtkCMCTree *ctree, 1519 GtkCMCTreeNode *node, 1520 const gchar *text, 1521 guint8 spacing, 1522 GdkPixbuf *pixbuf_closed, 1523 GdkPixbuf *pixbuf_opened, 1524 gboolean is_leaf, 1525 gboolean expanded) 1526 { 1527 if (GTK_CMCTREE_ROW (node)->pixbuf_opened) 1528 { 1529 g_object_unref (GTK_CMCTREE_ROW (node)->pixbuf_opened); 1530 } 1531 if (GTK_CMCTREE_ROW (node)->pixbuf_closed) 1532 { 1533 g_object_unref (GTK_CMCTREE_ROW (node)->pixbuf_closed); 1534 } 1535 1536 GTK_CMCTREE_ROW (node)->pixbuf_opened = NULL; 1537 GTK_CMCTREE_ROW (node)->pixbuf_closed = NULL; 1538 1539 if (pixbuf_closed) 1540 { 1541 GTK_CMCTREE_ROW (node)->pixbuf_closed = g_object_ref (pixbuf_closed); 1542 } 1543 if (pixbuf_opened) 1544 { 1545 GTK_CMCTREE_ROW (node)->pixbuf_opened = g_object_ref (pixbuf_opened); 1546 } 1547 1548 GTK_CMCTREE_ROW (node)->is_leaf = is_leaf; 1549 GTK_CMCTREE_ROW (node)->expanded = (is_leaf) ? FALSE : expanded; 1550 1551 if (GTK_CMCTREE_ROW (node)->expanded) 1552 gtk_cmctree_node_set_pixtext (ctree, node, ctree->tree_column, 1553 text, spacing, pixbuf_opened); 1554 else 1555 gtk_cmctree_node_set_pixtext (ctree, node, ctree->tree_column, 1556 text, spacing, pixbuf_closed); 1557 } 1558 1559 static GtkCMCTreeRow * 1560 srow_new (GtkCMCTree *ctree) 1561 { 1562 GtkCMCList *clist; 1563 GtkCMCTreeRow *ctree_row; 1564 int i; 1565 1566 clist = GTK_CMCLIST (ctree); 1567 ctree_row = g_slice_new (GtkCMCTreeRow); 1568 ctree_row->row.cell = g_slice_alloc (sizeof (GtkCMCell) * clist->columns); 1569 for (i = 0; i < clist->columns; i++) 1570 { 1571 ctree_row->row.cell[i].type = GTK_CMCELL_EMPTY; 1572 ctree_row->row.cell[i].vertical = 0; 1573 ctree_row->row.cell[i].horizontal = 0; 1574 ctree_row->row.cell[i].style = NULL; 1575 } 1576 1577 GTK_CMCELL_PIXTEXT (ctree_row->row.cell[ctree->tree_column])->text = NULL; 1578 1579 ctree_row->row.fg_set = FALSE; 1580 ctree_row->row.bg_set = FALSE; 1581 ctree_row->row.style = NULL; 1582 ctree_row->row.selectable = TRUE; 1583 ctree_row->row.state = GTK_STATE_NORMAL; 1584 ctree_row->row.data = NULL; 1585 ctree_row->row.destroy = NULL; 1586 1587 ctree_row->level = 0; 1588 ctree_row->expanded = FALSE; 1589 ctree_row->parent = NULL; 1590 ctree_row->sibling = NULL; 1591 ctree_row->children = NULL; 1592 ctree_row->pixbuf_closed = NULL; 1593 ctree_row->pixbuf_opened = NULL; 1594 1595 return ctree_row; 1596 } 1597 1598 static void 1599 srow_delete (GtkCMCTree *ctree, 1600 GtkCMCTreeRow *ctree_row) 1601 { 1602 GtkCMCList *clist; 1603 gint i; 1604 1605 clist = GTK_CMCLIST (ctree); 1606 1607 for (i = 0; i < clist->columns; i++) 1608 { 1609 GTK_CMCLIST_GET_CLASS (clist)->set_cell_contents 1610 (clist, &(ctree_row->row), i, GTK_CMCELL_EMPTY, NULL, 0, NULL); 1611 if (ctree_row->row.cell[i].style) 1612 { 1613 if (gtk_widget_get_realized (GTK_WIDGET(ctree))) 1614 gtk_style_detach (ctree_row->row.cell[i].style); 1615 g_object_unref (ctree_row->row.cell[i].style); 1616 } 1617 } 1618 1619 if (ctree_row->row.style) 1620 { 1621 if (gtk_widget_get_realized (GTK_WIDGET(ctree))) 1622 gtk_style_detach (ctree_row->row.style); 1623 g_object_unref (ctree_row->row.style); 1624 } 1625 1626 if (ctree_row->pixbuf_closed) 1627 { 1628 g_object_unref (ctree_row->pixbuf_closed); 1629 } 1630 1631 if (ctree_row->pixbuf_opened) 1632 { 1633 g_object_unref (ctree_row->pixbuf_opened); 1634 } 1635 1636 if (ctree_row->row.destroy) 1637 { 1638 GDestroyNotify dnotify = ctree_row->row.destroy; 1639 gpointer ddata = ctree_row->row.data; 1640 1641 ctree_row->row.destroy = NULL; 1642 ctree_row->row.data = NULL; 1643 1644 dnotify (ddata); 1645 } 1646 1647 g_slice_free1 (sizeof (GtkCMCell) * clist->columns, ctree_row->row.cell); 1648 g_slice_free (GtkCMCTreeRow, ctree_row); 1649 } 1650 1651 static void 1652 stree_delete_row (GtkCMCTree *ctree, 1653 GtkCMCTreeNode *node, 1654 gpointer data) 1655 { 1656 srow_delete (ctree, GTK_CMCTREE_ROW (node)); 1657 g_list_free_1 ((GList *)node); 1658 } 1659 1660 static void 1661 gtk_sctree_real_tree_expand (GtkCMCTree *ctree, 1662 GtkCMCTreeNode *node) 1663 { 1664 GtkCMCList *clist; 1665 GtkCMCTreeNode *work; 1666 GtkRequisition requisition; 1667 gboolean visible; 1668 1669 cm_return_if_fail (GTK_IS_CMCTREE (ctree)); 1670 1671 if (!node || GTK_CMCTREE_ROW (node)->expanded || GTK_CMCTREE_ROW (node)->is_leaf) 1672 return; 1673 1674 clist = GTK_CMCLIST (ctree); 1675 1676 GTK_CMCLIST_GET_CLASS (clist)->resync_selection (clist, NULL); 1677 1678 GTK_CMCTREE_ROW (node)->expanded = TRUE; 1679 1680 visible = gtk_cmctree_is_viewable (ctree, node); 1681 /* get cell width if tree_column is auto resized */ 1682 if (visible && clist->column[ctree->tree_column].auto_resize && 1683 !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist)) 1684 GTK_CMCLIST_GET_CLASS (clist)->cell_size_request 1685 (clist, >K_CMCTREE_ROW (node)->row, ctree->tree_column, &requisition); 1686 1687 /* unref/unset closed pixbuf */ 1688 if (GTK_CMCELL_PIXTEXT 1689 (GTK_CMCTREE_ROW (node)->row.cell[ctree->tree_column])->pixbuf) 1690 { 1691 g_object_unref 1692 (GTK_CMCELL_PIXTEXT 1693 (GTK_CMCTREE_ROW (node)->row.cell[ctree->tree_column])->pixbuf); 1694 1695 GTK_CMCELL_PIXTEXT 1696 (GTK_CMCTREE_ROW (node)->row.cell[ctree->tree_column])->pixbuf = NULL; 1697 } 1698 1699 /* set/ref opened pixbuf */ 1700 if (GTK_CMCTREE_ROW (node)->pixbuf_opened) 1701 { 1702 GTK_CMCELL_PIXTEXT 1703 (GTK_CMCTREE_ROW (node)->row.cell[ctree->tree_column])->pixbuf = 1704 g_object_ref (GTK_CMCTREE_ROW (node)->pixbuf_opened); 1705 } 1706 1707 1708 work = GTK_CMCTREE_ROW (node)->children; 1709 if (work) 1710 { 1711 GList *list = (GList *)work; 1712 gint *cell_width = NULL; 1713 gint tmp = 0; 1714 gint row; 1715 gint i; 1716 1717 if (visible && !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist)) 1718 { 1719 cell_width = g_new0 (gint, clist->columns); 1720 if (clist->column[ctree->tree_column].auto_resize) 1721 cell_width[ctree->tree_column] = requisition.width; 1722 1723 while (work) 1724 { 1725 /* search maximum cell widths of auto_resize columns */ 1726 for (i = 0; i < clist->columns; i++) 1727 if (clist->column[i].auto_resize) 1728 { 1729 GTK_CMCLIST_GET_CLASS (clist)->cell_size_request 1730 (clist, >K_CMCTREE_ROW (work)->row, i, &requisition); 1731 cell_width[i] = MAX (requisition.width, cell_width[i]); 1732 } 1733 1734 list = (GList *)work; 1735 work = GTK_CMCTREE_NODE_NEXT (work); 1736 tmp++; 1737 } 1738 } 1739 else 1740 while (work) 1741 { 1742 list = (GList *)work; 1743 work = GTK_CMCTREE_NODE_NEXT (work); 1744 tmp++; 1745 } 1746 1747 list->next = (GList *)GTK_CMCTREE_NODE_NEXT (node); 1748 1749 if (GTK_CMCTREE_NODE_NEXT (node)) 1750 { 1751 GList *tmp_list; 1752 1753 if (clist->row_list_end == list) 1754 clist->row_list_end = g_list_last(list); 1755 1756 tmp_list = (GList *)GTK_CMCTREE_NODE_NEXT (node); 1757 tmp_list->prev = list; 1758 } 1759 else 1760 clist->row_list_end = list; 1761 1762 list = (GList *)node; 1763 list->next = (GList *)(GTK_CMCTREE_ROW (node)->children); 1764 1765 if (visible && !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist)) 1766 { 1767 /* resize auto_resize columns if needed */ 1768 for (i = 0; i < clist->columns; i++) 1769 if (clist->column[i].auto_resize && 1770 cell_width[i] > clist->column[i].width) 1771 gtk_cmclist_set_column_width (clist, i, cell_width[i]); 1772 g_free (cell_width); 1773 1774 if (!GTK_SCTREE(ctree)->sorting) { 1775 /* update focus_row position */ 1776 row = g_list_position (clist->row_list, (GList *)node); 1777 if (row < clist->focus_row) 1778 clist->focus_row += tmp; 1779 } 1780 clist->rows += tmp; 1781 CLIST_REFRESH (clist); 1782 } 1783 } 1784 else if (visible && clist->column[ctree->tree_column].auto_resize) 1785 /* resize tree_column if needed */ 1786 gtk_sctree_column_auto_resize (clist, >K_CMCTREE_ROW (node)->row, ctree->tree_column, 1787 requisition.width); 1788 1789 } 1790 1791 GtkCMCTreeNode * 1792 gtk_sctree_insert_node (GtkCMCTree *ctree, 1793 GtkCMCTreeNode *parent, 1794 GtkCMCTreeNode *sibling, 1795 gchar *text[], 1796 guint8 spacing, 1797 GdkPixbuf *pixbuf_closed, 1798 GdkPixbuf *pixbuf_opened, 1799 gboolean is_leaf, 1800 gboolean expanded) 1801 { 1802 GtkCMCList *clist; 1803 GtkCMCTreeRow *new_row; 1804 GtkCMCTreeNode *node; 1805 GList *list; 1806 gint i; 1807 1808 cm_return_val_if_fail (GTK_IS_CMCTREE (ctree), NULL); 1809 if (sibling) 1810 cm_return_val_if_fail (GTK_CMCTREE_ROW (sibling)->parent == parent, NULL); 1811 1812 if (parent && GTK_CMCTREE_ROW (parent)->is_leaf) 1813 return NULL; 1814 1815 clist = GTK_CMCLIST (ctree); 1816 1817 /* create the row */ 1818 new_row = srow_new (ctree); 1819 list = g_list_alloc (); 1820 list->data = new_row; 1821 node = GTK_CMCTREE_NODE (list); 1822 1823 if (text) 1824 for (i = 0; i < clist->columns; i++) 1825 if (text[i] && i != ctree->tree_column) 1826 GTK_CMCLIST_GET_CLASS (clist)->set_cell_contents 1827 (clist, &(new_row->row), i, GTK_CMCELL_TEXT, text[i], 0, NULL); 1828 1829 sset_node_info (ctree, node, text ? 1830 text[ctree->tree_column] : NULL, spacing, pixbuf_closed, 1831 pixbuf_opened, is_leaf, expanded); 1832 1833 /* sorted insertion */ 1834 if (GTK_CMCLIST_AUTO_SORT (clist)) 1835 { 1836 if (parent) 1837 sibling = GTK_CMCTREE_ROW (parent)->children; 1838 else 1839 sibling = GTK_CMCTREE_NODE (clist->row_list); 1840 1841 while (sibling && clist->compare 1842 (clist, GTK_CMCTREE_ROW (node), GTK_CMCTREE_ROW (sibling)) > 0) 1843 sibling = GTK_CMCTREE_ROW (sibling)->sibling; 1844 } 1845 1846 gtk_sctree_link (ctree, node, parent, sibling, FALSE); 1847 1848 if (text && !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist) && 1849 gtk_cmctree_is_viewable (ctree, node)) 1850 { 1851 for (i = 0; i < clist->columns; i++) 1852 if (clist->column[i].auto_resize) 1853 gtk_sctree_column_auto_resize (clist, &(new_row->row), i, 0); 1854 } 1855 1856 if (clist->rows == 1) 1857 { 1858 clist->focus_row = 0; 1859 if (clist->selection_mode == GTK_SELECTION_BROWSE) 1860 gtk_sctree_select (GTK_SCTREE(ctree), node); 1861 } 1862 1863 1864 CLIST_REFRESH (clist); 1865 1866 return node; 1867 } 1868 1869 GtkCMCTreeNode * 1870 gtk_sctree_insert_gnode (GtkCMCTree *ctree, 1871 GtkCMCTreeNode *parent, 1872 GtkCMCTreeNode *sibling, 1873 GNode *gnode, 1874 GtkCMCTreeGNodeFunc func, 1875 gpointer data) 1876 { 1877 GtkCMCList *clist; 1878 GtkCMCTreeNode *cnode = NULL; 1879 GtkCMCTreeNode *child = NULL; 1880 GtkCMCTreeNode *new_child; 1881 GList *list; 1882 GNode *work; 1883 guint depth = 1; 1884 1885 cm_return_val_if_fail (GTK_IS_CMCTREE (ctree), NULL); 1886 cm_return_val_if_fail (gnode != NULL, NULL); 1887 cm_return_val_if_fail (func != NULL, NULL); 1888 if (sibling) 1889 cm_return_val_if_fail (GTK_CMCTREE_ROW (sibling)->parent == parent, NULL); 1890 1891 clist = GTK_CMCLIST (ctree); 1892 1893 if (parent) 1894 depth = GTK_CMCTREE_ROW (parent)->level + 1; 1895 1896 list = g_list_alloc (); 1897 list->data = srow_new (ctree); 1898 cnode = GTK_CMCTREE_NODE (list); 1899 1900 gtk_cmclist_freeze (clist); 1901 1902 sset_node_info (ctree, cnode, "", 0, NULL, NULL, TRUE, FALSE); 1903 1904 if (!func (ctree, depth, gnode, cnode, data)) 1905 { 1906 stree_delete_row (ctree, cnode, NULL); 1907 gtk_cmclist_thaw (clist); 1908 return NULL; 1909 } 1910 1911 if (GTK_CMCLIST_AUTO_SORT (clist)) 1912 { 1913 if (parent) 1914 sibling = GTK_CMCTREE_ROW (parent)->children; 1915 else 1916 sibling = GTK_CMCTREE_NODE (clist->row_list); 1917 1918 while (sibling && clist->compare 1919 (clist, GTK_CMCTREE_ROW (cnode), GTK_CMCTREE_ROW (sibling)) > 0) 1920 sibling = GTK_CMCTREE_ROW (sibling)->sibling; 1921 } 1922 1923 gtk_sctree_link (ctree, cnode, parent, sibling, FALSE); 1924 1925 for (work = g_node_last_child (gnode); work; work = work->prev) 1926 { 1927 new_child = gtk_sctree_insert_gnode (ctree, cnode, child, 1928 work, func, data); 1929 if (new_child) 1930 child = new_child; 1931 } 1932 1933 gtk_cmclist_thaw (clist); 1934 1935 return cnode; 1936 } 1937 1938 static void 1939 sreal_tree_move (GtkCMCTree *ctree, 1940 GtkCMCTreeNode *node, 1941 GtkCMCTreeNode *new_parent, 1942 GtkCMCTreeNode *new_sibling) 1943 { 1944 GtkCMCList *clist; 1945 GtkCMCTreeNode *work; 1946 gboolean visible = FALSE; 1947 1948 cm_return_if_fail (ctree != NULL); 1949 cm_return_if_fail (node != NULL); 1950 cm_return_if_fail (!new_sibling || 1951 GTK_CMCTREE_ROW (new_sibling)->parent == new_parent); 1952 1953 if (new_parent && GTK_CMCTREE_ROW (new_parent)->is_leaf) 1954 return; 1955 1956 /* new_parent != child of child */ 1957 for (work = new_parent; work; work = GTK_CMCTREE_ROW (work)->parent) 1958 if (work == node) 1959 return; 1960 1961 clist = GTK_CMCLIST (ctree); 1962 1963 visible = gtk_cmctree_is_viewable (ctree, node); 1964 1965 if (clist->selection_mode == GTK_SELECTION_MULTIPLE) 1966 { 1967 GTK_CMCLIST_GET_CLASS (clist)->resync_selection (clist, NULL); 1968 1969 g_list_free (clist->undo_selection); 1970 g_list_free (clist->undo_unselection); 1971 clist->undo_selection = NULL; 1972 clist->undo_unselection = NULL; 1973 } 1974 1975 if (GTK_CMCLIST_AUTO_SORT (clist)) 1976 { 1977 if (new_parent == GTK_CMCTREE_ROW (node)->parent) 1978 return; 1979 1980 if (new_parent) 1981 new_sibling = GTK_CMCTREE_ROW (new_parent)->children; 1982 else 1983 new_sibling = GTK_CMCTREE_NODE (clist->row_list); 1984 1985 while (new_sibling && clist->compare 1986 (clist, GTK_CMCTREE_ROW (node), GTK_CMCTREE_ROW (new_sibling)) > 0) 1987 new_sibling = GTK_CMCTREE_ROW (new_sibling)->sibling; 1988 } 1989 1990 if (new_parent == GTK_CMCTREE_ROW (node)->parent && 1991 new_sibling == GTK_CMCTREE_ROW (node)->sibling) 1992 return; 1993 1994 gtk_cmclist_freeze (clist); 1995 1996 work = NULL; 1997 1998 if (!GTK_SCTREE(ctree)->sorting && gtk_cmctree_is_viewable (ctree, node)) 1999 work = GTK_CMCTREE_NODE (g_list_nth (clist->row_list, clist->focus_row)); 2000 2001 gtk_sctree_unlink (ctree, node, FALSE); 2002 gtk_sctree_link (ctree, node, new_parent, new_sibling, FALSE); 2003 2004 if (!GTK_SCTREE(ctree)->sorting && work) 2005 { 2006 while (work && !gtk_cmctree_is_viewable (ctree, work)) 2007 work = GTK_CMCTREE_ROW (work)->parent; 2008 clist->focus_row = g_list_position (clist->row_list, (GList *)work); 2009 clist->undo_anchor = clist->focus_row; 2010 } 2011 2012 if (clist->column[ctree->tree_column].auto_resize && 2013 !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist) && 2014 (visible || gtk_cmctree_is_viewable (ctree, node))) 2015 gtk_cmclist_set_column_width 2016 (clist, ctree->tree_column, 2017 gtk_cmclist_optimal_column_width (clist, ctree->tree_column)); 2018 2019 gtk_cmclist_thaw (clist); 2020 } 2021 2022 void gtk_sctree_set_column_tooltip (GtkSCTree *sctree, 2023 int column, 2024 const gchar *tip) 2025 { 2026 CLAWS_SET_TIP(GTK_CMCLIST(sctree)->column[column].button, 2027 tip); 2028 } 2029