wtree.c revision 33c89af1
1/* 2 * $Xorg: wtree.c,v 1.4 2001/02/09 02:05:30 xorgcvs Exp $ 3 * 4Copyright 1989, 1998 The Open Group 5 6Permission to use, copy, modify, distribute, and sell this software and its 7documentation for any purpose is hereby granted without fee, provided that 8the above copyright notice appear in all copies and that both that 9copyright notice and this permission notice appear in supporting 10documentation. 11 12The above copyright notice and this permission notice shall be included in 13all copies or substantial portions of the Software. 14 15THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 19AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 22Except as contained in this notice, the name of The Open Group shall not be 23used in advertising or otherwise to promote the sale, use or other dealings 24in this Software without prior written authorization from The Open Group. 25 */ 26/* $XFree86: xc/programs/editres/wtree.c,v 1.4 2001/01/17 23:44:53 dawes Exp $ */ 27 28#include <stdio.h> 29#include <X11/Intrinsic.h> 30#include <X11/Xutil.h> 31#include <X11/StringDefs.h> 32 33#include <X11/Xaw/Cardinals.h> 34#include <X11/Xaw/Toggle.h> 35#include <X11/Xaw/Viewport.h> 36#include <X11/Xaw/Tree.h> 37 38#include "editresP.h" 39 40static void AddNodeToActiveList ( WNode * node ); 41static void RemoveNodeFromActiveList ( WNode * node ); 42static Boolean IsActiveNode ( WNode * node ); 43static void AddNode ( WNode ** top_node, WidgetTreeInfo * info, 44 TreeInfo * tree_info ); 45static void FillNode ( WidgetTreeInfo * info, WNode * node, 46 TreeInfo * tree_info ); 47static void AddChild ( WNode * parent, WNode * child ); 48static WNode ** CopyActiveNodes ( TreeInfo * tree_info ); 49 50/* Function Name: BuildVisualTree 51 * Description: Creates the Tree and shows it. 52 * Arguments: tree_parent - parent of the tree widget. 53 * event - the event that caused this action. 54 * Returns: none. 55 */ 56 57/* ARGSUSED */ 58void 59BuildVisualTree(tree_parent, event) 60Widget tree_parent; 61Event * event; 62{ 63 WNode * top; 64 char msg[BUFSIZ]; 65 66 if (global_tree_info != NULL) { 67 XtDestroyWidget(global_tree_info->tree_widget); 68 XtFree((char *)global_tree_info->active_nodes); 69 XtFree((char *)global_tree_info); 70 } 71 72 global_tree_info = CreateTree(event); 73 top = global_tree_info->top_node; 74 75 global_tree_info->tree_widget = XtCreateWidget("tree", treeWidgetClass, 76 tree_parent, NULL, ZERO); 77 78 if (top == NULL) { 79 SetMessage(global_screen_data.info_label, 80 res_labels[27]); 81 return; 82 } 83 84 AddTreeNode(global_tree_info->tree_widget, top); 85 86 if (XtIsRealized(tree_parent)) /* hack around problems in Xt. */ 87 XtRealizeWidget(global_tree_info->tree_widget); 88 89 XtManageChild(global_tree_info->tree_widget); 90 91 sprintf(msg, res_labels[11], top->name, top->class); 92 SetMessage(global_screen_data.info_label, msg); 93} 94 95/* Function Name: AddTreeNode 96 * Description: Adds all nodes below this to the Tree widget. 97 * Arguments: parent - parent of the tree widget. 98 * top - the top node of the tree. 99 * Returns: the tree widget. 100 * 101 * NOTE: This is a recursive function. 102 */ 103 104void 105AddTreeNode(tree, top) 106Widget tree; 107WNode * top; 108{ 109 int i; 110 Arg args[1]; 111 Cardinal num_args = 0; 112 char msg[BUFSIZ]; 113 114 if (top->parent != NULL) { 115 if (top->parent->widget == NULL) { 116 sprintf( msg, res_labels[28], 117 top->name, top->parent->name, "not been created yet"); 118 SetMessage(global_screen_data.info_label, msg); 119 } 120 XtSetArg(args[num_args], XtNtreeParent, top->parent->widget); 121 num_args++; 122 } 123 124 top->widget = XtCreateManagedWidget(top->name, toggleWidgetClass, tree, 125 args, num_args); 126 127 if (XSaveContext(XtDisplay(top->widget), (Window) top->widget, 128 NODE_INFO, (XPointer) top) != 0) { 129 sprintf( msg, res_labels[29], top->name); 130 SetMessage(global_screen_data.info_label, msg); 131 } 132 133 XtAddCallback(top->widget, XtNcallback, TreeToggle, (XtPointer) top); 134 135 for (i = 0; i < top->num_children; i++) 136 AddTreeNode(tree, top->children[i]); 137} 138 139/* Function Name: TreeToggle 140 * Description: Called whenever a tree node is toggled. 141 * Arguments: w - the tree widget. 142 * node_ptr - pointer to this node's information. 143 * state_ptr - state of the toggle. 144 * Returns: none. 145 */ 146 147/* ARGSUSED */ 148void 149TreeToggle(w, node_ptr, state_ptr) 150Widget w; 151XtPointer node_ptr, state_ptr; 152{ 153 Boolean state = (Boolean)(long) state_ptr; 154 WNode * node = (WNode *) node_ptr; 155 156 if (state) 157 AddNodeToActiveList(node); 158 else 159 RemoveNodeFromActiveList(node); 160} 161 162/* Function Name: AddNodeToActiveList 163 * Description: Adds this node to the list of active toggles. 164 * Arguments: node - node to add. 165 * Returns: none. 166 */ 167 168static void 169AddNodeToActiveList(node) 170WNode * node; 171{ 172 TreeInfo * info = node->tree_info; 173 174 if (IsActiveNode(node)) /* node already active. */ 175 return; 176 177 if (info->num_nodes >= info->alloc_nodes) { 178 info->alloc_nodes += NUM_INC; 179 info->active_nodes =(WNode **)XtRealloc((XtPointer) info->active_nodes, 180 sizeof(WNode *) * 181 info->alloc_nodes); 182 } 183 184 info->active_nodes[info->num_nodes++] = node; 185} 186 187/* Function Name: RemoveNodeFromActiveList 188 * Description: Removes a node from the active list. 189 * Arguments: node - node to remove. 190 * Returns: none. 191 */ 192 193static void 194RemoveNodeFromActiveList(node) 195WNode * node; 196{ 197 TreeInfo * info = node->tree_info; 198 Boolean found_node = FALSE; 199 int i; 200 201 if (!IsActiveNode(node)) /* This node is not active. */ 202 return; 203 204 for (i = 0; i < info->num_nodes; i++) { 205 if (found_node) 206 info->active_nodes[i - 1] = info->active_nodes[i]; 207 else if (info->active_nodes[i] == node) 208 found_node = TRUE; 209 } 210 211 info->num_nodes--; 212} 213 214/* Function Name: IsActiveNode 215 * Description: returns TRUE is this node is on the active list. 216 * Arguments: node - node to check. 217 * Returns: see above. 218 */ 219 220static Boolean 221IsActiveNode(node) 222WNode * node; 223{ 224 TreeInfo * info = node->tree_info; 225 int i; 226 227 for (i = 0; i < info->num_nodes; i++) 228 if (info->active_nodes[i] == node) 229 return(TRUE); 230 231 return(FALSE); 232} 233 234/* Function Name: CreateTree 235 * Description: Creates a widget tree give a list of names and classes. 236 * Arguments: event - the information from the client. 237 * Returns: The tree_info about this new tree. 238 */ 239 240TreeInfo * 241CreateTree(event) 242Event * event; 243{ 244 SendWidgetTreeEvent * send_event = (SendWidgetTreeEvent *) event; 245 int i; 246 247 TreeInfo * tree_info; 248 249 tree_info = (TreeInfo *) XtMalloc( (Cardinal) sizeof(TreeInfo)); 250 251 tree_info->tree_widget = NULL; 252 tree_info->top_node = NULL; 253 tree_info->active_nodes = NULL; 254 tree_info->num_nodes = tree_info->alloc_nodes = 0; 255 tree_info->flash_widgets = NULL; 256 tree_info->num_flash_widgets = tree_info->alloc_flash_widgets = 0; 257 258 for ( i = 0; i < (int)send_event->num_entries; i++) 259 AddNode(&(tree_info->top_node), (send_event->info + i), tree_info); 260 261 return(tree_info); 262} 263 264/* Function Name: PrintNodes 265 * Description: Prints all nodes. 266 * Arguments: top - the top node. 267 * Returns: none. 268 */ 269 270void 271PrintNodes(top) 272WNode * top; 273{ 274 int i; 275 276 if (top->parent == NULL) 277 printf("Top of Tree, Name: %10s, ID: %10ld, Class: %10s\n", 278 top->name, top->id, top->class); 279 else 280 printf("Parent %10s, Name: %10s, ID: %10ld, Class: %10s\n", 281 top->parent->name, top->name, top->id, top->class); 282 283 for (i = 0; i < top->num_children; i++) 284 PrintNodes(top->children[i]); 285} 286 287/* Function Name: _TreeRelabel 288 * Description: Modifies the selected elements of the tree 289 * Arguments: tree_info - the tree we are working on. 290 * type - type of selection to perform 291 * Returns: none. 292 */ 293 294void 295_TreeRelabel(tree_info, type) 296TreeInfo * tree_info; 297LabelTypes type; 298{ 299 WNode * top; 300 301 if (tree_info == NULL) { 302 SetMessage(global_screen_data.info_label, 303 res_labels[17]); 304 return; 305 } 306 307 top = tree_info->top_node; 308 309 PrepareToLayoutTree(tree_info->tree_widget); 310 _TreeRelabelNode(top, type, TRUE); 311 LayoutTree(tree_info->tree_widget); 312} 313 314/* Function Name: _TreeSelect 315 * Description: Activates relatives of the active nodes, as specified 316 * by type, or Selects all nodes as specified by type. 317 * Arguments: tree_info - information about the tree to work on. 318 * type - type of activate to invode. 319 * Returns: none. 320 */ 321 322void 323_TreeSelect(TreeInfo *tree_info, SelectTypes type) 324{ 325 WNode ** active_nodes; 326 Cardinal num_active_nodes; 327 int i; 328 329 if (tree_info == NULL) { 330 SetMessage(global_screen_data.info_label, 331 res_labels[17]); 332 return; 333 } 334 335 switch(type) { 336 case SelectNone: 337 case SelectAll: 338 case SelectInvert: 339 _TreeSelectNode(tree_info->top_node, type, TRUE); 340 return; 341 default: 342 break; /* otherwise continue. */ 343 } 344 345 if (tree_info->num_nodes == 0) { 346 SetMessage(global_screen_data.info_label, 347 res_labels[18]); 348 return; 349 } 350 351 active_nodes = CopyActiveNodes(tree_info); 352 num_active_nodes = tree_info->num_nodes; 353 354 for (i = 0; i < num_active_nodes; i++) 355 _TreeActivateNode(active_nodes[i], type); 356 357 XtFree((XtPointer) active_nodes); 358} 359 360/* Function Name: _TreeSelectNode 361 * Description: Modifies the state of a node and all its decendants. 362 * Arguments: node - node to operate on. 363 * type - type of selection to perform. 364 * recurse - whether to continue on down the tree. 365 * Returns: none. 366 */ 367 368void 369_TreeSelectNode(WNode *node, SelectTypes type, Boolean recurse) 370{ 371 int i; 372 Arg args[1]; 373 Boolean state; 374 375 switch(type) { 376 case SelectAll: 377 state = TRUE; 378 break; 379 case SelectNone: 380 state = FALSE; 381 break; 382 case SelectInvert: 383 XtSetArg(args[0], XtNstate, &state); 384 XtGetValues(node->widget, args, ONE); 385 386 state = !state; 387 break; 388 default: 389 SetMessage(global_screen_data.info_label, 390 res_labels[16]); 391 return; 392 } 393 394 XtSetArg(args[0], XtNstate, state); 395 XtSetValues(node->widget, args, ONE); 396 TreeToggle(node->widget, (XtPointer) node, (XtPointer)(long) state); 397 398 if (!recurse) 399 return; 400 401 for (i = 0; i < node->num_children; i++) 402 _TreeSelectNode(node->children[i], type, recurse); 403} 404 405/* Function Name: _TreeRelabelNodes 406 * Description: Modifies the node and all its decendants label. 407 * Arguments: node - node to operate on. 408 * type - type of selection to perform. 409 * recurse - whether to continue on down the tree. 410 * Returns: none. 411 */ 412 413void 414_TreeRelabelNode(WNode *node, LabelTypes type, Boolean recurse) 415{ 416 int i; 417 Arg args[1]; 418 char buf[30]; 419 char *label; 420 421 switch(type) { 422 case ClassLabel: 423 XtSetArg(args[0], XtNlabel, node->class); 424 break; 425 case NameLabel: 426 XtSetArg(args[0], XtNlabel, node->name); 427 break; 428 case IDLabel: 429 sprintf(buf, "id: 0x%lx", node->id); 430 XtSetArg(args[0], XtNlabel, buf); 431 break; 432 case WindowLabel: 433 if (node->window == EDITRES_IS_UNREALIZED) 434 strcpy(buf, "unrealized widget"); 435 else if (node->window == EDITRES_IS_OBJECT) 436 strcpy(buf, "non windowed object"); 437 else 438 sprintf(buf, "win: 0x%lx", node->window); 439 440 XtSetArg(args[0], XtNlabel, buf); 441 break; 442 case ToggleLabel: 443 XtSetArg(args[0], XtNlabel, &label); 444 XtGetValues(node->widget, args, ONE); 445 if (label && !strcmp(label, node->name)) 446 XtSetArg(args[0], XtNlabel, node->class); 447 else 448 XtSetArg(args[0], XtNlabel, node->name); 449 break; 450 default: 451 SetMessage(global_screen_data.info_label, 452 res_labels[32]); 453 return; 454 } 455 456 XtSetValues(node->widget, args, ONE); 457 458 if (!recurse) 459 return; 460 461 for (i = 0; i < node->num_children; i++) 462 _TreeRelabelNode(node->children[i], type, recurse); 463} 464 465/* Function Name: _TreeActivateNode 466 * Description: Activates relatives of the node specfied, as specified 467 * by type. 468 * Arguments: node - node to opererate on. 469 * type - type of activate to invode. 470 * Returns: none. 471 */ 472 473void 474_TreeActivateNode(node, type) 475WNode * node; 476SelectTypes type; 477{ 478 Arg args[1]; 479 int i; 480 481 XtSetArg(args[0], XtNstate, TRUE); 482 483 if ((type == SelectParent) || (type == SelectAncestors)) { 484 node = node->parent; 485 if (node == NULL) 486 return; 487 488 XtSetValues(node->widget, args, ONE); 489 AddNodeToActiveList(node); 490 491 if (type == SelectAncestors) 492 _TreeActivateNode(node, type); 493 } 494 else if ((type == SelectChildren) || (type == SelectDescendants)) 495 for (i = 0; i < node->num_children; i++) { 496 AddNodeToActiveList(node->children[i]); 497 XtSetValues(node->children[i]->widget, args, ONE); 498 if (type == SelectDescendants) 499 _TreeActivateNode(node->children[i], type); 500 } 501 else 502 SetMessage(global_screen_data.info_label, 503 res_labels[33]); 504} 505 506/************************************************************ 507 * 508 * Non - Exported Functions. 509 * 510 ************************************************************/ 511 512 513/* Function Name: AddNode 514 * Description: adds a node to the widget tree. 515 * Arguments: top_node - a pointer to the current top node. 516 * info - the info from the client about the widget tree. 517 * tree_info - global information on this tree. 518 * Returns: none. 519 */ 520 521static void 522AddNode(top_node, info, tree_info) 523WNode ** top_node; 524WidgetTreeInfo * info; 525TreeInfo * tree_info; 526{ 527 WNode *node, *parent; 528 Boolean early_break = FALSE; 529 Cardinal number = info->widgets.num_widgets; 530 531 if ( (node = FindNode(*top_node, info->widgets.ids, number)) == NULL) { 532 node = (WNode *) XtCalloc(sizeof(WNode), ONE); 533 534 node->id = info->widgets.ids[number - 1]; 535 FillNode(info, node, tree_info); 536 537 for ( number--; number > 0; number--, node = parent) { 538 parent = FindNode(*top_node, info->widgets.ids, number); 539 if (parent == NULL) { 540 parent = (WNode *) XtCalloc(sizeof(WNode), ONE); 541 parent->id = info->widgets.ids[number - 1]; 542 } 543 else 544 early_break = TRUE; 545 546 AddChild(parent, node); 547 548 if (early_break) 549 break; 550 } 551 552 if (!early_break) { 553 if (node->parent == NULL) 554 *top_node = node; 555 else 556 *top_node = node->parent; 557 } 558 } 559 else 560 FillNode(info, node, tree_info); 561} 562 563/* Function Name: FillNode 564 * Description: Fills in everything but the node id in the node. 565 * Arguments: info - the info from the client. 566 * node - node to fill. 567 * tree_info - global information on this tree. 568 * Returns: none 569 */ 570 571static void 572FillNode(info, node, tree_info) 573WidgetTreeInfo * info; 574WNode * node; 575TreeInfo * tree_info; 576{ 577 node->class = info->class; 578 info->class = NULL; /* keeps it from deallocating. */ 579 node->name = info->name; 580 info->name = NULL; 581 node->window = info->window; 582 node->tree_info = tree_info; 583} 584 585/* Function Name: AddChild 586 * Description: Adds a child to an existing node. 587 * Arguments: parent - parent node. 588 * child - child node to add. 589 * Returns: none. 590 */ 591 592static void 593AddChild(parent, child) 594WNode * parent, * child; 595{ 596 if (parent->num_children >= parent->alloc_children) { 597 parent->alloc_children += NUM_INC; 598 parent->children = (WNode **) XtRealloc((char *)parent->children, 599 sizeof(WNode *) * parent->alloc_children); 600 } 601 602 parent->children[parent->num_children] = child; 603 (parent->num_children)++; 604 605 child->parent = parent; 606} 607 608/************************************************************ 609 * 610 * Functions that operate of the current tree. 611 * 612 ************************************************************/ 613 614/* Function Name: CopyActiveNodes 615 * Description: returns a copy of the currently selected nodes. 616 * Arguments: tree_info - the tree info struct. 617 * Returns: a copy of the selected nodes. 618 */ 619 620static WNode ** 621CopyActiveNodes(tree_info) 622TreeInfo * tree_info; 623{ 624 WNode ** list; 625 int i; 626 627 if ( (tree_info == NULL) || (tree_info->num_nodes == 0)) 628 return(NULL); 629 630 list = (WNode **) XtMalloc(sizeof(WNode *) * tree_info->num_nodes); 631 632 for (i = 0; i < tree_info->num_nodes; i++) 633 list[i] = tree_info->active_nodes[i]; 634 635 return(list); 636} 637 638/* Function Name: SetAndCenterTreeNode 639 * Description: Deactivates all nodes, activates the one specified, and 640 * and moves the tree to be centered on the current node. 641 * Arguments: node - node to use. 642 * Returns: none. 643 */ 644 645void 646SetAndCenterTreeNode(node) 647WNode * node; 648{ 649 Arg args[5]; 650 Cardinal num_args; 651 Position node_x, node_y; 652 Dimension port_width, port_height; 653 Dimension node_width, node_height, node_bw; 654 655 _TreeSelect(node->tree_info, SelectNone); /* Unselect all nodes */ 656 _TreeSelectNode(node, SelectAll, FALSE); /* Select this node */ 657 658 /* 659 * Get porthole dimensions. 660 */ 661 662 num_args = 0; 663 XtSetArg(args[num_args], XtNwidth, &port_width); num_args++; 664 XtSetArg(args[num_args], XtNheight, &port_height); num_args++; 665 XtGetValues(XtParent(node->tree_info->tree_widget), args, num_args); 666 667 /* 668 * Get node widget dimensions. 669 */ 670 671 num_args = 0; 672 XtSetArg(args[num_args], XtNwidth, &node_width); num_args++; 673 XtSetArg(args[num_args], XtNheight, &node_height); num_args++; 674 XtSetArg(args[num_args], XtNborderWidth, &node_bw); num_args++; 675 XtSetArg(args[num_args], XtNx, &node_x); num_args++; 676 XtSetArg(args[num_args], XtNy, &node_y); num_args++; 677 XtGetValues(node->widget, args, num_args); 678 679 /* 680 * reset the node x and y location to be the new x and y location of 681 * the tree relative to the porthole. 682 */ 683 684 node_x = port_width/2 - (node_x + node_width/2 + node_bw); 685 node_y = port_height/2 - (node_y + node_height/2 + node_bw); 686 687 num_args = 0; 688 XtSetArg(args[num_args], XtNx, node_x); num_args++; 689 XtSetArg(args[num_args], XtNy, node_y); num_args++; 690 XtSetValues(node->tree_info->tree_widget, args, num_args); 691} 692 693/* Function Name: PerformTreeToFileDump 694 * Description: Dumps the contents of the current widget tree to 695 * the file specified. 696 * Arguments: node - node to dump. 697 * num_tabs - number of spaces to indent. 698 * fp - pointer to the file to write to. 699 * Returns: none. 700 */ 701 702void 703PerformTreeToFileDump(node, num_tabs, fp) 704WNode * node; 705int num_tabs; 706FILE * fp; 707{ 708 int i; 709 710 for (i = 0; i < num_tabs; i++) 711 fprintf(fp, "\t"); 712 fprintf(fp, "%s %s\n", node->class, node->name); 713 714 num_tabs++; 715 for (i = 0; i < node->num_children; i++) 716 PerformTreeToFileDump(node->children[i], num_tabs, fp); 717} 718 719