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