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