1 /*
2 * bltTreeViewCmd.c --
3 *
4 * This module implements an hierarchy widget for the BLT toolkit.
5 *
6 * Copyright 1998-1999 Lucent Technologies, Inc.
7 *
8 * Permission to use, copy, modify, and distribute this software and
9 * its documentation for any purpose and without fee is hereby
10 * granted, provided that the above copyright notice appear in all
11 * copies and that both that the copyright notice and warranty
12 * disclaimer appear in supporting documentation, and that the names
13 * of Lucent Technologies or any of their entities not be used in
14 * advertising or publicity pertaining to distribution of the software
15 * without specific, written prior permission.
16 *
17 * Lucent Technologies disclaims all warranties with regard to this
18 * software, including all implied warranties of merchantability and
19 * fitness. In no event shall Lucent Technologies be liable for any
20 * special, indirect or consequential damages or any damages
21 * whatsoever resulting from loss of use, data or profits, whether in
22 * an action of contract, negligence or other tortuous action, arising
23 * out of or in connection with the use or performance of this
24 * software.
25 *
26 * The "treeview" widget was created by George A. Howlett.
27 * Extensive cleanups and enhancements by Peter MacDonald.
28 */
29
30 /*
31 * TODO:
32 *
33 * BUGS:
34 * 1. "open" operation should change scroll offset so that as many
35 * new entries (up to half a screen) can be seen.
36 * 2. "open" needs to adjust the scrolloffset so that the same entry
37 * is seen at the same place.
38 */
39 #include "bltInt.h"
40
41 #ifndef NO_TREEVIEW
42
43 #include "bltTreeView.h"
44 #include "bltList.h"
45 #include <X11/Xutil.h>
46 #include <X11/Xatom.h>
47
48 #define CLAMP(val,low,hi) \
49 (((val) < (low)) ? (low) : ((val) > (hi)) ? (hi) : (val))
50
51 static TreeViewCompareProc ExactCompare, GlobCompare, RegexpCompare, InlistCompare;
52 static TreeViewApplyProc ShowEntryApplyProc, HideEntryApplyProc,
53 MapAncestorsApplyProc, FixSelectionsApplyProc;
54 static Tk_LostSelProc LostSelection;
55 static int SelectEntryApplyProc( TreeView *tvPtr, TreeViewEntry *entryPtr, TreeViewColumn *columnPtr);
56 static int GetEntryFromObj2( TreeView *tvPtr, Tcl_Obj *objPtr, TreeViewEntry **entryPtrPtr);
57 static int TagDefine( TreeView *tvPtr, Tcl_Interp *interp, char *tagName);
58
59 extern Blt_CustomOption bltTreeViewIconsOption;
60 extern Blt_CustomOption bltTreeViewUidOption;
61 extern Blt_CustomOption bltTreeViewTreeOption;
62 extern Blt_CustomOption bltTreeViewStyleOption;
63
64 extern Blt_ConfigSpec bltTreeViewButtonSpecs[];
65 extern Blt_ConfigSpec bltTreeViewSpecs[];
66 extern Blt_ConfigSpec bltTreeViewEntrySpecs[];
67
68 #define TAG_UNKNOWN (1<<0)
69 #define TAG_RESERVED (1<<1)
70 #define TAG_USER_DEFINED (1<<2)
71
72 #define TAG_SINGLE (1<<3)
73 #define TAG_MULTIPLE (1<<4)
74 #define TAG_LIST (1<<5)
75 #define TAG_ALL (1<<6)
76 #define TAG_ROOTCHILDREN (1<<7)
77
78 /*
79 *----------------------------------------------------------------------
80 *
81 * SkipSeparators --
82 *
83 * Moves the character pointer past one of more separators.
84 *
85 * Results:
86 * Returns the updates character pointer.
87 *
88 *----------------------------------------------------------------------
89 */
90 static char *
SkipSeparators(path,separator,length)91 SkipSeparators(path, separator, length)
92 char *path, *separator;
93 int length;
94 {
95 while ((path[0] == separator[0]) &&
96 (strncmp(path, separator, length) == 0)) {
97 path += length;
98 }
99 return path;
100 }
101
102 /*
103 *----------------------------------------------------------------------
104 *
105 * DeleteNode --
106 *
107 * Delete the node and its descendants. Don't remove the root
108 * node, though. If the root node is specified, simply remove
109 * all its children.
110 *
111 *----------------------------------------------------------------------
112 */
113 static void
DeleteNode(tvPtr,node)114 DeleteNode(tvPtr, node)
115 TreeView *tvPtr;
116 Blt_TreeNode node;
117 {
118 Blt_TreeNode root;
119
120 if (!Blt_TreeTagTableIsShared(tvPtr->tree)) {
121 Blt_TreeClearTags(tvPtr->tree, node);
122 }
123 root = tvPtr->rootNode;
124 if (node == root) {
125 Blt_TreeNode next;
126 /* Don't delete the root node. Simply clean out the tree. */
127 for (node = Blt_TreeFirstChild(node); node != NULL; node = next) {
128 next = Blt_TreeNextSibling(node);
129 Blt_TreeDeleteNode(tvPtr->tree, node);
130 }
131 } else if (Blt_TreeIsAncestor(root, node)) {
132 Blt_TreeDeleteNode(tvPtr->tree, node);
133 }
134 }
135
136 /*
137 *----------------------------------------------------------------------
138 *
139 * SplitPath --
140 *
141 * Returns the trailing component of the given path. Trailing
142 * separators are ignored.
143 *
144 * Results:
145 * Returns the string of the tail component.
146 *
147 *----------------------------------------------------------------------
148 */
149 static int
SplitPath(tvPtr,path,depthPtr,compPtrPtr)150 SplitPath(tvPtr, path, depthPtr, compPtrPtr)
151 TreeView *tvPtr;
152 char *path;
153 int *depthPtr;
154 char ***compPtrPtr;
155 {
156 int skipLen, pathLen;
157 int depth, listSize;
158 char **components;
159 register char *p;
160 char *sep;
161
162 if (tvPtr->pathSep == SEPARATOR_LIST) {
163 if (Tcl_SplitList(tvPtr->interp, path, depthPtr, compPtrPtr)
164 != TCL_OK) {
165 return TCL_ERROR;
166 }
167 return TCL_OK;
168 }
169 pathLen = strlen(path);
170
171 skipLen = strlen(tvPtr->pathSep);
172 path = SkipSeparators(path, tvPtr->pathSep, skipLen);
173 depth = pathLen / skipLen;
174
175 listSize = (depth + 1) * sizeof(char *);
176 components = Blt_Malloc(listSize + (pathLen + 1));
177 assert(components);
178 p = (char *)components + listSize;
179 strcpy(p, path);
180
181 sep = strstr(p, tvPtr->pathSep);
182 depth = 0;
183 while ((*p != '\0') && (sep != NULL)) {
184 *sep = '\0';
185 components[depth++] = p;
186 p = SkipSeparators(sep + skipLen, tvPtr->pathSep, skipLen);
187 sep = strstr(p, tvPtr->pathSep);
188 }
189 if (*p != '\0') {
190 components[depth++] = p;
191 }
192 components[depth] = NULL;
193 *depthPtr = depth;
194 *compPtrPtr = components;
195 return TCL_OK;
196 }
197
198
199 static TreeViewEntry *
LastEntry(tvPtr,entryPtr,mask)200 LastEntry(tvPtr, entryPtr, mask)
201 TreeView *tvPtr;
202 TreeViewEntry *entryPtr;
203 unsigned int mask;
204 {
205 Blt_TreeNode next;
206 TreeViewEntry *nextPtr;
207
208 next = Blt_TreeLastChild(entryPtr->node);
209 while (next != NULL) {
210 nextPtr = Blt_NodeToEntry(tvPtr, next);
211 if ((nextPtr->flags & mask) != mask) {
212 entryPtr = nextPtr;
213 break;
214 }
215 entryPtr = nextPtr;
216 next = Blt_TreeLastChild(next);
217 }
218 return entryPtr;
219 }
220
221 static TreeViewEntry *
LastNode(tvPtr,entryPtr,mask)222 LastNode(tvPtr, entryPtr, mask)
223 TreeView *tvPtr;
224 TreeViewEntry *entryPtr;
225 unsigned int mask;
226 {
227 TreeViewEntry *nextPtr;
228
229 while ((nextPtr = LastEntry(tvPtr, entryPtr, mask)) != NULL &&
230 nextPtr != entryPtr) {
231 entryPtr = nextPtr;
232 if ((nextPtr->flags & ENTRY_CLOSED) && entryPtr != tvPtr->rootPtr) {
233 break;
234 }
235 }
236 return entryPtr;
237 }
238
239
240 /*
241 *----------------------------------------------------------------------
242 *
243 * ShowEntryApplyProc --
244 *
245 * Results:
246 * Always returns TCL_OK.
247 *
248 *----------------------------------------------------------------------
249 */
250 /*ARGSUSED*/
251 static int
ShowEntryApplyProc(tvPtr,entryPtr)252 ShowEntryApplyProc(tvPtr, entryPtr)
253 TreeView *tvPtr; /* Not used. */
254 TreeViewEntry *entryPtr;
255 {
256 entryPtr->flags &= ~ENTRY_HIDDEN;
257 return TCL_OK;
258 }
259
260 /*
261 *----------------------------------------------------------------------
262 *
263 * HideEntryApplyProc --
264 *
265 * Results:
266 * Always returns TCL_OK.
267 *
268 *----------------------------------------------------------------------
269 */
270 /*ARGSUSED*/
271 static int
HideEntryApplyProc(tvPtr,entryPtr)272 HideEntryApplyProc(tvPtr, entryPtr)
273 TreeView *tvPtr; /* Not used. */
274 TreeViewEntry *entryPtr;
275 {
276 entryPtr->flags |= ENTRY_HIDDEN;
277 return TCL_OK;
278 }
279
280 static void
MapAncestors(tvPtr,entryPtr)281 MapAncestors(tvPtr, entryPtr)
282 TreeView *tvPtr;
283 TreeViewEntry *entryPtr;
284 {
285 while (entryPtr && entryPtr != tvPtr->rootPtr) {
286 entryPtr = Blt_TreeViewParentEntry(entryPtr);
287 if (entryPtr && entryPtr->flags & (ENTRY_CLOSED | ENTRY_HIDDEN)) {
288 tvPtr->flags |= TV_LAYOUT;
289 entryPtr->flags &= ~(ENTRY_CLOSED | ENTRY_HIDDEN);
290 }
291 }
292 }
293
294 /*
295 *----------------------------------------------------------------------
296 *
297 * MapAncestorsApplyProc --
298 *
299 * If a node in mapped, then all its ancestors must be mapped also.
300 * This routine traverses upwards and maps each unmapped ancestor.
301 * It's assumed that for any mapped ancestor, all it's ancestors
302 * will already be mapped too.
303 *
304 * Results:
305 * Always returns TCL_OK.
306 *
307 *----------------------------------------------------------------------
308 */
309 static int
MapAncestorsApplyProc(tvPtr,entryPtr)310 MapAncestorsApplyProc(tvPtr, entryPtr)
311 TreeView *tvPtr;
312 TreeViewEntry *entryPtr;
313 {
314 /*
315 * Make sure that all the ancestors of this entry are mapped too.
316 */
317 while (entryPtr != tvPtr->rootPtr) {
318 entryPtr = Blt_TreeViewParentEntry(entryPtr);
319 if ((entryPtr->flags & (ENTRY_HIDDEN | ENTRY_CLOSED)) == 0) {
320 break; /* Assume ancestors are also mapped. */
321 }
322 entryPtr->flags &= ~(ENTRY_HIDDEN | ENTRY_CLOSED);
323 }
324 return TCL_OK;
325 }
326
327 /*
328 *----------------------------------------------------------------------
329 *
330 * FindPath --
331 *
332 * Finds the node designated by the given path. Each path
333 * component is searched for as the tree is traversed.
334 *
335 * A leading character string is trimmed off the path if it
336 * matches the one designated (see the -trimleft option).
337 *
338 * If no separator is designated (see the -separator
339 * configuration option), the path is considered a Tcl list.
340 * Otherwise the each component of the path is separated by a
341 * character string. Leading and trailing separators are
342 * ignored. Multiple separators are treated as one.
343 *
344 * Results:
345 * Returns the pointer to the designated node. If any component
346 * can't be found, NULL is returned.
347 *
348 *----------------------------------------------------------------------
349 */
350 static TreeViewEntry *
FindPath(tvPtr,rootPtr,path)351 FindPath(tvPtr, rootPtr, path)
352 TreeView *tvPtr;
353 TreeViewEntry *rootPtr;
354 char *path;
355 {
356 Blt_TreeNode child;
357 char **compArr;
358 char *name;
359 int nComp;
360 register char **p;
361 TreeViewEntry *entryPtr;
362
363 /* Trim off characters that we don't want */
364 if (tvPtr->trimLeft != NULL) {
365 register char *s1, *s2;
366
367 /* Trim off leading character string if one exists. */
368 for (s1 = path, s2 = tvPtr->trimLeft; *s2 != '\0'; s2++, s1++) {
369 if (*s1 != *s2) {
370 break;
371 }
372 }
373 if (*s2 == '\0') {
374 path = s1;
375 }
376 }
377 if (*path == '\0') {
378 return rootPtr;
379 }
380 name = path;
381 entryPtr = rootPtr;
382 if (tvPtr->pathSep == SEPARATOR_NONE) {
383 child = Blt_TreeFindChildRev(entryPtr->node, name, tvPtr->insertFirst);
384 if (child == NULL) {
385 goto error;
386 }
387 return Blt_NodeToEntry(tvPtr, child);
388 }
389
390 if (SplitPath(tvPtr, path, &nComp, &compArr) != TCL_OK) {
391 return NULL;
392 }
393 for (p = compArr; *p != NULL; p++) {
394 name = *p;
395 child = Blt_TreeFindChildRev(entryPtr->node, name, tvPtr->insertFirst);
396 if (child == NULL) {
397 Blt_Free(compArr);
398 goto error;
399 }
400 entryPtr = Blt_NodeToEntry(tvPtr, child);
401 }
402 Blt_Free(compArr);
403 return entryPtr;
404 error:
405 {
406 Tcl_DString dString;
407
408 Tcl_DStringInit(&dString);
409 Blt_TreeViewGetFullName(tvPtr, entryPtr, FALSE, &dString);
410 Tcl_AppendResult(tvPtr->interp, "can't find node \"", name,
411 "\" in parent node \"", Tcl_DStringValue(&dString), "\"",
412 (char *)NULL);
413 Tcl_DStringFree(&dString);
414 }
415 return NULL;
416
417 }
418
419 /*
420 *----------------------------------------------------------------------
421 *
422 * NodeToObj --
423 *
424 * Converts a node pointer to a string representation.
425 * The string contains the node's index which is unique.
426 *
427 * Results:
428 * The string representation of the node is returned. Note that
429 * the string is stored statically, so that callers must save the
430 * string before the next call to this routine overwrites the
431 * static array again.
432 *
433 *----------------------------------------------------------------------
434 */
435 static Tcl_Obj *
NodeToObj(node)436 NodeToObj(node)
437 Blt_TreeNode node;
438 {
439 return Tcl_NewIntObj(Blt_TreeNodeId(node));
440 /*char string[200];
441
442 sprintf(string, "%d", Blt_TreeNodeId(node));
443 return Tcl_NewStringObj(string, -1);*/
444 }
445
446
447 static int
GetEntryFromSpecialId(tvPtr,string,entryPtrPtr)448 GetEntryFromSpecialId(tvPtr, string, entryPtrPtr)
449 TreeView *tvPtr;
450 char *string;
451 TreeViewEntry **entryPtrPtr;
452 {
453 Blt_TreeNode node;
454 TreeViewEntry *fromPtr, *entryPtr;
455 char c;
456
457 entryPtr = NULL;
458 fromPtr = tvPtr->fromPtr;
459 if (fromPtr == NULL) {
460 fromPtr = tvPtr->focusPtr;
461 }
462 if (fromPtr == NULL) {
463 fromPtr = tvPtr->rootPtr;
464 }
465 c = string[0];
466 if (c == '@') {
467 int x, y;
468
469 if (Blt_GetXY(tvPtr->interp, tvPtr->tkwin, string, &x, &y) == TCL_OK) {
470 entryPtr = Blt_TreeViewNearestEntry(tvPtr, x, y, TRUE);
471 }
472 } else if ((c == 'b') && (strcmp(string, "bottom") == 0)) {
473 if (tvPtr->flatView) {
474 entryPtr = FLATIND(tvPtr, tvPtr->nEntries - 1);
475 } else {
476 entryPtr = LastNode(tvPtr, tvPtr->rootPtr, ENTRY_MASK);
477 }
478 } else if ((c == 'l') && (strcmp(string, "last") == 0)) {
479 entryPtr = LastNode(tvPtr, tvPtr->rootPtr, 0);
480 } else if ((c == 't') && (strcmp(string, "tail") == 0)) {
481 entryPtr = LastNode(tvPtr, tvPtr->rootPtr, 0);
482 } else if ((c == 't') && (strcmp(string, "top") == 0)) {
483 if (tvPtr->flatView) {
484 entryPtr = FLATIND(tvPtr,0);
485 } else {
486 entryPtr = tvPtr->rootPtr;
487 }
488 if (entryPtr != NULL && entryPtr == tvPtr->rootPtr &&
489 tvPtr->flags & TV_HIDE_ROOT) {
490 entryPtr = Blt_TreeViewNextEntry(entryPtr, ENTRY_MASK);
491 }
492 } else if ((c == 'e') && (strcmp(string, "end") == 0)) {
493 entryPtr = LastEntry(tvPtr, tvPtr->rootPtr, ENTRY_MASK);
494 } else if ((c == 'a') && (strcmp(string, "anchor") == 0)) {
495 entryPtr = tvPtr->selAnchorPtr;
496 } else if ((c == 'a') && (strcmp(string, "active") == 0)) {
497 entryPtr = tvPtr->activePtr;
498 } else if ((c == 'f') && (strcmp(string, "focus") == 0)) {
499 entryPtr = tvPtr->focusPtr;
500 if ((entryPtr == tvPtr->rootPtr) && (tvPtr->flags & TV_HIDE_ROOT)) {
501 entryPtr = Blt_TreeViewNextEntry(tvPtr->rootPtr, ENTRY_MASK);
502 }
503 } else if ((c == 'r') && (strcmp(string, "root") == 0)) {
504 entryPtr = tvPtr->rootPtr;
505 } else if ((c == 'p') && (strcmp(string, "parent") == 0)) {
506 if (fromPtr != tvPtr->rootPtr) {
507 entryPtr = Blt_TreeViewParentEntry(fromPtr);
508 }
509 } else if ((c == 'c') && (strcmp(string, "current") == 0)) {
510 /* Can't trust picked item, if entries have been
511 * added or deleted. */
512 if (!(tvPtr->flags & TV_DIRTY)) {
513 ClientData context;
514
515 context = Blt_GetCurrentContext(tvPtr->bindTable);
516
517 if ((context == ITEM_ENTRY) ||
518 (context == ITEM_ENTRY_BUTTON) ||
519 ((unsigned int)context >= (unsigned int)ITEM_STYLE)) {
520 entryPtr = Blt_GetCurrentItem(tvPtr->bindTable);
521 }
522 }
523 } else if ((c == 'u') && (strcmp(string, "up") == 0)) {
524 entryPtr = fromPtr;
525 if (tvPtr->flatView) {
526 int i;
527
528 i = entryPtr->flatIndex - 1;
529 if (i >= 0) {
530 entryPtr = FLATIND( tvPtr, i);
531 }
532 } else {
533 entryPtr = Blt_TreeViewPrevEntry(fromPtr, ENTRY_MASK);
534 if (entryPtr == NULL) {
535 entryPtr = fromPtr;
536 }
537 if ((entryPtr == tvPtr->rootPtr) &&
538 (tvPtr->flags & TV_HIDE_ROOT)) {
539 entryPtr = Blt_TreeViewNextEntry(entryPtr, ENTRY_MASK);
540 }
541 }
542 } else if ((c == 'd') && (strcmp(string, "down") == 0)) {
543 entryPtr = fromPtr;
544 if (tvPtr->flatView) {
545 int i;
546
547 i = entryPtr->flatIndex + 1;
548 if (i < tvPtr->nEntries) {
549 entryPtr = FLATIND(tvPtr, i);
550 }
551 } else {
552 entryPtr = Blt_TreeViewNextEntry(fromPtr, ENTRY_MASK);
553 if (entryPtr == NULL) {
554 entryPtr = fromPtr;
555 }
556 if ((entryPtr == tvPtr->rootPtr) &&
557 (tvPtr->flags & TV_HIDE_ROOT)) {
558 entryPtr = Blt_TreeViewNextEntry(entryPtr, ENTRY_MASK);
559 }
560 }
561 } else if ((c == 'p') && (strcmp(string, "prev") == 0)) {
562 entryPtr = fromPtr;
563 if (tvPtr->flatView) {
564 int i;
565
566 i = entryPtr->flatIndex - 1;
567 if (i < 0) {
568 i = tvPtr->nEntries - 1;
569 }
570 entryPtr = FLATIND( tvPtr, i);
571 } else {
572 entryPtr = Blt_TreeViewPrevEntry(fromPtr, ENTRY_MASK);
573 if (entryPtr == NULL) {
574 entryPtr = LastEntry(tvPtr, tvPtr->rootPtr, ENTRY_MASK);
575 }
576 if ((entryPtr == tvPtr->rootPtr) &&
577 (tvPtr->flags & TV_HIDE_ROOT)) {
578 entryPtr = LastEntry(tvPtr, tvPtr->rootPtr, ENTRY_MASK);
579 /*entryPtr = Blt_TreeViewNextEntry(entryPtr, ENTRY_MASK); */
580 }
581 }
582 } else if ((c == 'n') && (strcmp(string, "next") == 0)) {
583 entryPtr = fromPtr;
584 if (tvPtr->flatView) {
585 int i;
586
587 i = entryPtr->flatIndex + 1;
588 if (i >= tvPtr->nEntries) {
589 i = 0;
590 }
591 entryPtr = FLATIND(tvPtr, i);
592 } else {
593 entryPtr = Blt_TreeViewNextEntry(fromPtr, ENTRY_MASK);
594 if (entryPtr == NULL) {
595 if (tvPtr->flags & TV_HIDE_ROOT) {
596 entryPtr = Blt_TreeViewNextEntry(tvPtr->rootPtr,ENTRY_MASK);
597 } else {
598 entryPtr = tvPtr->rootPtr;
599 }
600 }
601 }
602 } else if ((c == 'n') && (strcmp(string, "nextsibling") == 0)) {
603 node = Blt_TreeNextSibling(fromPtr->node);
604 if (node != NULL) {
605 entryPtr = Blt_NodeToEntry(tvPtr, node);
606 }
607 } else if ((c == 'p') && (strcmp(string, "prevsibling") == 0)) {
608 node = Blt_TreePrevSibling(fromPtr->node);
609 if (node != NULL) {
610 entryPtr = Blt_NodeToEntry(tvPtr, node);
611 }
612 } else if ((c == 'v') && (strcmp(string, "view.top") == 0)) {
613 if (tvPtr->nVisible > 0) {
614 entryPtr = tvPtr->visibleArr[0];
615 }
616 } else if ((c == 'v') && (strcmp(string, "view.bottom") == 0)) {
617 if (tvPtr->nVisible > 0) {
618 entryPtr = tvPtr->visibleArr[tvPtr->nVisible - 1];
619 }
620 } else {
621 return TCL_ERROR;
622 }
623 *entryPtrPtr = entryPtr;
624 return TCL_OK;
625 }
626
627 static int
GetTagInfo(tvPtr,tagName,infoPtr)628 GetTagInfo(tvPtr, tagName, infoPtr)
629 TreeView *tvPtr;
630 char *tagName;
631 TreeViewTagInfo *infoPtr;
632 {
633 static int cnt = 0;
634
635 infoPtr->tagType = TAG_RESERVED | TAG_SINGLE;
636 infoPtr->entryPtr = NULL;
637
638 if (strcmp(tagName, "all") == 0) {
639 infoPtr->entryPtr = tvPtr->rootPtr;
640 infoPtr->tagType |= (TAG_ALL|TAG_MULTIPLE);
641
642 infoPtr->node = infoPtr->entryPtr->node;
643 infoPtr->inode = infoPtr->node->inode;
644 } else if (strcmp(tagName, "nonroot") == 0) {
645 infoPtr->entryPtr = Blt_TreeViewNextEntry(tvPtr->rootPtr, 0);
646 infoPtr->tagType |= (TAG_ALL|TAG_MULTIPLE);
647 if (infoPtr->entryPtr) {
648 infoPtr->node = infoPtr->entryPtr->node;
649 infoPtr->inode = infoPtr->node->inode;
650 }
651 } else if (strcmp(tagName, "rootchildren") == 0) {
652 infoPtr->entryPtr = Blt_TreeViewNextEntry(tvPtr->rootPtr, 0);
653 infoPtr->tagType |= (TAG_ROOTCHILDREN|TAG_MULTIPLE);
654 if (infoPtr->entryPtr) {
655 infoPtr->node = infoPtr->entryPtr->node;
656 infoPtr->inode = infoPtr->node->inode;
657 }
658 } else {
659 /* TODO: is this broken: are nodes not being found for tags. FIXED???. */
660 Blt_HashTable *tablePtr;
661
662 tablePtr = Blt_TreeTagHashTable(tvPtr->tree, tagName);
663 if (tablePtr != NULL) {
664 Blt_HashEntry *hPtr;
665
666 infoPtr->tagType = TAG_USER_DEFINED; /* Empty tags are not
667 * an error. */
668 hPtr = Blt_FirstHashEntry(tablePtr, &infoPtr->cursor);
669 if (hPtr != NULL) {
670 Blt_TreeNode node;
671 int inode;
672
673 node = Blt_GetHashValue(hPtr);
674 inode = node->inode;
675 infoPtr->entryPtr = Blt_NodeToEntry(tvPtr, node);
676 if (infoPtr->entryPtr == NULL && cnt++ == 0) {
677 /* fprintf(stderr, "Dangling node: %d\n", node->inode); */
678 }
679 if (infoPtr->entryPtr != NULL) {
680 infoPtr->node = infoPtr->entryPtr->node;
681 infoPtr->inode = infoPtr->node->inode;
682 }
683 if (Blt_TreeNodeDeleted(infoPtr->entryPtr->node)) {
684 return TCL_ERROR;
685 }
686 if (tablePtr->numEntries > 1) {
687 infoPtr->tagType |= TAG_MULTIPLE;
688 }
689 }
690 } else {
691 infoPtr->tagType = TAG_UNKNOWN;
692 Tcl_AppendResult(tvPtr->interp, "can't find tag or id \"", tagName,
693 "\" in \"", Tk_PathName(tvPtr->tkwin), "\"", (char *)NULL);
694 return TCL_ERROR;
695 }
696 }
697 return TCL_OK;
698 }
699
700 TreeViewEntry *
Blt_TreeViewFirstTaggedEntry(infoPtr)701 Blt_TreeViewFirstTaggedEntry(infoPtr)
702 TreeViewTagInfo *infoPtr;
703 {
704 return infoPtr->entryPtr;
705 }
706
707 TreeViewEntry *
Blt_TreeViewNextTaggedEntry(infoPtr)708 Blt_TreeViewNextTaggedEntry(infoPtr)
709 TreeViewTagInfo *infoPtr;
710 {
711 TreeViewEntry *entryPtr;
712 static int cnt = 0;
713 Blt_TreeNode node;
714
715 entryPtr = NULL;
716 if (infoPtr->entryPtr != NULL) {
717 TreeView *tvPtr = infoPtr->entryPtr->tvPtr;
718
719 if (infoPtr->tagType == TAG_LIST) {
720 int inode, i;
721 i = ++infoPtr->idx;
722
723 if (i >= infoPtr->objc) {
724 return NULL;
725 }
726 if (Tcl_GetIntFromObj(tvPtr->interp, infoPtr->objv[i], &inode) != TCL_OK) {
727 return NULL;
728 }
729 node = Blt_TreeGetNode(tvPtr->tree, inode);
730 infoPtr->entryPtr = Blt_NodeToEntry(tvPtr, node);
731 return infoPtr->entryPtr;
732 }
733
734 if (infoPtr->tagType & TAG_ALL) {
735 if (Blt_TreeNodeDeleted(infoPtr->node) || (infoPtr->inode != infoPtr->node->inode)) {
736 return NULL;
737 }
738 entryPtr = Blt_TreeViewNextEntry(infoPtr->entryPtr, 0);
739 if (entryPtr != NULL) {
740 infoPtr->node =entryPtr->node;
741 infoPtr->inode = infoPtr->node->inode;
742 }
743
744 } else if (infoPtr->tagType & TAG_ROOTCHILDREN) {
745 if (Blt_TreeNodeDeleted(infoPtr->node) || (infoPtr->inode != infoPtr->node->inode)) {
746 return NULL;
747 }
748 entryPtr = Blt_TreeViewNextSibling(infoPtr->entryPtr, 0);
749 if (entryPtr != NULL) {
750 infoPtr->node =entryPtr->node;
751 infoPtr->inode = infoPtr->node->inode;
752 }
753 } else if (infoPtr->tagType & TAG_MULTIPLE) {
754 Blt_HashEntry *hPtr;
755 if (infoPtr->tPtr && infoPtr->tPtr->refCount<=1) {
756 /* Tag was deleted. */
757 return NULL;
758 }
759 hPtr = Blt_NextHashEntry(&infoPtr->cursor);
760 if (hPtr != NULL) {
761
762 node = Blt_GetHashValue(hPtr);
763 entryPtr = Blt_NodeToEntry(tvPtr, node);
764 /*TODO: sometimes this fails. Fixed tag deleted problem. */
765 if (entryPtr == NULL && cnt++ == 0) {
766 /*fprintf(stderr, "dangling node: %d\n", node->inode); */
767 }
768 }
769 }
770 infoPtr->entryPtr = entryPtr;
771 }
772 return entryPtr;
773 }
774
775 /*ARGSUSED*/
776 void
Blt_TreeViewGetTags(interp,tvPtr,entryPtr,list)777 Blt_TreeViewGetTags(interp, tvPtr, entryPtr, list)
778 Tcl_Interp *interp; /* Not used. */
779 TreeView *tvPtr;
780 TreeViewEntry *entryPtr;
781 Blt_List list;
782 {
783 Blt_HashEntry *hPtr;
784 Blt_HashSearch cursor;
785 Blt_TreeTagEntry *tPtr;
786
787 for (hPtr = Blt_TreeFirstTag(tvPtr->tree, &cursor); hPtr != NULL;
788 hPtr = Blt_NextHashEntry(&cursor)) {
789 tPtr = Blt_GetHashValue(hPtr);
790 hPtr = Blt_FindHashEntry(&tPtr->nodeTable, (char *)entryPtr->node);
791 if (hPtr != NULL) {
792 Blt_ListAppend(list, Blt_TreeViewGetUid(tvPtr, tPtr->tagName),0);
793 }
794 }
795 }
796
797 /*
798 *----------------------------------------------------------------------
799 *
800 * AddTag --
801 *
802 *----------------------------------------------------------------------
803 */
804 static int
AddTag(tvPtr,node,tagName)805 AddTag(tvPtr, node, tagName)
806 TreeView *tvPtr;
807 Blt_TreeNode node;
808 char *tagName;
809 {
810 TreeViewEntry *entryPtr;
811
812 if (strcmp(tagName, "root") == 0 || strcmp(tagName, "all") == 0 ||
813 strcmp(tagName, "nonroot") == 0 || strcmp(tagName, "rootchildren") == 0) {
814 Tcl_AppendResult(tvPtr->interp, "can't add reserved tag \"",
815 tagName, "\"", (char *)NULL);
816 return TCL_ERROR;
817 }
818 if (isdigit(UCHAR(tagName[0]))) {
819 Tcl_AppendResult(tvPtr->interp, "invalid tag \"", tagName,
820 "\": can't start with digit", (char *)NULL);
821 return TCL_ERROR;
822 }
823 if (isdigit(UCHAR(tagName[0]))) {
824 Tcl_AppendResult(tvPtr->interp, "invalid tag \"", tagName,
825 "\": can't start with digit", (char *)NULL);
826 return TCL_ERROR;
827 }
828 if (tagName[0] == '@') {
829 Tcl_AppendResult(tvPtr->interp, "invalid tag \"", tagName,
830 "\": can't start with \"@\"", (char *)NULL);
831 return TCL_ERROR;
832 }
833 tvPtr->fromPtr = NULL;
834 if (GetEntryFromSpecialId(tvPtr, tagName, &entryPtr) == TCL_OK) {
835 Tcl_AppendResult(tvPtr->interp, "invalid tag \"", tagName,
836 "\": is a special id", (char *)NULL);
837 return TCL_ERROR;
838 }
839 /* Add the tag to the node. */
840 return Blt_TreeAddTag(tvPtr->tree, node, tagName);
841 }
842
843 int
Blt_TreeViewFindTaggedEntries(tvPtr,objPtr,infoPtr)844 Blt_TreeViewFindTaggedEntries(tvPtr, objPtr, infoPtr)
845 TreeView *tvPtr;
846 Tcl_Obj *objPtr;
847 TreeViewTagInfo *infoPtr;
848 {
849 char *tagName;
850 TreeViewEntry *entryPtr;
851
852 memset(infoPtr, 0, sizeof(*infoPtr));
853 infoPtr->init = 1;
854 tagName = Tcl_GetString(objPtr);
855 infoPtr->tvPtr = tvPtr;
856 tvPtr->fromPtr = NULL;
857 if (tagName[0] == 0) {
858 infoPtr->tagType = TAG_LIST;
859 infoPtr->entryPtr = NULL;
860 infoPtr->objc = 0;
861 infoPtr->idx = 0;
862 return TCL_OK;
863 }
864 if (strstr(tagName, "->") != NULL) {
865 if (GetEntryFromObj2(tvPtr, objPtr, &infoPtr->entryPtr) != TCL_OK) {
866 return TCL_ERROR;
867 }
868 infoPtr->tagType = (TAG_RESERVED | TAG_SINGLE);
869 return TCL_OK;
870 }
871
872 if (isdigit(UCHAR(tagName[0]))) {
873 int inode;
874 Blt_TreeNode node;
875 char *cp = tagName;
876 int i;
877
878 while (isdigit(UCHAR(*cp)) && *cp != 0) {
879 cp++;
880 }
881 if (*cp != 0) {
882 if (Tcl_ListObjGetElements(tvPtr->interp, objPtr, &infoPtr->objc,
883 &infoPtr->objv) != TCL_OK) {
884 return TCL_ERROR;
885 }
886 if (infoPtr->objc<1) {
887 return TCL_ERROR;
888 }
889 for (i=infoPtr->objc-1; i>=0; i--) {
890 if (Tcl_GetIntFromObj(tvPtr->interp, infoPtr->objv[i], &inode) != TCL_OK) {
891 return TCL_ERROR;
892 }
893 /* No use checking nodes here as they can later be deleted. */
894 /*node = Blt_TreeGetNode(tvPtr->tree, inode);
895 if (node == NULL) {
896 Tcl_AppendResult(interp, "unknown node: ", Blt_Itoa(inode), 0);
897 return TCL_ERROR;
898 }*/
899 }
900 node = Blt_TreeGetNode(tvPtr->tree, inode);
901 infoPtr->objPtr = objPtr;
902 Tcl_IncrRefCount(objPtr);
903 infoPtr->entryPtr = Blt_NodeToEntry(tvPtr, node);
904 infoPtr->tagType = TAG_LIST;
905 infoPtr->idx = 0;
906 return TCL_OK;
907 }
908
909 if (Tcl_GetIntFromObj(tvPtr->interp, objPtr, &inode) != TCL_OK) {
910 return TCL_ERROR;
911 }
912 node = Blt_TreeGetNode(tvPtr->tree, inode);
913 infoPtr->entryPtr = Blt_NodeToEntry(tvPtr, node);
914 infoPtr->tagType = (TAG_RESERVED | TAG_SINGLE);
915 } else if (GetEntryFromSpecialId(tvPtr, tagName, &entryPtr) == TCL_OK) {
916 infoPtr->entryPtr = entryPtr;
917 infoPtr->tagType = (TAG_RESERVED | TAG_SINGLE);
918 } else {
919 if (GetTagInfo(tvPtr, tagName, infoPtr) != TCL_OK) {
920 return TCL_ERROR;
921 }
922 if ((infoPtr->tagType & TAG_USER_DEFINED)) {
923 infoPtr->tPtr = Blt_TreeTagHashEntry(tvPtr->tree, tagName);
924 Blt_TreeTagRefIncr(infoPtr->tPtr);
925 }
926 }
927 return TCL_OK;
928 }
929
930
931 /* Cleanup and release resources. */
932 int
Blt_TreeViewDoneTaggedEntries(infoPtr)933 Blt_TreeViewDoneTaggedEntries(infoPtr)
934 TreeViewTagInfo *infoPtr;
935 {
936 if (infoPtr->init == 1) {
937 infoPtr->init = 0;
938 if (infoPtr->objPtr != NULL) {
939 Tcl_DecrRefCount(infoPtr->objPtr);
940 infoPtr->objPtr = NULL;
941 }
942 if ((infoPtr->tagType & TAG_USER_DEFINED) && infoPtr->tPtr) {
943 Blt_TreeTagRefDecr(infoPtr->tPtr);
944 infoPtr->tPtr = NULL;
945 }
946 }
947 return TCL_OK;
948 }
949
950 static Blt_TreeNode
MaxNode(Blt_Tree tree)951 MaxNode(Blt_Tree tree) {
952 Blt_TreeNode node, root, mnode;
953 int max = 0;
954
955 mnode = root = Blt_TreeRootNode(tree);
956 for (node = root; node != NULL; node = Blt_TreeNextNode(root, node)) {
957 if (node->inode > max) {
958 max = node->inode;
959 mnode = node;
960 }
961 }
962 return mnode;
963 }
964
965 static Blt_TreeNode
ParseModifiers(Tcl_Interp * interp,Blt_Tree tree,Blt_TreeNode node,char * modifiers)966 ParseModifiers(
967 Tcl_Interp *interp,
968 Blt_Tree tree,
969 Blt_TreeNode node,
970 char *modifiers)
971 {
972 char *p, *np;
973
974 p = modifiers;
975 do {
976 p += 2; /* Skip the initial "->" */
977 np = strstr(p, "->");
978 if (np != NULL) {
979 *np = '\0';
980 }
981 if ((*p == 'p') && (strcmp(p, "parentnode") == 0)) {
982 node = Blt_TreeNodeParent(node);
983 } else if ((*p == 'f') && (strcmp(p, "firstchild") == 0)) {
984 node = Blt_TreeFirstChild(node);
985 } else if ((*p == 'l') && (strcmp(p, "lastchild") == 0)) {
986 node = Blt_TreeLastChild(node);
987 } else if ((*p == 'n') && (strcmp(p, "nextnode") == 0)) {
988 node = Blt_TreeNextNode(Blt_TreeRootNode(tree), node);
989 } else if ((*p == 'n') && (strcmp(p, "nextsibling") == 0)) {
990 node = Blt_TreeNextSibling(node);
991 } else if ((*p == 'p') && (strcmp(p, "prevnode") == 0)) {
992 node = Blt_TreePrevNode(Blt_TreeRootNode(tree), node);
993 } else if ((*p == 'p') && (strcmp(p, "prevsibling") == 0)) {
994 node = Blt_TreePrevSibling(node);
995 } else if ((*p == 'm') && (strcmp(p, "maxnode") == 0)) {
996 node = MaxNode(tree);
997 } else if (isdigit(UCHAR(*p))) {
998 int inode;
999
1000 if (Tcl_GetInt(interp, p, &inode) != TCL_OK) {
1001 node = NULL;
1002 } else {
1003 node = Blt_TreeGetNode(tree, inode);
1004 }
1005 } else {
1006 char *endp;
1007
1008 if (np != NULL) {
1009 endp = np - 1;
1010 } else {
1011 endp = p + strlen(p) - 1;
1012 }
1013 if ((*p == '\'') && (*endp == '\'')) {
1014 *endp = '\0';
1015 node = Blt_TreeFindChild(node, p + 1);
1016 *endp = '\'';
1017 } else if ((*p == '"') && (*endp == '"')) {
1018 *endp = '\0';
1019 node = Blt_TreeFindChild(node, p + 1);
1020 *endp = '"';
1021 } else {
1022 node = Blt_TreeFindChild(node, p);
1023 }
1024 }
1025 if (node == NULL) {
1026 goto error;
1027 }
1028 if (np != NULL) {
1029 *np = '-'; /* Repair the string */
1030 }
1031 p = np;
1032 } while (np != NULL);
1033 return node;
1034 error:
1035 if (np != NULL) {
1036 *np = '-'; /* Repair the string */
1037 }
1038 return NULL;
1039 }
1040
1041
1042 /*
1043 *----------------------------------------------------------------------
1044 *
1045 * GetEntryFromObj2 --
1046 *
1047 * Converts a string into node pointer. The string may be in one
1048 * of the following forms:
1049 *
1050 * NNN - inode.
1051 * "active" - Currently active node.
1052 * "anchor" - anchor of selected region.
1053 * "current" - Currently picked node in bindtable.
1054 * "focus" - The node currently with focus.
1055 * "root" - Root node.
1056 * "end" - Last open node in the entire hierarchy.
1057 * "next" - Next open node from the currently active
1058 * node. Wraps around back to top.
1059 * "prev" - Previous open node from the currently active
1060 * node. Wraps around back to bottom.
1061 * "up" - Next open node from the currently active
1062 * node. Does not wrap around.
1063 * "down" - Previous open node from the currently active
1064 * node. Does not wrap around.
1065 * "nextsibling" - Next sibling of the current node.
1066 * "prevsibling" - Previous sibling of the current node.
1067 * "parent" - Parent of the current node.
1068 * "view.top" - Top of viewport.
1069 * "view.bottom" - Bottom of viewport.
1070 * @x,y - Closest node to the specified X-Y position.
1071 *
1072 * Results:
1073 * If the string is successfully converted, TCL_OK is returned.
1074 * The pointer to the node is returned via nodePtr.
1075 * Otherwise, TCL_ERROR is returned and an error message is left
1076 * in interpreter's result field.
1077 *
1078 *----------------------------------------------------------------------
1079 */
1080 static int
GetEntryFromObj2(tvPtr,objPtr,entryPtrPtr)1081 GetEntryFromObj2(tvPtr, objPtr, entryPtrPtr)
1082 TreeView *tvPtr;
1083 Tcl_Obj *objPtr;
1084 TreeViewEntry **entryPtrPtr;
1085 {
1086 Tcl_Interp *interp;
1087 char *string;
1088 TreeViewTagInfo info = {0};
1089 char *p;
1090 char save;
1091 int result;
1092 Blt_TreeNode node;
1093
1094 interp = tvPtr->interp;
1095
1096 string = Tcl_GetString(objPtr);
1097 *entryPtrPtr = NULL;
1098 p = strstr(string, "->");
1099 if (isdigit(UCHAR(string[0]))) {
1100 int inode;
1101
1102 if (p != NULL) {
1103
1104 save = *p;
1105 *p = '\0';
1106 result = Tcl_GetInt(interp, string, &inode);
1107 *p = save;
1108 if (result != TCL_OK) {
1109 return TCL_ERROR;
1110 }
1111 } else {
1112
1113 if (Tcl_GetIntFromObj(interp, objPtr, &inode) != TCL_OK) {
1114 return TCL_ERROR;
1115 }
1116 }
1117 node = Blt_TreeGetNode(tvPtr->tree, inode);
1118 if (node == NULL) {
1119 Tcl_AppendResult(interp, "unknown entry: ", string, 0);
1120 return TCL_ERROR;
1121 }
1122 if (p != NULL) {
1123 node = ParseModifiers(interp, tvPtr->tree, node, p);
1124 if (node == NULL) {
1125 Tcl_AppendResult(interp, "can't find tag or id:", string, 0);
1126 return TCL_ERROR;
1127 }
1128 }
1129
1130 *entryPtrPtr = Blt_NodeToEntry(tvPtr, node);
1131 return TCL_OK; /* Node Id. */
1132 }
1133 if (p == NULL) {
1134 if (GetEntryFromSpecialId(tvPtr, string, entryPtrPtr) == TCL_OK) {
1135 return TCL_OK; /* Special Id. */
1136 }
1137 if (GetTagInfo(tvPtr, string, &info) != TCL_OK) {
1138 return TCL_ERROR;
1139 }
1140 } else {
1141 save = *p;
1142 *p = '\0';
1143 info.tagType = 0;
1144 result = GetEntryFromSpecialId(tvPtr, string, &info.entryPtr);
1145 if (result != TCL_OK) {
1146 result = GetTagInfo(tvPtr, string, &info);
1147 }
1148 *p = save;
1149 if (result != TCL_OK) {
1150 return TCL_ERROR;
1151 }
1152 if (info.tagType & TAG_MULTIPLE) {
1153 Tcl_AppendResult(interp, "more than one entry tagged as \"", string,
1154 "\"", (char *)NULL);
1155 return TCL_ERROR;
1156 }
1157 node = ParseModifiers(interp, tvPtr->tree, info.entryPtr->node, p);
1158 if (node == NULL) {
1159 Tcl_AppendResult(interp, "can't find tag or id:", string, 0);
1160 return TCL_ERROR;
1161 }
1162 info.entryPtr = Blt_NodeToEntry(tvPtr, node);
1163 }
1164 if (info.tagType & TAG_MULTIPLE) {
1165 Tcl_AppendResult(interp, "more than one entry tagged as \"", string,
1166 "\"", (char *)NULL);
1167 return TCL_ERROR;
1168 }
1169 *entryPtrPtr = info.entryPtr;
1170 return TCL_OK; /* Singleton tag. */
1171 }
1172
1173 static int
GetEntryFromObj(tvPtr,objPtr,entryPtrPtr)1174 GetEntryFromObj(tvPtr, objPtr, entryPtrPtr)
1175 TreeView *tvPtr;
1176 Tcl_Obj *objPtr;
1177 TreeViewEntry **entryPtrPtr;
1178 {
1179 tvPtr->fromPtr = NULL;
1180 return GetEntryFromObj2(tvPtr, objPtr, entryPtrPtr);
1181 }
1182
1183 /*
1184 *----------------------------------------------------------------------
1185 *
1186 * Blt_TreeViewGetEntry --
1187 *
1188 * Returns an entry based upon its index.
1189 *
1190 * Results:
1191 * If the string is successfully converted, TCL_OK is returned.
1192 * The pointer to the node is returned via nodePtr.
1193 * Otherwise, TCL_ERROR is returned and an error message is left
1194 * in interpreter's result field.
1195 *
1196 *----------------------------------------------------------------------
1197 */
1198 int
Blt_TreeViewGetEntry(tvPtr,objPtr,entryPtrPtr)1199 Blt_TreeViewGetEntry(tvPtr, objPtr, entryPtrPtr)
1200 TreeView *tvPtr;
1201 Tcl_Obj *objPtr;
1202 TreeViewEntry **entryPtrPtr;
1203 {
1204 TreeViewEntry *entryPtr;
1205
1206 if (GetEntryFromObj(tvPtr, objPtr, &entryPtr) != TCL_OK) {
1207 return TCL_ERROR;
1208 }
1209 if (entryPtr == NULL) {
1210 Tcl_ResetResult(tvPtr->interp);
1211 Tcl_AppendResult(tvPtr->interp, "can't find entry \"",
1212 Tcl_GetString(objPtr), "\" in \"", Tk_PathName(tvPtr->tkwin),
1213 "\"", (char *)NULL);
1214 return TCL_ERROR;
1215 }
1216 *entryPtrPtr = entryPtr;
1217 return TCL_OK;
1218 }
1219
1220 static Blt_TreeNode
GetNthNode(parent,position)1221 GetNthNode(parent, position)
1222 Blt_TreeNode parent;
1223 int position;
1224 {
1225 Blt_TreeNode node;
1226 int count;
1227
1228 count = 0;
1229 for(node = Blt_TreeFirstChild(parent); node != NULL;
1230 node = Blt_TreeNextSibling(node)) {
1231 if (count++ == position) {
1232 return node;
1233 }
1234 }
1235 return Blt_TreeLastChild(parent);
1236 }
1237
1238 static TreeViewEntry *
GetNthEntry(TreeViewEntry * parentPtr,int position,unsigned int mask)1239 GetNthEntry(
1240 TreeViewEntry *parentPtr,
1241 int position,
1242 unsigned int mask)
1243 {
1244 TreeViewEntry *entryPtr;
1245 int count;
1246
1247 count = 0;
1248 for(entryPtr = Blt_TreeViewFirstChild(parentPtr, mask); entryPtr != NULL;
1249 entryPtr = Blt_TreeViewNextSibling(entryPtr, mask)) {
1250 if (count++ == position) {
1251 return entryPtr;
1252 }
1253 }
1254 return Blt_TreeViewLastChild(parentPtr, mask);
1255 }
1256
1257 /*
1258 * Preprocess the command string for percent substitution.
1259 */
1260 void
Blt_TreeViewPercentSubst(tvPtr,entryPtr,columnPtr,command,value,resultPtr)1261 Blt_TreeViewPercentSubst(tvPtr, entryPtr, columnPtr, command, value, resultPtr)
1262 TreeView *tvPtr;
1263 TreeViewEntry *entryPtr;
1264 TreeViewColumn *columnPtr;
1265 char *command;
1266 char *value;
1267 Tcl_DString *resultPtr;
1268 {
1269 register char *last, *p;
1270 char *fullName;
1271 Tcl_DString dString;
1272 TreeViewValue *valuePtr;
1273 int one = (command[0] == '%' && strlen(command)==2);
1274
1275 /*
1276 * Get the full path name of the node, in case we need to
1277 * substitute for it.
1278 */
1279 Tcl_DStringInit(&dString);
1280 fullName = Blt_TreeViewGetFullName(tvPtr, entryPtr, TRUE, &dString);
1281 Tcl_DStringInit(resultPtr);
1282 /* Append the widget name and the node .t 0 */
1283 for (last = p = command; *p != '\0'; p++) {
1284 if (*p == '%') {
1285 char *string;
1286 char buf[3];
1287
1288 if (p > last) {
1289 *p = '\0';
1290 Tcl_DStringAppend(resultPtr, last, -1);
1291 *p = '%';
1292 }
1293 switch (*(p + 1)) {
1294 case '%': /* Percent sign */
1295 string = "%";
1296 break;
1297 case 'W': /* Widget name */
1298 string = Tk_PathName(tvPtr->tkwin);
1299 if (!one) {
1300 Tcl_DStringAppendElement(resultPtr, string);
1301 string = NULL;
1302 }
1303 break;
1304 case 'F': /* Formatted value of the data. */
1305 if (entryPtr && columnPtr &&
1306 ((valuePtr = Blt_TreeViewFindValue(entryPtr, columnPtr))) &&
1307 valuePtr->textPtr) {
1308 Tcl_DString dStr;
1309 Tcl_DStringInit(&dStr);
1310 Blt_TextLayoutValue( valuePtr->textPtr, &dStr);
1311 if (!one) {
1312 Tcl_DStringAppendElement(resultPtr, Tcl_DStringValue(&dStr));
1313 } else {
1314 Tcl_DStringAppend(resultPtr, Tcl_DStringValue(&dStr), -1);
1315 }
1316 Tcl_DStringFree(&dStr);
1317 string = NULL;
1318 break;
1319 }
1320 case 'V': /* Value */
1321 string = value;
1322 if (!one) {
1323 Tcl_DStringAppendElement(resultPtr, value);
1324 string = NULL;
1325 }
1326 break;
1327 case 'P': /* Full pathname */
1328 string = fullName;
1329 if (!one) {
1330 Tcl_DStringAppendElement(resultPtr, string);
1331 string = NULL;
1332 }
1333 break;
1334 case 'p': /* Name of the node */
1335 string = (entryPtr?GETLABEL(entryPtr):"");
1336 if (!one) {
1337 Tcl_DStringAppendElement(resultPtr, string);
1338 string = NULL;
1339 }
1340 break;
1341 case '#': /* Node identifier */
1342 string = (entryPtr?Blt_Itoa(Blt_TreeNodeId(entryPtr->node)):"-1");
1343 break;
1344 case 'C': /* Column key */
1345 string = (columnPtr?columnPtr->key:"??");
1346 if (!one) {
1347 Tcl_DStringAppendElement(resultPtr, string);
1348 string = NULL;
1349 }
1350 break;
1351 default:
1352 if (*(p + 1) == '\0') {
1353 p--;
1354 }
1355 buf[0] = *p, buf[1] = *(p + 1), buf[2] = '\0';
1356 string = buf;
1357 break;
1358 }
1359 if (string) {
1360 Tcl_DStringAppend(resultPtr, string, -1);
1361 }
1362 p++;
1363 last = p + 1;
1364 }
1365 }
1366 if (p > last) {
1367 *p = '\0';
1368 Tcl_DStringAppend(resultPtr, last, -1);
1369 }
1370 Tcl_DStringFree(&dString);
1371 }
1372
1373 /*
1374 *----------------------------------------------------------------------
1375 *
1376 * SelectEntryApplyProc --
1377 *
1378 * Sets the selection flag for a node. The selection flag is
1379 * set/cleared/toggled based upon the flag set in the treeview
1380 * widget.
1381 *
1382 * Results:
1383 * Always returns TCL_OK.
1384 *
1385 *----------------------------------------------------------------------
1386 */
1387 static int
SelectEntryApplyProc(tvPtr,entryPtr,columnPtr)1388 SelectEntryApplyProc(tvPtr, entryPtr, columnPtr)
1389 TreeView *tvPtr;
1390 TreeViewEntry *entryPtr;
1391 TreeViewColumn *columnPtr;
1392 {
1393 Blt_HashEntry *hPtr;
1394
1395 switch (tvPtr->flags & TV_SELECT_MASK) {
1396 case TV_SELECT_CLEAR:
1397 Blt_TreeViewDeselectEntry(tvPtr, entryPtr, columnPtr);
1398 break;
1399
1400 case TV_SELECT_SET:
1401 Blt_TreeViewSelectEntry(tvPtr, entryPtr, columnPtr);
1402 break;
1403
1404 case TV_SELECT_TOGGLE:
1405 if ((tvPtr->selectMode & SELECT_MODE_CELLMASK) && columnPtr != NULL) {
1406 if (Blt_TreeViewEntryIsSelected(tvPtr, entryPtr, columnPtr)) {
1407 Blt_TreeViewDeselectEntry(tvPtr, entryPtr, columnPtr);
1408 } else {
1409 Blt_TreeViewSelectEntry(tvPtr, entryPtr, columnPtr);
1410 }
1411 } else {
1412 hPtr = Blt_FindHashEntry(&tvPtr->selectTable, (char *)entryPtr);
1413 if (hPtr != NULL) {
1414 Blt_TreeViewDeselectEntry(tvPtr, entryPtr, columnPtr);
1415 } else {
1416 Blt_TreeViewSelectEntry(tvPtr, entryPtr, columnPtr);
1417 }
1418 }
1419 break;
1420 }
1421 return TCL_OK;
1422 }
1423
1424 /*
1425 *----------------------------------------------------------------------
1426 *
1427 * EventuallyInvokeSelectCmd --
1428 *
1429 * Queues a request to execute the -selectcommand code associated
1430 * with the widget at the next idle point. Invoked whenever the
1431 * selection changes.
1432 *
1433 * Results:
1434 * None.
1435 *
1436 * Side effects:
1437 * Tcl code gets executed for some application-specific task.
1438 *
1439 *----------------------------------------------------------------------
1440 */
1441 static void
EventuallyInvokeSelectCmd(tvPtr)1442 EventuallyInvokeSelectCmd(tvPtr)
1443 TreeView *tvPtr;
1444 {
1445 if (!(tvPtr->flags & TV_SELECT_PENDING)) {
1446 tvPtr->flags |= TV_SELECT_PENDING;
1447 Tcl_DoWhenIdle(Blt_TreeViewSelectCmdProc, tvPtr);
1448 }
1449 }
1450
1451 /*
1452 *----------------------------------------------------------------------
1453 *
1454 * Blt_TreeViewPruneSelection --
1455 *
1456 * The root entry being deleted or closed. Deselect any of its
1457 * descendants that are currently selected.
1458 *
1459 * Results:
1460 * None.
1461 *
1462 * Side effects:
1463 * If any of the entry's descendants are deselected the widget
1464 * is redrawn and the a selection command callback is invoked
1465 * (if there's one configured).
1466 *
1467 *----------------------------------------------------------------------
1468 */
1469 void
Blt_TreeViewPruneSelection(tvPtr,rootPtr)1470 Blt_TreeViewPruneSelection(tvPtr, rootPtr)
1471 TreeView *tvPtr;
1472 TreeViewEntry *rootPtr;
1473 {
1474 Blt_ChainLink *linkPtr, *nextPtr;
1475 TreeViewEntry *entryPtr;
1476 int selectionChanged;
1477
1478 /*
1479 * Check if any of the currently selected entries are a descendant
1480 * of of the current root entry. Deselect the entry and indicate
1481 * that the treeview widget needs to be redrawn.
1482 */
1483 selectionChanged = FALSE;
1484 for (linkPtr = Blt_ChainFirstLink(tvPtr->selChainPtr); linkPtr != NULL;
1485 linkPtr = nextPtr) {
1486 nextPtr = Blt_ChainNextLink(linkPtr);
1487 entryPtr = Blt_ChainGetValue(linkPtr);
1488 if (Blt_TreeIsAncestor(rootPtr->node, entryPtr->node)) {
1489 Blt_TreeViewDeselectEntry(tvPtr, entryPtr, NULL);
1490 selectionChanged = TRUE;
1491 }
1492 }
1493 if (selectionChanged) {
1494 Blt_TreeViewEventuallyRedraw(tvPtr);
1495 if (tvPtr->selectCmd != NULL) {
1496 EventuallyInvokeSelectCmd(tvPtr);
1497 }
1498 }
1499 }
1500
1501
1502 /*
1503 * --------------------------------------------------------------
1504 *
1505 * TreeView operations
1506 *
1507 * --------------------------------------------------------------
1508 */
1509
1510 /*ARGSUSED*/
1511 static int
FocusOp(tvPtr,interp,objc,objv)1512 FocusOp(tvPtr, interp, objc, objv)
1513 TreeView *tvPtr;
1514 Tcl_Interp *interp;
1515 int objc;
1516 Tcl_Obj *CONST *objv;
1517 {
1518 if (objc == 3) {
1519 TreeViewEntry *entryPtr;
1520
1521 if (GetEntryFromObj(tvPtr, objv[2], &entryPtr) != TCL_OK) {
1522 return TCL_ERROR;
1523 }
1524 if ((entryPtr != NULL) && (entryPtr != tvPtr->focusPtr)) {
1525 if (entryPtr->flags & ENTRY_HIDDEN) {
1526 /* Doesn't make sense to set focus to a node you can't see. */
1527 MapAncestors(tvPtr, entryPtr);
1528 }
1529 /* Changing focus can only affect the visible entries. The
1530 * entry layout stays the same. */
1531 if (tvPtr->focusPtr != NULL) {
1532 tvPtr->focusPtr->flags |= ENTRY_REDRAW;
1533 }
1534 entryPtr->flags |= ENTRY_REDRAW;
1535 tvPtr->flags |= TV_SCROLL;
1536 tvPtr->focusPtr = entryPtr;
1537 }
1538 Blt_TreeViewEventuallyRedraw(tvPtr);
1539 }
1540 Blt_SetFocusItem(tvPtr->bindTable, tvPtr->focusPtr, ITEM_ENTRY);
1541 if (tvPtr->focusPtr != NULL) {
1542 Tcl_SetObjResult(interp, NodeToObj(tvPtr->focusPtr->node));
1543 }
1544 return TCL_OK;
1545 }
1546
1547 /*
1548 * .t entry isset entry col
1549 *
1550 */
1551 /*ARGSUSED*/
1552 static int
EntryIssetOp(tvPtr,interp,objc,objv)1553 EntryIssetOp(tvPtr, interp, objc, objv)
1554 TreeView *tvPtr;
1555 Tcl_Interp *interp;
1556 int objc;
1557 Tcl_Obj *CONST *objv;
1558 {
1559 TreeViewEntry *entryPtr;
1560 TreeViewColumn *columnPtr;
1561 Tcl_Obj *objPtr;
1562 int rc;
1563
1564 if (Blt_TreeViewGetColumn(interp, tvPtr, objv[4], &columnPtr)
1565 != TCL_OK || columnPtr == NULL) {
1566 return TCL_ERROR;
1567 }
1568 if (columnPtr == &tvPtr->treeColumn) {
1569 Tcl_AppendResult(interp, "can not use tree column", 0);
1570 return TCL_ERROR;
1571 }
1572 if (Blt_TreeViewGetEntry(tvPtr, objv[3], &entryPtr) != TCL_OK ||
1573 entryPtr == NULL) {
1574 return TCL_ERROR;
1575 }
1576
1577 rc = (Blt_TreeGetValueByKey(tvPtr->interp, tvPtr->tree, entryPtr->node,
1578 columnPtr->key, &objPtr) == TCL_OK);
1579 Tcl_SetObjResult(interp, Tcl_NewIntObj(rc));
1580 return TCL_OK;
1581 }
1582
1583
1584 /*
1585 * .t entry isvisible entry
1586 *
1587 */
1588 /*ARGSUSED*/
1589 static int
EntryIsvisibleOp(tvPtr,interp,objc,objv)1590 EntryIsvisibleOp(tvPtr, interp, objc, objv)
1591 TreeView *tvPtr;
1592 Tcl_Interp *interp;
1593 int objc;
1594 Tcl_Obj *CONST *objv;
1595 {
1596 TreeViewEntry *entryPtr;
1597 int rc;
1598
1599 if (Blt_TreeViewGetEntry(tvPtr, objv[3], &entryPtr) != TCL_OK ||
1600 entryPtr == NULL) {
1601 return TCL_ERROR;
1602 }
1603 rc = Blt_TreeViewEntryIsHidden(entryPtr);
1604 Tcl_SetObjResult(interp, Tcl_NewIntObj(!rc));
1605 return TCL_OK;
1606 }
1607
1608 /*
1609 * .t entry ismapped entry
1610 *
1611 */
1612 /*ARGSUSED*/
1613 static int
EntryIsmappedOp(tvPtr,interp,objc,objv)1614 EntryIsmappedOp(tvPtr, interp, objc, objv)
1615 TreeView *tvPtr;
1616 Tcl_Interp *interp;
1617 int objc;
1618 Tcl_Obj *CONST *objv;
1619 {
1620 TreeViewEntry *entryPtr;
1621 int rc;
1622
1623 if (Blt_TreeViewGetEntry(tvPtr, objv[3], &entryPtr) != TCL_OK ||
1624 entryPtr == NULL) {
1625 return TCL_ERROR;
1626 }
1627 rc = Blt_TreeViewEntryIsMapped(entryPtr);
1628 Tcl_SetObjResult(interp, Tcl_NewIntObj(rc));
1629 return TCL_OK;
1630 }
1631
1632 /*
1633 * .t entry unset ENTRY KEY
1634 *
1635 */
1636 /*ARGSUSED*/
1637 static int
EntryUnsetOp(tvPtr,interp,objc,objv)1638 EntryUnsetOp(tvPtr, interp, objc, objv)
1639 TreeView *tvPtr;
1640 Tcl_Interp *interp;
1641 int objc;
1642 Tcl_Obj *CONST *objv;
1643 {
1644 TreeViewEntry *entryPtr;
1645 TreeViewColumn *columnPtr;
1646 char *left;
1647
1648 if (GetEntryFromObj(tvPtr, objv[3], &entryPtr) != TCL_OK) {
1649 return TCL_ERROR;
1650 }
1651 if (Blt_TreeViewGetColumnKey(interp, tvPtr, objv[4], &columnPtr, &left)
1652 != TCL_OK || columnPtr == NULL) {
1653 return TCL_ERROR;
1654 }
1655
1656 if (left == NULL) {
1657 if (Blt_TreeUnsetValueByKey(tvPtr->interp, tvPtr->tree, entryPtr->node,
1658 columnPtr->key) != TCL_OK) {
1659 Tcl_ResetResult(interp);
1660 return TCL_OK;
1661 }
1662 Blt_TreeViewDeleteValue(entryPtr, columnPtr->key);
1663 } else {
1664 if (Blt_TreeUnsetValue(tvPtr->interp, tvPtr->tree, entryPtr->node,
1665 Tcl_GetString(objv[4])) != TCL_OK) {
1666 Tcl_ResetResult(interp);
1667 return TCL_OK;
1668 }
1669 Blt_TreeViewAddValue(entryPtr, columnPtr);
1670 }
1671 tvPtr->flags |= (TV_LAYOUT | TV_DIRTY | TV_RESORT);
1672 entryPtr->flags |= ENTRY_DIRTY;
1673 Blt_TreeViewEventuallyRedraw(tvPtr);
1674 return TCL_OK;
1675 }
1676
1677 /*
1678 * .t entry set ENTRY KEY ?VALUE?
1679 *
1680 */
1681 /*ARGSUSED*/
1682 static int
EntrySetOp(tvPtr,interp,objc,objv)1683 EntrySetOp(tvPtr, interp, objc, objv)
1684 TreeView *tvPtr;
1685 Tcl_Interp *interp;
1686 int objc;
1687 Tcl_Obj *CONST *objv;
1688 {
1689 TreeViewEntry *entryPtr;
1690 TreeViewColumn *columnPtr;
1691 int n, result;
1692 Blt_TreeNode node;
1693 char *left, *string;
1694
1695 if (GetEntryFromObj(tvPtr, objv[3], &entryPtr) != TCL_OK) {
1696 return TCL_ERROR;
1697 }
1698 node = entryPtr->node;
1699 string = Tcl_GetString(objv[4]);
1700 if (Blt_TreeViewGetColumnKey(interp, tvPtr, objv[4], &columnPtr, &left)
1701 != TCL_OK || columnPtr == NULL) {
1702 return TCL_ERROR;
1703 }
1704
1705 if (objc == 5) {
1706 Tcl_Obj *objPtr;
1707 if (Blt_TreeGetValue(tvPtr->interp, tvPtr->tree, entryPtr->node,
1708 string /*columnPtr->key*/, &objPtr) != TCL_OK) {
1709 Tcl_ResetResult(interp);
1710 return TCL_OK;
1711 }
1712 Tcl_SetObjResult(interp, objPtr);
1713 return TCL_OK;
1714 }
1715
1716 if (objc % 2) {
1717 Tcl_AppendResult( interp, "odd number of arguments", 0);
1718 return TCL_ERROR;
1719 }
1720
1721 Tcl_Preserve(entryPtr);
1722 result = TCL_OK;
1723 if (objc == 6) {
1724 result = Blt_TreeSetValue(tvPtr->interp, tvPtr->tree, entryPtr->node,
1725 string /*columnPtr->key*/, objv[5]);
1726 if ((entryPtr->flags & ENTRY_DELETED) || (tvPtr->flags & TV_DELETED)) {
1727 Tcl_Release(entryPtr);
1728 return TCL_ERROR;
1729 }
1730 if (result != TCL_OK) {
1731 Tcl_Release(entryPtr);
1732 return TCL_ERROR;
1733 }
1734 Blt_TreeViewAddValue(entryPtr, columnPtr);
1735 Tcl_SetObjResult(interp, objv[5]);
1736 Blt_TreeViewEventuallyRedraw(tvPtr);
1737 return TCL_OK;
1738 }
1739
1740 n = 4;
1741 while (n<objc) {
1742 string = Tcl_GetString(objv[n]);
1743 result = Blt_TreeSetValue(tvPtr->interp, tvPtr->tree, entryPtr->node,
1744 string /*columnPtr->key*/, objv[n+1]);
1745 if ((entryPtr->flags & ENTRY_DELETED) || (tvPtr->flags & TV_DELETED)) {
1746 Tcl_Release(entryPtr);
1747 return TCL_ERROR;
1748 }
1749 if (result != TCL_OK) {
1750 break;
1751 }
1752 Blt_TreeViewAddValue(entryPtr, columnPtr);
1753 n += 2;
1754 if (n>=objc) break;
1755 if (Blt_TreeViewGetColumnKey(interp, tvPtr, objv[n], &columnPtr, &left)
1756 != TCL_OK || columnPtr == NULL) {
1757 result = TCL_ERROR;
1758 break;
1759 }
1760 }
1761 Tcl_Release(entryPtr);
1762 Blt_TreeViewEventuallyRedraw(tvPtr);
1763 return result;
1764 }
1765
1766 /*
1767 * .t entry incr ENTRY KEY ?AMOUNT?
1768 *
1769 */
1770 /*ARGSUSED*/
1771 static int
EntryIncrOp(tvPtr,interp,objc,objv)1772 EntryIncrOp(tvPtr, interp, objc, objv)
1773 TreeView *tvPtr;
1774 Tcl_Interp *interp;
1775 int objc;
1776 Tcl_Obj *CONST *objv;
1777 {
1778 TreeViewEntry *entryPtr;
1779 TreeViewColumn *columnPtr;
1780 Blt_TreeNode node;
1781 double dVal, dIncr = 1.0;
1782 int iVal, iIncr = 1, isInt = 0;
1783 Tcl_Obj *objPtr, *valueObjPtr;
1784 char *left, *string;
1785
1786 if (GetEntryFromObj(tvPtr, objv[3], &entryPtr) != TCL_OK) {
1787 return TCL_ERROR;
1788 }
1789 node = entryPtr->node;
1790 string = Tcl_GetString(objv[4]);
1791 if (Blt_TreeViewGetColumnKey(interp, tvPtr, objv[4], &columnPtr, &left)
1792 != TCL_OK || columnPtr == NULL) {
1793 return TCL_ERROR;
1794 }
1795
1796 if (Blt_TreeGetValue(tvPtr->interp, tvPtr->tree, entryPtr->node,
1797 string /* columnPtr->key */, &valueObjPtr) != TCL_OK) {
1798 return TCL_ERROR;
1799 }
1800
1801 if (Tcl_GetIntFromObj(NULL, valueObjPtr, &iVal) == TCL_OK &&
1802 (objc <= 5 || Tcl_GetIntFromObj(NULL, objv[5], &iIncr) == TCL_OK)) {
1803 isInt = 1;
1804 } else {
1805 if (objc > 5 && Tcl_GetDoubleFromObj(interp, objv[5], &dIncr) != TCL_OK) {
1806 return TCL_ERROR;
1807 }
1808 if (Tcl_GetDoubleFromObj(interp, valueObjPtr, &dVal) != TCL_OK) {
1809 return TCL_ERROR;
1810 }
1811 }
1812 if (isInt) {
1813 iVal += iIncr;
1814 objPtr = Tcl_NewIntObj(iVal);
1815 } else {
1816 dVal += dIncr;
1817 objPtr = Tcl_NewDoubleObj(dVal);
1818 }
1819
1820 if (Blt_TreeSetValue(tvPtr->interp, tvPtr->tree, entryPtr->node,
1821 string /*columnPtr->key*/, objPtr) != TCL_OK) {
1822 return TCL_ERROR;
1823 }
1824 Blt_TreeViewAddValue(entryPtr, columnPtr);
1825 Tcl_SetObjResult(interp, objPtr);
1826 Blt_TreeViewEventuallyRedraw(tvPtr);
1827 return TCL_OK;
1828 }
1829
1830
1831 /*
1832 * .t entry get ENTRY ?KEY? ?DEFAULT?
1833 *
1834 */
1835 /*ARGSUSED*/
1836 static int
EntryGetOp(tvPtr,interp,objc,objv)1837 EntryGetOp(tvPtr, interp, objc, objv)
1838 TreeView *tvPtr;
1839 Tcl_Interp *interp;
1840 int objc;
1841 Tcl_Obj *CONST *objv;
1842 {
1843 TreeViewEntry *entryPtr;
1844 Blt_TreeNode node;
1845 char *key;
1846 Tcl_Obj *objPtr;
1847
1848 if (GetEntryFromObj(tvPtr, objv[3], &entryPtr) != TCL_OK) {
1849 return TCL_ERROR;
1850 }
1851 Tcl_Preserve(entryPtr);
1852 if (objc<=4) {
1853 Blt_ChainLink *linkPtr;
1854 TreeViewColumn *columnPtr;
1855 Tcl_Obj *listObjPtr;
1856
1857 listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **)NULL);
1858 for (linkPtr = Blt_ChainFirstLink(tvPtr->colChainPtr); linkPtr != NULL;
1859 linkPtr = Blt_ChainNextLink(linkPtr)) {
1860 columnPtr = Blt_ChainGetValue(linkPtr);
1861 if (columnPtr->hidden) {
1862 continue;
1863 }
1864 if (Blt_TreeGetValue(tvPtr->interp, tvPtr->tree, entryPtr->node,
1865 columnPtr->key, &objPtr) != TCL_OK) {
1866 objPtr = Tcl_NewStringObj("", -1);
1867 }
1868 if ((entryPtr->flags & ENTRY_DELETED) || (tvPtr->flags & TV_DELETED)) {
1869 Tcl_Release(entryPtr);
1870 Tcl_DecrRefCount(listObjPtr);
1871 return TCL_ERROR;
1872 }
1873 Tcl_ListObjAppendElement(interp, listObjPtr, objPtr);
1874 }
1875 Tcl_SetObjResult(interp, listObjPtr);
1876 Tcl_Release(entryPtr);
1877 return TCL_OK;
1878 }
1879 key = Tcl_GetString(objv[4]);
1880 node = entryPtr->node;
1881 Tcl_Release(entryPtr);
1882 if (Blt_TreeGetValue(tvPtr->interp, tvPtr->tree, entryPtr->node,
1883 key, &objPtr) != TCL_OK) {
1884 if (objc != 6) {
1885 return TCL_ERROR;
1886 }
1887 Tcl_SetObjResult(interp, objv[5]);
1888 return TCL_OK;
1889 }
1890 Tcl_SetObjResult(interp, objPtr);
1891 return TCL_OK;
1892 }
1893
1894 /*
1895 * .t entry value ENTRY ?KEY?
1896 *
1897 */
1898 /*ARGSUSED*/
1899 static int
EntryValueOp(tvPtr,interp,objc,objv)1900 EntryValueOp(tvPtr, interp, objc, objv)
1901 TreeView *tvPtr;
1902 Tcl_Interp *interp;
1903 int objc;
1904 Tcl_Obj *CONST *objv;
1905 {
1906 TreeViewEntry *entryPtr;
1907 TreeViewColumn *columnPtr = NULL;
1908 TreeViewValue *valuePtr;
1909 Blt_ChainLink *linkPtr;
1910 Tcl_Obj *objPtr, *listObjPtr;
1911
1912 if (GetEntryFromObj(tvPtr, objv[3], &entryPtr) != TCL_OK) {
1913 return TCL_ERROR;
1914 }
1915 if (objc>4 && Blt_TreeViewGetColumn(interp, tvPtr, objv[4], &columnPtr)
1916 != TCL_OK) {
1917 return TCL_ERROR;
1918 }
1919
1920 Tcl_Preserve(entryPtr);
1921 if (columnPtr != NULL) {
1922 valuePtr = Blt_TreeViewFindValue(entryPtr, columnPtr);
1923 if ((entryPtr->flags & ENTRY_DELETED) || (tvPtr->flags & TV_DELETED)) {
1924 Tcl_Release(entryPtr);
1925 return TCL_ERROR;
1926 }
1927 Tcl_Release(entryPtr);
1928 if (valuePtr && valuePtr->textPtr) {
1929 Tcl_DString dStr;
1930 Tcl_DStringInit(&dStr);
1931 Blt_TextLayoutValue( valuePtr->textPtr, &dStr);
1932 objPtr = Tcl_NewStringObj( Tcl_DStringValue(&dStr), -1);
1933 Tcl_DStringFree(&dStr);
1934 Tcl_SetObjResult(tvPtr->interp, objPtr);
1935 return TCL_OK;
1936 }
1937
1938 if (Blt_TreeGetValueByKey(tvPtr->interp, tvPtr->tree, entryPtr->node,
1939 columnPtr->key, &objPtr) != TCL_OK) {
1940 Tcl_ResetResult(interp);
1941 } else {
1942 Tcl_SetObjResult(interp, objPtr);
1943 }
1944 return TCL_OK;
1945 }
1946
1947 listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **)NULL);
1948 for(linkPtr = Blt_ChainFirstLink(tvPtr->colChainPtr); linkPtr != NULL;
1949 linkPtr = Blt_ChainNextLink(linkPtr)) {
1950 columnPtr = Blt_ChainGetValue(linkPtr);
1951 if (columnPtr->hidden) {
1952 continue;
1953 }
1954 valuePtr = Blt_TreeViewFindValue(entryPtr, columnPtr);
1955 if ((entryPtr->flags & ENTRY_DELETED) || (tvPtr->flags & TV_DELETED)) {
1956 Tcl_Release(entryPtr);
1957 Tcl_DecrRefCount(listObjPtr);
1958 return TCL_ERROR;
1959 }
1960 if (valuePtr && valuePtr->textPtr) {
1961 Tcl_DString dStr;
1962 Tcl_DStringInit(&dStr);
1963 Blt_TextLayoutValue( valuePtr->textPtr, &dStr);
1964 objPtr = Tcl_NewStringObj( Tcl_DStringValue(&dStr), -1);
1965 Tcl_DStringFree(&dStr);
1966 Tcl_ListObjAppendElement(interp, listObjPtr, objPtr);
1967 continue;
1968 }
1969 if ((entryPtr->flags & ENTRY_DELETED) || (tvPtr->flags & TV_DELETED)) {
1970 Tcl_Release(entryPtr);
1971 Tcl_DecrRefCount(listObjPtr);
1972 return TCL_ERROR;
1973 }
1974 if (Blt_TreeGetValueByKey(tvPtr->interp, tvPtr->tree, entryPtr->node,
1975 columnPtr->key, &objPtr) != TCL_OK) {
1976 objPtr = Tcl_NewStringObj("",0);
1977 }
1978 Tcl_ListObjAppendElement(interp, listObjPtr, objPtr);
1979 }
1980 Tcl_Release(entryPtr);
1981 Tcl_SetObjResult(interp, listObjPtr);
1982
1983 return TCL_OK;
1984 }
1985
1986 /*
1987 *----------------------------------------------------------------------
1988 *
1989 * BboxOp --
1990 *
1991 *----------------------------------------------------------------------
1992 */
1993 /*ARGSUSED*/
1994 static int
BboxOp(tvPtr,interp,objc,objv)1995 BboxOp(tvPtr, interp, objc, objv)
1996 TreeView *tvPtr;
1997 Tcl_Interp *interp;
1998 int objc; /* Not used. */
1999 Tcl_Obj *CONST *objv;
2000 {
2001 register int i;
2002 TreeViewEntry *entryPtr;
2003 int height, yBot;
2004 int left, top, right, bottom;
2005 int screen;
2006 int lWidth;
2007 char *string;
2008
2009 if (tvPtr->flags & TV_LAYOUT) {
2010 /*
2011 * The layout is dirty. Recompute it now, before we use the
2012 * world dimensions. But remember, the "bbox" operation isn't
2013 * valid for hidden entries (since they're not visible, they
2014 * don't have world coordinates).
2015 */
2016 Blt_TreeViewComputeLayout(tvPtr);
2017 }
2018 left = tvPtr->worldWidth;
2019 top = tvPtr->worldHeight;
2020 right = bottom = 0;
2021
2022 screen = FALSE;
2023 string = Tcl_GetString(objv[2]);
2024 if ((string[0] == '-') && (strcmp(string, "-screen") == 0)) {
2025 screen = TRUE;
2026 objc--, objv++;
2027 }
2028 for (i = 2; i < objc; i++) {
2029 string = Tcl_GetString(objv[i]);
2030 if ((string[0] == 'a') && (strcmp(string, "all") == 0)) {
2031 left = top = 0;
2032 right = tvPtr->worldWidth;
2033 bottom = tvPtr->worldHeight;
2034 break;
2035 }
2036 if (GetEntryFromObj(tvPtr, objv[i], &entryPtr) != TCL_OK) {
2037 return TCL_ERROR;
2038 }
2039 if (entryPtr == NULL) {
2040 continue;
2041 }
2042 if (entryPtr->flags & ENTRY_HIDDEN) {
2043 continue;
2044 }
2045 yBot = entryPtr->worldY + entryPtr->height;
2046 height = VPORTHEIGHT(tvPtr);
2047 if ((yBot <= tvPtr->yOffset) &&
2048 (entryPtr->worldY >= (tvPtr->yOffset + height))) {
2049 continue;
2050 }
2051 if (bottom < yBot) {
2052 bottom = yBot;
2053 }
2054 if (top > entryPtr->worldY) {
2055 top = entryPtr->worldY;
2056 }
2057 lWidth = ICONWIDTH(DEPTH(tvPtr, entryPtr->node));
2058 if (right < (entryPtr->worldX + entryPtr->width + lWidth)) {
2059 right = (entryPtr->worldX + entryPtr->width + lWidth);
2060 }
2061 if (left > entryPtr->worldX) {
2062 left = entryPtr->worldX;
2063 }
2064 }
2065
2066 if (screen) {
2067 #if 0
2068 width = VPORTWIDTH(tvPtr);
2069 height = VPORTHEIGHT(tvPtr);
2070 /*
2071 * Do a min-max text for the intersection of the viewport and
2072 * the computed bounding box. If there is no intersection, return
2073 * the empty string.
2074 */
2075 if (((right < tvPtr->xOffset) &&
2076 (left >= (tvPtr->xOffset + width))) ||
2077 ((bottom < tvPtr->yOffset) &&
2078 (top >= (tvPtr->yOffset + height)))) {
2079 return TCL_OK;
2080 }
2081 /* Otherwise clip the coordinates at the view port boundaries. */
2082 if (left < tvPtr->xOffset) {
2083 left = tvPtr->xOffset;
2084 } else if (right > (tvPtr->xOffset + width)) {
2085 right = tvPtr->xOffset + width;
2086 }
2087 if (top < tvPtr->yOffset) {
2088 top = tvPtr->yOffset;
2089 } else if (bottom > (tvPtr->yOffset + height)) {
2090 bottom = tvPtr->yOffset + height;
2091 }
2092 #endif
2093 left = SCREENX(tvPtr, left), top = SCREENY(tvPtr, top);
2094 right = SCREENX(tvPtr, right), bottom = SCREENY(tvPtr, bottom);
2095 }
2096 if ((left <= right) && (top <= bottom)) {
2097 Tcl_Obj *listObjPtr;
2098
2099 listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **)NULL);
2100 Tcl_ListObjAppendElement(interp, listObjPtr, Tcl_NewIntObj(left));
2101 Tcl_ListObjAppendElement(interp, listObjPtr, Tcl_NewIntObj(top));
2102 Tcl_ListObjAppendElement(interp, listObjPtr,
2103 Tcl_NewIntObj(right - left));
2104 Tcl_ListObjAppendElement(interp, listObjPtr,
2105 Tcl_NewIntObj(bottom - top));
2106 Tcl_SetObjResult(interp, listObjPtr);
2107 }
2108 return TCL_OK;
2109 }
2110
2111 static void
DrawButton(tvPtr,entryPtr)2112 DrawButton(tvPtr, entryPtr)
2113 TreeView *tvPtr;
2114 TreeViewEntry *entryPtr;
2115 {
2116 Drawable drawable;
2117 int sx, sy, dx, dy;
2118 int width, height;
2119 int left, right, top, bottom;
2120
2121 dx = SCREENX(tvPtr, entryPtr->worldX) + entryPtr->buttonX;
2122 dy = SCREENY(tvPtr, entryPtr->worldY) + entryPtr->buttonY;
2123 width = tvPtr->button.width;
2124 height = tvPtr->button.height;
2125
2126 top = tvPtr->titleHeight + tvPtr->insetY;
2127 bottom = Tk_Height(tvPtr->tkwin) - tvPtr->insetY;
2128 left = tvPtr->insetX;
2129 right = Tk_Width(tvPtr->tkwin) - tvPtr->insetX;
2130
2131 if (((dx + width) < left) || (dx > right) ||
2132 ((dy + height) < top) || (dy > bottom)) {
2133 return; /* Value is clipped. */
2134 }
2135 drawable = Tk_GetPixmap(tvPtr->display, Tk_WindowId(tvPtr->tkwin),
2136 width, height, Tk_Depth(tvPtr->tkwin));
2137 /* Draw the background of the value. */
2138 Blt_TreeViewDrawButton(tvPtr, entryPtr, drawable, 0, 0);
2139
2140 /* Clip the drawable if necessary */
2141 sx = sy = 0;
2142 if (dx < left) {
2143 width -= left - dx;
2144 sx += left - dx;
2145 dx = left;
2146 }
2147 if ((dx + width) >= right) {
2148 width -= (dx + width) - right;
2149 }
2150 if (dy < top) {
2151 height -= top - dy;
2152 sy += top - dy;
2153 dy = top;
2154 }
2155 if ((dy + height) >= bottom) {
2156 height -= (dy + height) - bottom;
2157 }
2158 XCopyArea(tvPtr->display, drawable, Tk_WindowId(tvPtr->tkwin),
2159 tvPtr->lineGC, sx, sy, width, height, dx, dy);
2160 Tk_FreePixmap(tvPtr->display, drawable);
2161 }
2162
2163 /*
2164 *----------------------------------------------------------------------
2165 *
2166 * ButtonActivateOp --
2167 *
2168 * Selects the button to appear active.
2169 *
2170 *----------------------------------------------------------------------
2171 */
2172 /*ARGSUSED*/
2173 static int
ButtonActivateOp(tvPtr,interp,objc,objv)2174 ButtonActivateOp(tvPtr, interp, objc, objv)
2175 TreeView *tvPtr;
2176 Tcl_Interp *interp;
2177 int objc; /* Not used. */
2178 Tcl_Obj *CONST *objv;
2179 {
2180 TreeViewEntry *oldPtr, *newPtr;
2181 char *string;
2182
2183 string = Tcl_GetString(objv[3]);
2184 if (string[0] == '\0') {
2185 newPtr = NULL;
2186 } else if (GetEntryFromObj(tvPtr, objv[3], &newPtr) != TCL_OK) {
2187 return TCL_ERROR;
2188 }
2189 if (tvPtr->treeColumn.hidden) {
2190 return TCL_OK;
2191 }
2192 if (tvPtr->button.reqSize==0) {
2193 return TCL_OK;
2194 }
2195 if ((newPtr != NULL) && !(newPtr->flags & ENTRY_HAS_BUTTON)) {
2196 newPtr = NULL;
2197 }
2198 oldPtr = tvPtr->activeButtonPtr;
2199 tvPtr->activeButtonPtr = newPtr;
2200 if (!(tvPtr->flags & TV_REDRAW) && (newPtr != oldPtr)) {
2201 if ((oldPtr != NULL) && (oldPtr != tvPtr->rootPtr)) {
2202 DrawButton(tvPtr, oldPtr);
2203 }
2204 if ((newPtr != NULL) && (newPtr != tvPtr->rootPtr)) {
2205 DrawButton(tvPtr, newPtr);
2206 }
2207 }
2208 return TCL_OK;
2209 }
2210
2211 /*
2212 *----------------------------------------------------------------------
2213 *
2214 * ButtonBindOp --
2215 *
2216 * .t bind tag sequence command
2217 *
2218 *----------------------------------------------------------------------
2219 */
2220 /*ARGSUSED*/
2221 static int
ButtonBindOp(tvPtr,interp,objc,objv)2222 ButtonBindOp(tvPtr, interp, objc, objv)
2223 TreeView *tvPtr;
2224 Tcl_Interp *interp;
2225 int objc; /* Not used. */
2226 Tcl_Obj *CONST *objv;
2227 {
2228 ClientData object;
2229 char *string;
2230
2231 string = Tcl_GetString(objv[3]);
2232 /* Assume that this is a binding tag. */
2233 object = Blt_TreeViewButtonTag(tvPtr, string);
2234 if (object == NULL) {
2235 return TCL_OK;
2236 }
2237 return Blt_ConfigureBindingsFromObj(interp, tvPtr->bindTable, object,
2238 objc - 4, objv + 4);
2239 }
2240
2241 /*
2242 *----------------------------------------------------------------------
2243 *
2244 * ButtonCgetOp --
2245 *
2246 *----------------------------------------------------------------------
2247 */
2248 /*ARGSUSED*/
2249 static int
ButtonCgetOp(tvPtr,interp,objc,objv)2250 ButtonCgetOp(tvPtr, interp, objc, objv)
2251 TreeView *tvPtr;
2252 Tcl_Interp *interp;
2253 int objc; /* Not used. */
2254 Tcl_Obj *CONST *objv;
2255 {
2256 Blt_TreeViewOptsInit(tvPtr);
2257 return Blt_ConfigureValueFromObj(interp, tvPtr->tkwin,
2258 bltTreeViewButtonSpecs, (char *)tvPtr, objv[3], 0);
2259 }
2260
2261 /*
2262 *----------------------------------------------------------------------
2263 *
2264 * ButtonConfigureOp --
2265 *
2266 * This procedure is called to process a list of configuration
2267 * options database, in order to reconfigure the one of more
2268 * entries in the widget.
2269 *
2270 * .h button configure option value
2271 *
2272 * Results:
2273 * A standard Tcl result. If TCL_ERROR is returned, then
2274 * interp->result contains an error message.
2275 *
2276 * Side effects:
2277 * Configuration information, such as text string, colors, font,
2278 * etc. get set for tvPtr; old resources get freed, if there
2279 * were any. The hypertext is redisplayed.
2280 *
2281 *----------------------------------------------------------------------
2282 */
2283 static int
ButtonConfigureOp(tvPtr,interp,objc,objv)2284 ButtonConfigureOp(tvPtr, interp, objc, objv)
2285 TreeView *tvPtr;
2286 Tcl_Interp *interp;
2287 int objc;
2288 Tcl_Obj *CONST *objv;
2289 {
2290 Blt_TreeViewOptsInit(tvPtr);
2291 if (objc == 3) {
2292 return Blt_ConfigureInfoFromObj(interp, tvPtr->tkwin,
2293 bltTreeViewButtonSpecs, (char *)tvPtr, (Tcl_Obj *)NULL, 0);
2294 } else if (objc == 4) {
2295 return Blt_ConfigureInfoFromObj(interp, tvPtr->tkwin,
2296 bltTreeViewButtonSpecs, (char *)tvPtr, objv[3], 0);
2297 }
2298 if (Blt_ConfigureWidgetFromObj(tvPtr->interp, tvPtr->tkwin,
2299 bltTreeViewButtonSpecs, objc - 3, objv + 3, (char *)tvPtr,
2300 BLT_CONFIG_OBJV_ONLY, NULL) != TCL_OK) {
2301 return TCL_ERROR;
2302 }
2303 if (tvPtr->tile != NULL) {
2304 Blt_SetTileChangedProc(tvPtr->tile, Blt_TreeViewTileChangedProc, tvPtr);
2305 }
2306 if (tvPtr->selectTile != NULL) {
2307 Blt_SetTileChangedProc(tvPtr->selectTile, Blt_TreeViewTileChangedProc, tvPtr);
2308 }
2309
2310 Blt_TreeViewConfigureButtons(tvPtr);
2311 Blt_TreeViewEventuallyRedraw(tvPtr);
2312 return TCL_OK;
2313 }
2314
2315 /*
2316 *----------------------------------------------------------------------
2317 *
2318 * ButtonOp --
2319 *
2320 * This procedure handles button operations.
2321 *
2322 * Results:
2323 * A standard Tcl result.
2324 *
2325 *----------------------------------------------------------------------
2326 */
2327 static Blt_OpSpec buttonOps[] =
2328 {
2329 {"activate", 1, (Blt_Op)ButtonActivateOp, 4, 4, "tagOrId",},
2330 {"bind", 1, (Blt_Op)ButtonBindOp, 4, 6, "tagName ?sequence command?",},
2331 {"cget", 2, (Blt_Op)ButtonCgetOp, 4, 4, "option",},
2332 {"configure", 2, (Blt_Op)ButtonConfigureOp, 3, 0, "?option value?...",},
2333 };
2334
2335 static int nButtonOps = sizeof(buttonOps) / sizeof(Blt_OpSpec);
2336
2337 static int
ButtonOp(tvPtr,interp,objc,objv)2338 ButtonOp(tvPtr, interp, objc, objv)
2339 TreeView *tvPtr;
2340 Tcl_Interp *interp;
2341 int objc;
2342 Tcl_Obj *CONST *objv;
2343 {
2344 Blt_Op proc;
2345 int result;
2346
2347 proc = Blt_GetOpFromObj(interp, nButtonOps, buttonOps, BLT_OP_ARG2, objc,
2348 objv, 0);
2349 if (proc == NULL) {
2350 return TCL_ERROR;
2351 }
2352 result = (*proc) (tvPtr, interp, objc, objv);
2353 return result;
2354 }
2355
2356 /*
2357 *----------------------------------------------------------------------
2358 *
2359 * CgetOp --
2360 *
2361 *----------------------------------------------------------------------
2362 */
2363 /*ARGSUSED*/
2364 static int
CgetOp(tvPtr,interp,objc,objv)2365 CgetOp(tvPtr, interp, objc, objv)
2366 TreeView *tvPtr;
2367 Tcl_Interp *interp;
2368 int objc; /* Not used. */
2369 Tcl_Obj *CONST *objv;
2370 {
2371 Blt_TreeViewOptsInit(tvPtr);
2372 return Blt_ConfigureValueFromObj(interp, tvPtr->tkwin, bltTreeViewSpecs,
2373 (char *)tvPtr, objv[2], 0);
2374 }
2375
2376 static int
CloseTreeEntry(TreeView * tvPtr,TreeViewEntry * entryPtr)2377 CloseTreeEntry(TreeView *tvPtr, TreeViewEntry *entryPtr) {
2378 if (Blt_TreeViewFirstChild(entryPtr, 0) != NULL &&
2379 entryPtr != tvPtr->rootPtr) {
2380 return Blt_TreeViewCloseEntry(tvPtr, entryPtr);
2381 }
2382 return TCL_OK;
2383 }
2384
2385
2386 /*ARGSUSED*/
2387 static int
CloseOp(tvPtr,interp,objc,objv)2388 CloseOp(tvPtr, interp, objc, objv)
2389 TreeView *tvPtr;
2390 Tcl_Interp *interp; /* Not used. */
2391 int objc;
2392 Tcl_Obj *CONST *objv;
2393 {
2394 TreeViewEntry *entryPtr;
2395 TreeViewTagInfo info = {0};
2396 int recurse, trees, result;
2397 register int i;
2398
2399 recurse = FALSE;
2400 trees = FALSE;
2401
2402 while (objc > 2) {
2403 char *string;
2404 int length;
2405
2406 string = Tcl_GetStringFromObj(objv[2], &length);
2407 if ((string[0] == '-') && (length > 1) &&
2408 (strncmp(string, "-recurse", length) == 0)) {
2409 objv++, objc--;
2410 recurse = TRUE;
2411 } else if ((string[0] == '-') && (length > 1) &&
2412 (strncmp(string, "-trees", length) == 0)) {
2413 objv++, objc--;
2414 trees = TRUE;
2415 } else break;
2416 }
2417 for (i = 2; i < objc; i++) {
2418 if (Blt_TreeViewFindTaggedEntries(tvPtr, objv[i], &info) != TCL_OK) {
2419 return TCL_ERROR;
2420 }
2421 for (entryPtr = Blt_TreeViewFirstTaggedEntry(&info); entryPtr != NULL;
2422 entryPtr = Blt_TreeViewNextTaggedEntry(&info)) {
2423 /*
2424 * Clear the selections for any entries that may have become
2425 * hidden by closing the node.
2426 */
2427 Blt_TreeViewPruneSelection(tvPtr, entryPtr);
2428
2429 /*
2430 * -----------------------------------------------------------
2431 *
2432 * Check if either the "focus" entry or selection anchor
2433 * is in this hierarchy. Must move it or disable it before
2434 * we close the node. Otherwise it may be deleted by a Tcl
2435 * "close" script, and we'll be left pointing to a bogus
2436 * memory location.
2437 *
2438 * -----------------------------------------------------------
2439 */
2440 if ((tvPtr->focusPtr != NULL) &&
2441 (Blt_TreeIsAncestor(entryPtr->node, tvPtr->focusPtr->node))) {
2442 tvPtr->focusPtr = entryPtr;
2443 Blt_SetFocusItem(tvPtr->bindTable, tvPtr->focusPtr, ITEM_ENTRY);
2444 }
2445 if ((tvPtr->selAnchorPtr != NULL) &&
2446 (Blt_TreeIsAncestor(entryPtr->node,
2447 tvPtr->selAnchorPtr->node))) {
2448 tvPtr->selMarkPtr = tvPtr->selAnchorPtr = NULL;
2449 }
2450 if ((tvPtr->activePtr != NULL) &&
2451 (Blt_TreeIsAncestor(entryPtr->node, tvPtr->activePtr->node))) {
2452 tvPtr->activePtr = entryPtr;
2453 }
2454 if (trees) {
2455 result = Blt_TreeViewApply(tvPtr, entryPtr,
2456 CloseTreeEntry, 0);
2457 } else if (recurse) {
2458 result = Blt_TreeViewApply(tvPtr, entryPtr,
2459 Blt_TreeViewCloseEntry, 0);
2460 } else {
2461 result = Blt_TreeViewCloseEntry(tvPtr, entryPtr);
2462 }
2463 if (result != TCL_OK) {
2464 tvPtr->flags |= (TV_LAYOUT | TV_DIRTY | TV_RESORT);
2465 Blt_TreeViewDoneTaggedEntries(&info);
2466 return TCL_ERROR;
2467 }
2468 }
2469 Blt_TreeViewDoneTaggedEntries(&info);
2470 }
2471 /* Closing a node may affect the visible entries and the
2472 * the world layout of the entries. */
2473 tvPtr->flags |= (TV_LAYOUT | TV_DIRTY | TV_RESORT);
2474 Blt_TreeViewEventuallyRedraw(tvPtr);
2475 return TCL_OK;
2476 }
2477
2478 /*
2479 *----------------------------------------------------------------------
2480 *
2481 * ConfigureOp --
2482 *
2483 * This procedure is called to process an objv/objc list, plus
2484 * the Tk option database, in order to configure (or reconfigure)
2485 * the widget.
2486 *
2487 * Results:
2488 * A standard Tcl result. If TCL_ERROR is returned, then
2489 * interp->result contains an error message.
2490 *
2491 * Side effects:
2492 * Configuration information, such as text string, colors, font,
2493 * etc. get set for tvPtr; old resources get freed, if there
2494 * were any. The widget is redisplayed.
2495 *
2496 *----------------------------------------------------------------------
2497 */
2498 static int
ConfigureOp(tvPtr,interp,objc,objv)2499 ConfigureOp(tvPtr, interp, objc, objv)
2500 TreeView *tvPtr;
2501 Tcl_Interp *interp;
2502 int objc;
2503 Tcl_Obj *CONST *objv;
2504 {
2505 Blt_TreeViewOptsInit(tvPtr);
2506 if (objc == 2) {
2507 return Blt_ConfigureInfoFromObj(interp, tvPtr->tkwin, bltTreeViewSpecs,
2508 (char *)tvPtr, (Tcl_Obj *)NULL, 0);
2509 } else if (objc == 3) {
2510 return Blt_ConfigureInfoFromObj(interp, tvPtr->tkwin,
2511 bltTreeViewSpecs, (char *)tvPtr, objv[2], 0);
2512 }
2513 if (Blt_ConfigureWidgetFromObj(interp, tvPtr->tkwin, bltTreeViewSpecs,
2514 objc - 2, objv + 2, (char *)tvPtr, BLT_CONFIG_OBJV_ONLY, NULL) != TCL_OK) {
2515 return TCL_ERROR;
2516 }
2517 if (Blt_TreeViewUpdateWidget(interp, tvPtr) != TCL_OK) {
2518 return TCL_ERROR;
2519 }
2520 if (tvPtr->tile != NULL) {
2521 Blt_SetTileChangedProc(tvPtr->tile, Blt_TreeViewTileChangedProc, tvPtr);
2522 }
2523 if (tvPtr->selectTile != NULL) {
2524 Blt_SetTileChangedProc(tvPtr->selectTile, Blt_TreeViewTileChangedProc, tvPtr);
2525 }
2526 Blt_TreeViewEventuallyRedraw(tvPtr);
2527 return TCL_OK;
2528 }
2529
2530 /*ARGSUSED*/
2531 static int
CurselectionOp(tvPtr,interp,objc,objv)2532 CurselectionOp(tvPtr, interp, objc, objv)
2533 TreeView *tvPtr;
2534 Tcl_Interp *interp; /* Not used. */
2535 int objc; /* Not used. */
2536 Tcl_Obj *CONST *objv; /* Not used. */
2537 {
2538 #if 0
2539 TreeViewEntry *entryPtr;
2540 TreeViewColumn *columnPtr;
2541 Tcl_Obj *listObjPtr, *objPtr;
2542
2543 Blt_HashEntry *hPtr;
2544 Blt_HashSearch cursor;
2545 TreeViewValue *valuePtr;
2546 Blt_ChainLink *linkPtr;
2547
2548 if (tvPtr->selectMode & SELECT_MODE_CELLMASK) {
2549 Tcl_AppendResult(interp, "-selectmode must not be 'cell' or 'multicell'", 0);
2550 return TCL_ERROR;
2551 }
2552 listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **)NULL);
2553
2554 for (hPtr = Blt_FirstHashEntry(&tvPtr->selectTable, &cursor);
2555 hPtr != NULL; hPtr = Blt_NextHashEntry(&cursor)) {
2556 entryPtr = (TreeViewEntry *)Blt_GetHashKey(&tvPtr->selectTable, hPtr);
2557 objPtr = NodeToObj(entryPtr->node);
2558 Tcl_ListObjAppendElement(interp, listObjPtr, objPtr);
2559 }
2560
2561
2562 Tcl_SetObjResult(interp, listObjPtr);
2563
2564 return TCL_OK;
2565 #else
2566 TreeViewEntry *entryPtr;
2567 Tcl_Obj *listObjPtr, *objPtr;
2568
2569 listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **)NULL);
2570 if (tvPtr->flags & TV_SELECT_SORTED) {
2571 Blt_ChainLink *linkPtr;
2572
2573 for (linkPtr = Blt_ChainFirstLink(tvPtr->selChainPtr); linkPtr != NULL;
2574 linkPtr = Blt_ChainNextLink(linkPtr)) {
2575 entryPtr = Blt_ChainGetValue(linkPtr);
2576 objPtr = NodeToObj(entryPtr->node);
2577 Tcl_ListObjAppendElement(interp, listObjPtr, objPtr);
2578
2579 }
2580 } else {
2581 for (entryPtr = tvPtr->rootPtr; entryPtr != NULL;
2582 entryPtr = Blt_TreeViewNextEntry(entryPtr, ENTRY_MASK)) {
2583 if (Blt_TreeViewEntryIsSelected(tvPtr, entryPtr, NULL)) {
2584 objPtr = NodeToObj(entryPtr->node);
2585 Tcl_ListObjAppendElement(interp, listObjPtr, objPtr);
2586 }
2587 }
2588 }
2589 Tcl_SetObjResult(interp, listObjPtr);
2590 return TCL_OK;
2591 #endif
2592 }
2593
2594 /*
2595 *----------------------------------------------------------------------
2596 *
2597 * BindOp --
2598 *
2599 * .t bind tagOrId sequence command
2600 *
2601 *----------------------------------------------------------------------
2602 */
2603 /*ARGSUSED*/
2604 static int
BindOp(tvPtr,interp,objc,objv)2605 BindOp(tvPtr, interp, objc, objv)
2606 TreeView *tvPtr;
2607 Tcl_Interp *interp;
2608 int objc;
2609 Tcl_Obj *CONST *objv;
2610 {
2611 ClientData object;
2612 TreeViewEntry *entryPtr;
2613 char *string;
2614
2615 /*
2616 * Entries are selected by id only. All other strings are
2617 * interpreted as a binding tag.
2618 */
2619 object = NULL;
2620 string = Tcl_GetString(objv[2]);
2621 if (isdigit(UCHAR(string[0]))) {
2622 Blt_TreeNode node;
2623 int inode;
2624
2625 if (Tcl_GetIntFromObj(tvPtr->interp, objv[2], &inode) != TCL_OK) {
2626 return TCL_ERROR;
2627 }
2628 node = Blt_TreeGetNode(tvPtr->tree, inode);
2629 object = Blt_NodeToEntry(tvPtr, node);
2630 } else if (GetEntryFromSpecialId(tvPtr, string, &entryPtr) == TCL_OK) {
2631 if (entryPtr != NULL) {
2632 return TCL_OK; /* Special id doesn't currently exist. */
2633 }
2634 object = entryPtr;
2635 } else {
2636 /* Assume that this is a binding tag. */
2637 object = Blt_TreeViewEntryTag(tvPtr, string);
2638 }
2639 if (object == NULL) {
2640 Tcl_AppendResult(interp, "unknown object", string, 0);
2641 return TCL_ERROR;
2642 }
2643 return Blt_ConfigureBindingsFromObj(interp, tvPtr->bindTable, object,
2644 objc - 3, objv + 3);
2645 }
2646
2647
2648 /*ARGSUSED*/
2649 static int
EditOp(tvPtr,interp,objc,objv)2650 EditOp(tvPtr, interp, objc, objv)
2651 TreeView *tvPtr;
2652 Tcl_Interp *interp; /* Not used. */
2653 int objc;
2654 Tcl_Obj *CONST *objv;
2655 {
2656 TreeViewEntry *entryPtr;
2657 char *string;
2658 int isRoot, isTest;
2659 int x, y, wx, wy;
2660 int rootX, rootY;
2661
2662 Tk_GetRootCoords(tvPtr->tkwin, &rootX, &rootY);
2663
2664 isRoot = isTest = FALSE;
2665 while (objc>2) {
2666 string = Tcl_GetString(objv[2]);
2667 if (strcmp("-root", string) == 0) {
2668 isRoot = TRUE;
2669 objv++, objc--;
2670 } else if (strcmp("-test", string) == 0) {
2671 isTest = TRUE;
2672 objv++, objc--;
2673 } else if (strcmp("-noscroll", string) == 0) {
2674 tvPtr->noScroll = 1;
2675 if (objc == 3) { return TCL_OK;}
2676 objv++, objc--;
2677 } else if (strcmp("-scroll", string) == 0) {
2678 tvPtr->noScroll = 0;
2679 if (objc == 3) { return TCL_OK;}
2680 objv++, objc--;
2681 } else {
2682 break;
2683 }
2684 }
2685 if (objc != 4) {
2686 Tcl_AppendResult(interp, "wrong # args: should be \"",
2687 Tcl_GetString(objv[0]), " ", Tcl_GetString(objv[1]),
2688 " ?-root? x y\"", (char *)NULL);
2689 return TCL_ERROR;
2690
2691 }
2692 if ((Tcl_GetIntFromObj(interp, objv[2], &x) != TCL_OK) ||
2693 (Tcl_GetIntFromObj(interp, objv[3], &y) != TCL_OK)) {
2694 return TCL_ERROR;
2695 }
2696 wx = x;
2697 wy = y;
2698 if (isRoot) {
2699 x -= rootX;
2700 y -= rootY;
2701 }
2702 entryPtr = Blt_TreeViewNearestEntry(tvPtr, x, y, FALSE);
2703 if (entryPtr != NULL) {
2704 Blt_ChainLink *linkPtr;
2705 TreeViewColumn *columnPtr;
2706 int worldX;
2707
2708 worldX = WORLDX(tvPtr, x);
2709 for (linkPtr = Blt_ChainFirstLink(tvPtr->colChainPtr);
2710 linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) {
2711 columnPtr = Blt_ChainGetValue(linkPtr);
2712 if (!columnPtr->editable) {
2713 continue; /* Column isn't editable. */
2714 }
2715 if ((worldX >= columnPtr->worldX) &&
2716 (worldX < (columnPtr->worldX + columnPtr->width))) {
2717 TreeViewValue *valuePtr;
2718
2719 valuePtr = Blt_TreeViewFindValue(entryPtr, columnPtr);
2720 if (valuePtr != NULL) {
2721 TreeViewStyle *stylePtr;
2722 int retVal = isTest;
2723
2724 stylePtr = CHOOSE3(tvPtr->stylePtr,columnPtr->stylePtr, valuePtr->stylePtr);
2725 if (stylePtr->classPtr->editProc != NULL) {
2726 if ((*stylePtr->classPtr->editProc)(tvPtr, entryPtr,
2727 valuePtr, stylePtr, x, y, &retVal) != TCL_OK) {
2728 return TCL_ERROR;
2729 }
2730 Blt_TreeViewEventuallyRedraw(tvPtr);
2731 }
2732 Tcl_SetObjResult(interp, Tcl_NewIntObj(retVal));
2733 return TCL_OK;
2734 }
2735 }
2736 }
2737 }
2738 Tcl_SetObjResult(interp, Tcl_NewIntObj(0));
2739 return TCL_OK;
2740 }
2741
2742 /*
2743 *----------------------------------------------------------------------
2744 *
2745 * EntryActivateOp --
2746 *
2747 * Selects the entry to appear active.
2748 *
2749 *----------------------------------------------------------------------
2750 */
2751 /*ARGSUSED*/
2752 static int
EntryActivateOp(tvPtr,interp,objc,objv)2753 EntryActivateOp(tvPtr, interp, objc, objv)
2754 TreeView *tvPtr;
2755 Tcl_Interp *interp;
2756 int objc; /* Not used. */
2757 Tcl_Obj *CONST *objv;
2758 {
2759 TreeViewEntry *newPtr, *oldPtr;
2760 char *string;
2761
2762 string = Tcl_GetString(objv[3]);
2763 if (string[0] == '\0') {
2764 newPtr = NULL;
2765 } else if (GetEntryFromObj(tvPtr, objv[3], &newPtr) != TCL_OK) {
2766 return TCL_ERROR;
2767 }
2768 if (tvPtr->treeColumn.hidden) {
2769 return TCL_OK;
2770 }
2771 oldPtr = tvPtr->activePtr;
2772 tvPtr->activePtr = newPtr;
2773 if (!(tvPtr->flags & TV_REDRAW) && (newPtr != oldPtr)) {
2774 Drawable drawable;
2775 int x, y;
2776
2777 drawable = Tk_WindowId(tvPtr->tkwin);
2778 if (oldPtr != NULL) {
2779 x = SCREENX(tvPtr, oldPtr->worldX);
2780 if (!tvPtr->flatView) {
2781 int hr, level;
2782 level = DEPTH(tvPtr, oldPtr->node);
2783 x += ICONWIDTH(level);
2784 hr = ((tvPtr->flags & TV_HIDE_ROOT) ? 1 : 0);
2785 if (!(tvPtr->lineWidth>0 || tvPtr->button.reqSize>0 || level>hr)) {
2786 x = 2;
2787 }
2788 }
2789 y = SCREENY(tvPtr, oldPtr->worldY);
2790 oldPtr->flags |= ENTRY_ICON;
2791 Blt_TreeViewDrawIcon(tvPtr, oldPtr, drawable, x, y, 1);
2792 }
2793 if (newPtr != NULL) {
2794 x = SCREENX(tvPtr, newPtr->worldX);
2795 if (!tvPtr->flatView) {
2796 int hr, level;
2797 level = DEPTH(tvPtr, newPtr->node);
2798 x += ICONWIDTH(level);
2799 hr = ((tvPtr->flags & TV_HIDE_ROOT) ? 1 : 0);
2800 if (!(tvPtr->lineWidth>0 || tvPtr->button.reqSize>0 || level>hr)) {
2801 x = 2;
2802 }
2803 }
2804 y = SCREENY(tvPtr, newPtr->worldY);
2805 newPtr->flags |= ENTRY_ICON;
2806 Blt_TreeViewDrawIcon(tvPtr, newPtr, drawable, x, y, 1);
2807 }
2808 }
2809 return TCL_OK;
2810 }
2811
2812 /*
2813 *----------------------------------------------------------------------
2814 *
2815 * EntryCgetOp --
2816 *
2817 *----------------------------------------------------------------------
2818 */
2819 /*ARGSUSED*/
2820 static int
EntryCgetOp(tvPtr,interp,objc,objv)2821 EntryCgetOp(tvPtr, interp, objc, objv)
2822 TreeView *tvPtr;
2823 Tcl_Interp *interp;
2824 int objc; /* Not used. */
2825 Tcl_Obj *CONST *objv;
2826 {
2827 TreeViewEntry *entryPtr;
2828
2829 if (Blt_TreeViewGetEntry(tvPtr, objv[3], &entryPtr) != TCL_OK) {
2830 return TCL_ERROR;
2831 }
2832 Blt_TreeViewOptsInit(tvPtr);
2833 return Blt_ConfigureValueFromObj(interp, tvPtr->tkwin,
2834 bltTreeViewEntrySpecs, (char *)entryPtr, objv[4], 0);
2835 }
2836
2837 /*
2838 *----------------------------------------------------------------------
2839 *
2840 * EntryConfigureOp --
2841 *
2842 * This procedure is called to process a list of configuration
2843 * options database, in order to reconfigure the one of more
2844 * entries in the widget.
2845 *
2846 * .h entryconfigure node node node node option value
2847 *
2848 * Results:
2849 * A standard Tcl result. If TCL_ERROR is returned, then
2850 * interp->result contains an error message.
2851 *
2852 * Side effects:
2853 * Configuration information, such as text string, colors, font,
2854 * etc. get set for tvPtr; old resources get freed, if there
2855 * were any. The hypertext is redisplayed.
2856 *
2857 *----------------------------------------------------------------------
2858 */
2859 static int
EntryConfigureOp(tvPtr,interp,objc,objv)2860 EntryConfigureOp(tvPtr, interp, objc, objv)
2861 TreeView *tvPtr;
2862 Tcl_Interp *interp;
2863 int objc;
2864 Tcl_Obj *CONST *objv;
2865 {
2866 int nIds, configObjc;
2867 Tcl_Obj *CONST *configObjv;
2868 register int i;
2869 TreeViewEntry *entryPtr;
2870 TreeViewTagInfo info = {0};
2871 char *string;
2872
2873 /* Figure out where the option value pairs begin */
2874 for (i = 3; i < objc; i++) {
2875 string = Tcl_GetString(objv[i]);
2876 if (string[0] == '-') {
2877 break;
2878 }
2879 }
2880 nIds = i-3; /* # of tags or ids specified */
2881 if (nIds<1) {
2882 Tcl_AppendResult(interp, "no ids specified", 0);
2883 return TCL_ERROR;
2884 }
2885 objc -= 3, objv += 3;
2886 configObjc = objc - nIds; /* # of options specified */
2887 configObjv = objv + nIds; /* Start of options in objv */
2888
2889 Blt_TreeViewOptsInit(tvPtr);
2890 for (i = 0; i < nIds; i++) {
2891 if (Blt_TreeViewFindTaggedEntries(tvPtr, objv[i], &info) != TCL_OK) {
2892 return TCL_ERROR;
2893 }
2894 for (entryPtr = Blt_TreeViewFirstTaggedEntry(&info); entryPtr != NULL;
2895 entryPtr = Blt_TreeViewNextTaggedEntry(&info)) {
2896 if (configObjc == 0) {
2897 return Blt_ConfigureInfoFromObj(interp, tvPtr->tkwin,
2898 bltTreeViewEntrySpecs, (char *)entryPtr,
2899 (Tcl_Obj *)NULL, 0);
2900 } else if (configObjc == 1) {
2901 return Blt_ConfigureInfoFromObj(interp, tvPtr->tkwin,
2902 bltTreeViewEntrySpecs, (char *)entryPtr,
2903 configObjv[0], 0);
2904 }
2905 if (Blt_TreeViewConfigureEntry(tvPtr, entryPtr, configObjc,
2906 configObjv, BLT_CONFIG_OBJV_ONLY) != TCL_OK) {
2907 Blt_TreeViewDoneTaggedEntries(&info);
2908 return TCL_ERROR;
2909 }
2910 }
2911 Blt_TreeViewDoneTaggedEntries(&info);
2912 }
2913 tvPtr->flags |= (TV_DIRTY | TV_LAYOUT | TV_SCROLL | TV_RESORT|TV_DIRTYALL);
2914 Blt_TreeViewEventuallyRedraw(tvPtr);
2915 return TCL_OK;
2916 }
2917
2918 /*
2919 *----------------------------------------------------------------------
2920 *
2921 * EntryIsOpenOp --
2922 *
2923 *----------------------------------------------------------------------
2924 */
2925 /*ARGSUSED*/
2926 static int
EntryIsBeforeOp(tvPtr,interp,objc,objv)2927 EntryIsBeforeOp(tvPtr, interp, objc, objv)
2928 TreeView *tvPtr;
2929 Tcl_Interp *interp;
2930 int objc; /* Not used. */
2931 Tcl_Obj *CONST *objv;
2932 {
2933 TreeViewEntry *e1Ptr, *e2Ptr;
2934 int bool;
2935
2936 if ((Blt_TreeViewGetEntry(tvPtr, objv[3], &e1Ptr) != TCL_OK) ||
2937 (Blt_TreeViewGetEntry(tvPtr, objv[4], &e2Ptr) != TCL_OK)) {
2938 return TCL_ERROR;
2939 }
2940 bool = Blt_TreeIsBefore(e1Ptr->node, e2Ptr->node);
2941 Tcl_SetObjResult(interp, Tcl_NewBooleanObj(bool));
2942 return TCL_OK;
2943 }
2944
2945 /*
2946 *----------------------------------------------------------------------
2947 *
2948 * EntryIsHiddenOp --
2949 *
2950 *----------------------------------------------------------------------
2951 */
2952 /*ARGSUSED*/
2953 static int
EntryIsHiddenOp(tvPtr,interp,objc,objv)2954 EntryIsHiddenOp(tvPtr, interp, objc, objv)
2955 TreeView *tvPtr;
2956 Tcl_Interp *interp;
2957 int objc; /* Not used. */
2958 Tcl_Obj *CONST *objv;
2959 {
2960 TreeViewEntry *entryPtr;
2961 int bool;
2962
2963 if (Blt_TreeViewGetEntry(tvPtr, objv[3], &entryPtr) != TCL_OK) {
2964 return TCL_ERROR;
2965 }
2966 bool = (entryPtr->flags & ENTRY_HIDDEN);
2967 Tcl_SetObjResult(interp, Tcl_NewBooleanObj(bool));
2968 return TCL_OK;
2969 }
2970
2971 /*
2972 *----------------------------------------------------------------------
2973 *
2974 * EntryIsLeafOp --
2975 *
2976 *----------------------------------------------------------------------
2977 */
2978 /*ARGSUSED*/
2979 static int
EntryIsLeafOp(tvPtr,interp,objc,objv)2980 EntryIsLeafOp(tvPtr, interp, objc, objv)
2981 TreeView *tvPtr;
2982 Tcl_Interp *interp;
2983 int objc; /* Not used. */
2984 Tcl_Obj *CONST *objv;
2985 {
2986 TreeViewEntry *entryPtr;
2987 int bool;
2988
2989 if (Blt_TreeViewGetEntry(tvPtr, objv[3], &entryPtr) != TCL_OK) {
2990 return TCL_ERROR;
2991 }
2992 bool = Blt_TreeViewIsLeaf(entryPtr);
2993 Tcl_SetObjResult(interp, Tcl_NewBooleanObj(bool));
2994 return TCL_OK;
2995 }
2996
2997
2998 /*
2999 *----------------------------------------------------------------------
3000 *
3001 * EntryIsOpenOp --
3002 *
3003 *----------------------------------------------------------------------
3004 */
3005 /*ARGSUSED*/
3006 static int
EntryIsOpenOp(tvPtr,interp,objc,objv)3007 EntryIsOpenOp(tvPtr, interp, objc, objv)
3008 TreeView *tvPtr;
3009 Tcl_Interp *interp;
3010 int objc; /* Not used. */
3011 Tcl_Obj *CONST *objv;
3012 {
3013 TreeViewEntry *entryPtr;
3014 int bool;
3015
3016 if (Blt_TreeViewGetEntry(tvPtr, objv[3], &entryPtr) != TCL_OK) {
3017 return TCL_ERROR;
3018 }
3019 bool = ((entryPtr->flags & ENTRY_CLOSED) == 0);
3020 Tcl_SetObjResult(interp, Tcl_NewBooleanObj(bool));
3021 return TCL_OK;
3022 }
3023
3024 /*ARGSUSED*/
3025 static int
EntryParentOp(tvPtr,interp,objc,objv)3026 EntryParentOp(tvPtr, interp, objc, objv)
3027 TreeView *tvPtr;
3028 Tcl_Interp *interp;
3029 int objc;
3030 Tcl_Obj *CONST *objv;
3031 {
3032 TreeViewEntry *entryPtr;
3033
3034 if (Blt_TreeViewGetEntry(tvPtr, objv[3], &entryPtr) != TCL_OK) {
3035 return TCL_ERROR;
3036 }
3037 entryPtr = Blt_TreeViewParentEntry(entryPtr);
3038 if (entryPtr != NULL) {
3039 Tcl_SetObjResult(interp, NodeToObj(entryPtr->node));
3040 }
3041 return TCL_OK;
3042 }
3043
3044 /*ARGSUSED*/
3045 static int
EntryUpOp(tvPtr,interp,objc,objv)3046 EntryUpOp(tvPtr, interp, objc, objv)
3047 TreeView *tvPtr;
3048 Tcl_Interp *interp;
3049 int objc;
3050 Tcl_Obj *CONST *objv;
3051 {
3052 TreeViewEntry *entryPtr, *fromPtr;
3053
3054 if (Blt_TreeViewGetEntry(tvPtr, objv[3], &entryPtr) != TCL_OK) {
3055 return TCL_ERROR;
3056 }
3057 fromPtr = entryPtr;
3058 if (tvPtr->flatView) {
3059 int i;
3060
3061 i = entryPtr->flatIndex - 1;
3062 if (i >= 0) {
3063 entryPtr = FLATIND(tvPtr,i);
3064 }
3065 } else {
3066 entryPtr = Blt_TreeViewPrevEntry(fromPtr, ENTRY_MASK);
3067 if (entryPtr == NULL) {
3068 entryPtr = fromPtr;
3069 }
3070 if ((entryPtr == tvPtr->rootPtr) &&
3071 (tvPtr->flags & TV_HIDE_ROOT)) {
3072 entryPtr = Blt_TreeViewNextEntry(entryPtr, ENTRY_MASK);
3073 }
3074 }
3075 if (entryPtr != NULL) {
3076 Tcl_SetObjResult(interp, NodeToObj(entryPtr->node));
3077 }
3078 return TCL_OK;
3079 }
3080
3081 /*ARGSUSED*/
3082 static int
EntryDepthOp(tvPtr,interp,objc,objv)3083 EntryDepthOp(tvPtr, interp, objc, objv)
3084 TreeView *tvPtr;
3085 Tcl_Interp *interp;
3086 int objc;
3087 Tcl_Obj *CONST *objv;
3088 {
3089 TreeViewEntry *entryPtr;
3090
3091 if (Blt_TreeViewGetEntry(tvPtr, objv[3], &entryPtr) != TCL_OK) {
3092 return TCL_ERROR;
3093 }
3094 if (entryPtr != NULL) {
3095 Tcl_SetObjResult(interp, Tcl_NewIntObj(DEPTH(tvPtr, entryPtr->node)));
3096 }
3097 return TCL_OK;
3098 }
3099
3100
3101 /*ARGSUSED*/
3102 static int
EntryDownOp(tvPtr,interp,objc,objv)3103 EntryDownOp(tvPtr, interp, objc, objv)
3104 TreeView *tvPtr;
3105 Tcl_Interp *interp;
3106 int objc;
3107 Tcl_Obj *CONST *objv;
3108 {
3109 TreeViewEntry *entryPtr, *fromPtr;
3110
3111 if (Blt_TreeViewGetEntry(tvPtr, objv[3], &entryPtr) != TCL_OK) {
3112 return TCL_ERROR;
3113 }
3114 fromPtr = entryPtr;
3115 if (tvPtr->flatView) {
3116 int i;
3117
3118 i = entryPtr->flatIndex + 1;
3119 if (i < tvPtr->nEntries) {
3120 entryPtr = FLATIND(tvPtr, i);
3121 }
3122 } else {
3123 entryPtr = Blt_TreeViewNextEntry(fromPtr, ENTRY_MASK);
3124 if (entryPtr == NULL) {
3125 entryPtr = fromPtr;
3126 }
3127 if ((entryPtr == tvPtr->rootPtr) &&
3128 (tvPtr->flags & TV_HIDE_ROOT)) {
3129 entryPtr = Blt_TreeViewNextEntry(entryPtr, ENTRY_MASK);
3130 }
3131 }
3132 if (entryPtr != NULL) {
3133 Tcl_SetObjResult(interp, NodeToObj(entryPtr->node));
3134 }
3135 return TCL_OK;
3136 }
3137
3138 /*ARGSUSED*/
3139 static int
EntryExistsOp(tvPtr,interp,objc,objv)3140 EntryExistsOp(tvPtr, interp, objc, objv)
3141 TreeView *tvPtr;
3142 Tcl_Interp *interp;
3143 int objc;
3144 Tcl_Obj *CONST *objv;
3145 {
3146 TreeViewEntry *entryPtr;
3147 TreeViewColumn *columnPtr;
3148
3149 int exists;
3150
3151 if (objc==5 && Blt_TreeViewGetColumn(interp, tvPtr, objv[4], &columnPtr) != TCL_OK) {
3152 return TCL_ERROR;
3153 }
3154 exists = (Blt_TreeViewGetEntry(tvPtr, objv[3], &entryPtr) == TCL_OK);
3155
3156 if (exists && objc == 5) {
3157 if (!Blt_TreeValueExists(tvPtr->tree, entryPtr->node, Tcl_GetString(objv[4]))) {
3158 exists = FALSE;
3159 }
3160 }
3161 Tcl_SetObjResult(interp, Tcl_NewBooleanObj(exists));
3162 return TCL_OK;
3163 }
3164
3165
3166 /*ARGSUSED*/
3167 static int
EntryPrevOp(tvPtr,interp,objc,objv)3168 EntryPrevOp(tvPtr, interp, objc, objv)
3169 TreeView *tvPtr;
3170 Tcl_Interp *interp;
3171 int objc;
3172 Tcl_Obj *CONST *objv;
3173 {
3174 TreeViewEntry *entryPtr, *fromPtr;
3175
3176 if (Blt_TreeViewGetEntry(tvPtr, objv[3], &entryPtr) != TCL_OK) {
3177 return TCL_ERROR;
3178 }
3179 fromPtr = entryPtr;
3180 if (tvPtr->flatView) {
3181 int i;
3182
3183 i = entryPtr->flatIndex - 1;
3184 if (i < 0) {
3185 i = tvPtr->nEntries - 1;
3186 }
3187 entryPtr = FLATIND(tvPtr, i);
3188 } else {
3189 entryPtr = Blt_TreeViewPrevEntry(fromPtr, ENTRY_MASK);
3190 if (entryPtr == NULL) {
3191 entryPtr = LastEntry(tvPtr, tvPtr->rootPtr, ENTRY_MASK);
3192 }
3193 if ((entryPtr == tvPtr->rootPtr) &&
3194 (tvPtr->flags & TV_HIDE_ROOT)) {
3195 /*entryPtr = Blt_TreeViewNextEntry(entryPtr, ENTRY_MASK); */
3196 entryPtr = LastEntry(tvPtr, tvPtr->rootPtr, ENTRY_MASK);
3197 }
3198 }
3199 if (entryPtr != NULL) {
3200 Tcl_SetObjResult(interp, NodeToObj(entryPtr->node));
3201 }
3202 return TCL_OK;
3203 }
3204
3205 /*ARGSUSED*/
3206 static int
EntryRelabelOp(tvPtr,interp,objc,objv)3207 EntryRelabelOp(tvPtr, interp, objc, objv)
3208 TreeView *tvPtr;
3209 Tcl_Interp *interp;
3210 int objc;
3211 Tcl_Obj *CONST *objv;
3212 {
3213 TreeViewEntry *entryPtr;
3214 char *string;
3215 if ((tvPtr->flags & TV_ALLOW_DUPLICATES) == 0) {
3216 Tcl_AppendResult(interp, "must enable -allowduplicates to use relabel", 0);
3217 return TCL_ERROR;
3218 }
3219
3220 if (Blt_TreeViewGetEntry(tvPtr, objv[3], &entryPtr) != TCL_OK) {
3221 return TCL_ERROR;
3222 }
3223 string = Tcl_GetString(objv[4]);
3224 Blt_TreeRelabelNode(tvPtr->tree, entryPtr->node, string);
3225 return TCL_OK;
3226 }
3227
3228 /*ARGSUSED*/
3229 static int
EntrySelectOp(tvPtr,interp,objc,objv)3230 EntrySelectOp(tvPtr, interp, objc, objv)
3231 TreeView *tvPtr;
3232 Tcl_Interp *interp;
3233 int objc;
3234 Tcl_Obj *CONST *objv;
3235 {
3236 TreeViewEntry *entryPtr;
3237 Tcl_DString dStr;
3238 int rc;
3239
3240 if (Blt_TreeViewGetEntry(tvPtr, objv[3], &entryPtr) != TCL_OK) {
3241 return TCL_ERROR;
3242 }
3243 if ((entryPtr != NULL) && (entryPtr != tvPtr->focusPtr)) {
3244 if (entryPtr->flags & ENTRY_HIDDEN) {
3245 /* Doesn't make sense to set focus to a node you can't see. */
3246 MapAncestors(tvPtr, entryPtr);
3247 }
3248 /* Changing focus can only affect the visible entries. The
3249 * entry layout stays the same. */
3250 if (tvPtr->focusPtr != NULL) {
3251 tvPtr->focusPtr->flags |= ENTRY_REDRAW;
3252 }
3253 entryPtr->flags |= ENTRY_REDRAW;
3254 tvPtr->flags |= TV_SCROLL;
3255 tvPtr->focusPtr = entryPtr;
3256 }
3257 Tcl_DStringInit(&dStr);
3258 Tcl_DStringAppend(&dStr, "::blt::tv::MoveFocus ", -1);
3259 Tcl_DStringAppend(&dStr, Tk_PathName(tvPtr->tkwin), -1);
3260 Tcl_DStringAppend(&dStr, " focus", -1);
3261 rc = Tcl_GlobalEval(interp, Tcl_DStringValue(&dStr));
3262 Tcl_DStringFree(&dStr);
3263 return rc;
3264 }
3265
3266 /*ARGSUSED*/
3267 static int
EntrySiblingOp(tvPtr,interp,objc,objv)3268 EntrySiblingOp(tvPtr, interp, objc, objv)
3269 TreeView *tvPtr;
3270 Tcl_Interp *interp;
3271 int objc;
3272 Tcl_Obj *CONST *objv;
3273 {
3274 TreeViewEntry *entryPtr = NULL, *fromPtr;
3275 Blt_TreeNode node;
3276 int next = 1;
3277
3278 if (objc>4) {
3279 const char *cp;
3280 cp = Tcl_GetString(objv[3]);
3281 if (!strcmp(cp, "-before")) {
3282 next = 0;
3283 } else {
3284 Tcl_AppendResult(interp, "expected \"-before\"", 0);
3285 return TCL_ERROR;
3286 }
3287 objc--;
3288 objv++;
3289 }
3290 if (Blt_TreeViewGetEntry(tvPtr, objv[3], &fromPtr) != TCL_OK) {
3291 return TCL_ERROR;
3292 }
3293 if (next) {
3294 node = Blt_TreeNextSibling(fromPtr->node);
3295 if (node != NULL) {
3296 entryPtr = Blt_NodeToEntry(tvPtr, node);
3297 }
3298 } else {
3299 node = Blt_TreePrevSibling(fromPtr->node);
3300 if (node != NULL) {
3301 entryPtr = Blt_NodeToEntry(tvPtr, node);
3302 }
3303 }
3304
3305 if (entryPtr != NULL) {
3306 Tcl_SetObjResult(interp, NodeToObj(entryPtr->node));
3307 }
3308 return TCL_OK;
3309 }
3310
3311 /*ARGSUSED*/
3312 static int
EntryNextOp(tvPtr,interp,objc,objv)3313 EntryNextOp(tvPtr, interp, objc, objv)
3314 TreeView *tvPtr;
3315 Tcl_Interp *interp;
3316 int objc;
3317 Tcl_Obj *CONST *objv;
3318 {
3319 TreeViewEntry *entryPtr;
3320
3321 if (Blt_TreeViewGetEntry(tvPtr, objv[3], &entryPtr) != TCL_OK) {
3322 return TCL_ERROR;
3323 }
3324 if (tvPtr->flatView) {
3325 int i;
3326
3327 i = entryPtr->flatIndex + 1;
3328 if (i >= tvPtr->nEntries) {
3329 i = 0;
3330 }
3331 entryPtr = FLATIND(tvPtr, i);
3332 } else {
3333 entryPtr = Blt_TreeViewNextEntry(entryPtr, ENTRY_MASK);
3334 if (entryPtr == NULL) {
3335 if (tvPtr->flags & TV_HIDE_ROOT) {
3336 entryPtr = Blt_TreeViewNextEntry(tvPtr->rootPtr,ENTRY_MASK);
3337 } else {
3338 entryPtr = tvPtr->rootPtr;
3339 }
3340 }
3341 }
3342 if (entryPtr != NULL) {
3343 Tcl_SetObjResult(interp, NodeToObj(entryPtr->node));
3344 }
3345 return TCL_OK;
3346 }
3347
3348 /*ARGSUSED*/
3349 static int
EntryChildrenOp(tvPtr,interp,objc,objv)3350 EntryChildrenOp(tvPtr, interp, objc, objv)
3351 TreeView *tvPtr;
3352 Tcl_Interp *interp;
3353 int objc;
3354 Tcl_Obj *CONST *objv;
3355 {
3356 TreeViewEntry *parentPtr;
3357 Tcl_Obj *listObjPtr, *objPtr;
3358 unsigned int mask;
3359
3360 mask = 0;
3361 if (Blt_TreeViewGetEntry(tvPtr, objv[3], &parentPtr) != TCL_OK) {
3362 return TCL_ERROR;
3363 }
3364 listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **)NULL);
3365 if (objc == 4) {
3366 TreeViewEntry *entryPtr;
3367
3368 for (entryPtr = Blt_TreeViewFirstChild(parentPtr, mask);
3369 entryPtr != NULL;
3370 entryPtr = Blt_TreeViewNextSibling(entryPtr, mask)) {
3371 objPtr = NodeToObj(entryPtr->node);
3372 Tcl_ListObjAppendElement(interp, listObjPtr, objPtr);
3373 }
3374 } else if (objc == 6) {
3375 TreeViewEntry *entryPtr, *lastPtr, *firstPtr;
3376 int firstPos, lastPos;
3377 int nNodes;
3378
3379 if ((Blt_GetPositionFromObj(interp, objv[4], &firstPos) != TCL_OK) ||
3380 (Blt_GetPositionFromObj(interp, objv[5], &lastPos) != TCL_OK)) {
3381 return TCL_ERROR;
3382 }
3383 nNodes = Blt_TreeNodeDegree(parentPtr->node);
3384 if (nNodes == 0) {
3385 return TCL_OK;
3386 }
3387 if ((lastPos == END) || (lastPos >= nNodes)) {
3388 lastPtr = Blt_TreeViewLastChild(parentPtr, mask);
3389 } else {
3390 lastPtr = GetNthEntry(parentPtr, lastPos, mask);
3391 }
3392 if ((firstPos == END) || (firstPos >= nNodes)) {
3393 firstPtr = Blt_TreeViewLastChild(parentPtr, mask);
3394 } else {
3395 firstPtr = GetNthEntry(parentPtr, firstPos, mask);
3396 }
3397 if ((lastPos != END) && (firstPos > lastPos)) {
3398 for (entryPtr = lastPtr; entryPtr != NULL;
3399 entryPtr = Blt_TreeViewPrevEntry(entryPtr, mask)) {
3400 objPtr = NodeToObj(entryPtr->node);
3401 Tcl_ListObjAppendElement(interp, listObjPtr, objPtr);
3402 if (entryPtr == firstPtr) {
3403 break;
3404 }
3405 }
3406 } else {
3407 for (entryPtr = firstPtr; entryPtr != NULL;
3408 entryPtr = Blt_TreeViewNextEntry(entryPtr, mask)) {
3409 objPtr = NodeToObj(entryPtr->node);
3410 Tcl_ListObjAppendElement(interp, listObjPtr, objPtr);
3411 if (entryPtr == lastPtr) {
3412 break;
3413 }
3414 }
3415 }
3416 } else {
3417 Tcl_AppendResult(interp, "wrong # args: should be \"",
3418 Tcl_GetString(objv[0]), " ",
3419 Tcl_GetString(objv[1]), " ",
3420 Tcl_GetString(objv[2]), " tagOrId ?first last?",
3421 (char *)NULL);
3422 return TCL_ERROR;
3423 }
3424 Tcl_SetObjResult(interp, listObjPtr);
3425 return TCL_OK;
3426 }
3427
3428
3429 /*
3430 *----------------------------------------------------------------------
3431 *
3432 * EntryDeleteOp --
3433 *
3434 *----------------------------------------------------------------------
3435 */
3436 /*ARGSUSED*/
3437 static int
EntryDeleteOp(tvPtr,interp,objc,objv)3438 EntryDeleteOp(tvPtr, interp, objc, objv)
3439 TreeView *tvPtr;
3440 Tcl_Interp *interp;
3441 int objc; /* Not used. */
3442 Tcl_Obj *CONST *objv;
3443 {
3444 TreeViewEntry *entryPtr;
3445
3446 if (Blt_TreeViewGetEntry(tvPtr, objv[3], &entryPtr) != TCL_OK) {
3447 return TCL_ERROR;
3448 }
3449 if (objc == 5) {
3450 int entryPos;
3451 Blt_TreeNode node;
3452 /*
3453 * Delete a single child node from a hierarchy specified
3454 * by its numeric position.
3455 */
3456 if (Blt_GetPositionFromObj(interp, objv[3], &entryPos) != TCL_OK) {
3457 return TCL_ERROR;
3458 }
3459 if (entryPos >= (int)Blt_TreeNodeDegree(entryPtr->node)) {
3460 return TCL_OK; /* Bad first index */
3461 }
3462 if (entryPos == END) {
3463 node = Blt_TreeLastChild(entryPtr->node);
3464 } else {
3465 node = GetNthNode(entryPtr->node, entryPos);
3466 }
3467 DeleteNode(tvPtr, node);
3468 } else {
3469 int firstPos, lastPos;
3470 Blt_TreeNode node, first, last, next;
3471 int nEntries;
3472 /*
3473 * Delete range of nodes in hierarchy specified by first/last
3474 * positions.
3475 */
3476 if ((Blt_GetPositionFromObj(interp, objv[4], &firstPos) != TCL_OK) ||
3477 (Blt_GetPositionFromObj(interp, objv[5], &lastPos) != TCL_OK)) {
3478 return TCL_ERROR;
3479 }
3480 nEntries = Blt_TreeNodeDegree(entryPtr->node);
3481 if (nEntries == 0) {
3482 return TCL_OK;
3483 }
3484 if (firstPos == END) {
3485 firstPos = nEntries - 1;
3486 }
3487 if (firstPos >= nEntries) {
3488 Tcl_AppendResult(interp, "first position \"",
3489 Tcl_GetString(objv[4]), " is out of range", (char *)NULL);
3490 return TCL_ERROR;
3491 }
3492 if ((lastPos == END) || (lastPos >= nEntries)) {
3493 lastPos = nEntries - 1;
3494 }
3495 if (firstPos > lastPos) {
3496 Tcl_AppendResult(interp, "bad range: \"", Tcl_GetString(objv[4]),
3497 " > ", Tcl_GetString(objv[5]), "\"", (char *)NULL);
3498 return TCL_ERROR;
3499 }
3500 first = GetNthNode(entryPtr->node, firstPos);
3501 last = GetNthNode(entryPtr->node, lastPos);
3502 for (node = first; node != NULL; node = next) {
3503 next = Blt_TreeNextSibling(node);
3504 DeleteNode(tvPtr, node);
3505 if (node == last) {
3506 break;
3507 }
3508 }
3509 }
3510 tvPtr->flags |= (TV_LAYOUT | TV_DIRTY | TV_RESORT);
3511 Blt_TreeViewEventuallyRedraw(tvPtr);
3512 return TCL_OK;
3513 }
3514
3515 /*
3516 *----------------------------------------------------------------------
3517 *
3518 * EntrySizeOp --
3519 *
3520 * Counts the number of entries at this node.
3521 *
3522 * Results:
3523 * A standard Tcl result. If an error occurred TCL_ERROR is
3524 * returned and interp->result will contain an error message.
3525 * Otherwise, TCL_OK is returned and interp->result contains
3526 * the number of entries.
3527 *
3528 *----------------------------------------------------------------------
3529 */
3530 static int
EntrySizeOp(tvPtr,interp,objc,objv)3531 EntrySizeOp(tvPtr, interp, objc, objv)
3532 TreeView *tvPtr;
3533 Tcl_Interp *interp;
3534 int objc;
3535 Tcl_Obj *CONST *objv;
3536 {
3537 TreeViewEntry *entryPtr;
3538 int length, sum, recurse;
3539 char *string;
3540
3541 recurse = FALSE;
3542 string = Tcl_GetStringFromObj(objv[3], &length);
3543 if ((string[0] == '-') && (length > 1) &&
3544 (strncmp(string, "-recurse", length) == 0)) {
3545 objv++, objc--;
3546 recurse = TRUE;
3547 }
3548 if (objc != 4) {
3549 Tcl_AppendResult(interp, "wrong or missing args", (char *)NULL);
3550 return TCL_ERROR;
3551 }
3552 if (Blt_TreeViewGetEntry(tvPtr, objv[3], &entryPtr) != TCL_OK) {
3553 return TCL_ERROR;
3554 }
3555 if (recurse) {
3556 sum = Blt_TreeSize(entryPtr->node);
3557 } else {
3558 sum = Blt_TreeNodeDegree(entryPtr->node);
3559 }
3560 Tcl_SetObjResult(interp, Tcl_NewIntObj(sum));
3561 return TCL_OK;
3562 }
3563
3564 /*
3565 *----------------------------------------------------------------------
3566 *
3567 * EntryOp --
3568 *
3569 * This procedure handles entry operations.
3570 *
3571 * Results:
3572 * A standard Tcl result.
3573 *
3574 *----------------------------------------------------------------------
3575 */
3576
3577 static Blt_OpSpec entryOps[] =
3578 {
3579 {"activate", 1, (Blt_Op)EntryActivateOp, 4, 4, "tagOrId",},
3580 /*bbox*/
3581 /*bind*/
3582 {"cget", 2, (Blt_Op)EntryCgetOp, 5, 5, "tagOrId option",},
3583 {"children", 2, (Blt_Op)EntryChildrenOp, 4, 6,
3584 "tagOrId firstPos lastPos",},
3585 /*close*/
3586 {"configure", 2, (Blt_Op)EntryConfigureOp, 4, 0,
3587 "tagOrId ?tagOrId...? ?option value?...",},
3588 {"delete", 3, (Blt_Op)EntryDeleteOp, 5, 6, "tagOrId firstPos ?lastPos?",},
3589 {"depth", 3, (Blt_Op)EntryDepthOp, 4, 4, "tagOrId",},
3590 {"down", 2, (Blt_Op)EntryDownOp, 4, 4, "tagOrId",},
3591 {"exists", 1, (Blt_Op)EntryExistsOp, 4, 5, "tagOrId ?col?",},
3592 /*focus*/
3593 /*hide*/
3594 {"get", 2, (Blt_Op)EntryGetOp, 4, -1, "tagOrId ?key? ?default?",},
3595 {"incr", 3, (Blt_Op)EntryIncrOp, 5, 6, "tagOrId key ?amount?",},
3596 /*index*/
3597 {"isbefore", 3, (Blt_Op)EntryIsBeforeOp, 5, 5, "tagOrId tagOrId",},
3598 {"ishidden", 3, (Blt_Op)EntryIsHiddenOp, 4, 4, "tagOrId",},
3599 {"isleaf", 3, (Blt_Op)EntryIsLeafOp, 4, 4, "tagOrId",},
3600 {"ismapped", 3, (Blt_Op)EntryIsmappedOp, 4, 4, "tagOrId",},
3601 {"isopen", 3, (Blt_Op)EntryIsOpenOp, 4, 4, "tagOrId",},
3602 {"isset", 3, (Blt_Op)EntryIssetOp, 5, 5, "tagOrId col",},
3603 {"isvisible", 3, (Blt_Op)EntryIsvisibleOp, 4, 4, "tagOrId",},
3604 /*move*/
3605 /*nearest*/
3606 /*open*/
3607 {"next", 2, (Blt_Op)EntryNextOp, 4, 4, "tagOrId",},
3608 {"parent", 2, (Blt_Op)EntryParentOp, 4, 4, "tagOrId",},
3609 {"prev", 2, (Blt_Op)EntryPrevOp, 4, 4, "tagOrId",},
3610 {"relabel", 2, (Blt_Op)EntryRelabelOp, 5, 5, "tagOrId newLabel",},
3611 {"select", 2, (Blt_Op)EntrySelectOp, 4, 4, "tagOrId",},
3612 /*see*/
3613 {"set", 2, (Blt_Op)EntrySetOp, 5, -1, "tagOrId col ?value ...?",},
3614 /*show*/
3615 {"sibling", 3, (Blt_Op)EntrySiblingOp, 4, 5, "?-before? tagOrId",},
3616 {"size", 3, (Blt_Op)EntrySizeOp, 4, 5, "?-recurse? tagOrId",},
3617 {"unset", 2, (Blt_Op)EntryUnsetOp, 5, 5, "tagOrId col",},
3618 {"up", 1, (Blt_Op)EntryUpOp, 4, 4, "tagOrId",},
3619 {"value", 2, (Blt_Op)EntryValueOp, 4, 5, "tagOrId ?col?",},
3620 /*toggle*/
3621 };
3622 static int nEntryOps = sizeof(entryOps) / sizeof(Blt_OpSpec);
3623
3624 static int
EntryOp(tvPtr,interp,objc,objv)3625 EntryOp(tvPtr, interp, objc, objv)
3626 TreeView *tvPtr;
3627 Tcl_Interp *interp;
3628 int objc;
3629 Tcl_Obj *CONST *objv;
3630 {
3631 Blt_Op proc;
3632 int result;
3633
3634 proc = Blt_GetOpFromObj(interp, nEntryOps, entryOps, BLT_OP_ARG2, objc,
3635 objv, 0);
3636 if (proc == NULL) {
3637 return TCL_ERROR;
3638 }
3639 result = (*proc) (tvPtr, interp, objc, objv);
3640 return result;
3641 }
3642
3643 /*ARGSUSED*/
3644 static int
ExactCompare(interp,name,patternPtr,nocase)3645 ExactCompare(interp, name, patternPtr, nocase)
3646 Tcl_Interp *interp; /* Not used. */
3647 char *name;
3648 Tcl_Obj *patternPtr;
3649 int nocase;
3650 {
3651 char *pattern = Tcl_GetString(patternPtr);
3652 if (!nocase) {
3653 return (strcmp(name, pattern) == 0);
3654 } else {
3655 return (strcasecmp(name, pattern) == 0);
3656 }
3657 }
3658
3659 /*ARGSUSED*/
3660 static int
GlobCompare(interp,name,patternPtr,nocase)3661 GlobCompare(interp, name, patternPtr, nocase)
3662 Tcl_Interp *interp; /* Not used. */
3663 char *name;
3664 Tcl_Obj *patternPtr;
3665 int nocase;
3666 {
3667 char *pattern = Tcl_GetString(patternPtr);
3668 return Tcl_StringCaseMatch(name, pattern, nocase);
3669 }
3670
3671 static int
RegexpCompare(interp,name,patternPtr,nocase)3672 RegexpCompare(interp, name, patternPtr, nocase)
3673 Tcl_Interp *interp;
3674 char *name;
3675 Tcl_Obj *patternPtr;
3676 int nocase;
3677 {
3678 Tcl_DString dStr;
3679 int len, i, result;
3680 char *cp;
3681
3682 Tcl_Obj *namePtr;
3683 if (!nocase) {
3684 namePtr = Tcl_NewStringObj(name, -1);
3685 result = Tcl_RegExpMatchObj(interp, namePtr, patternPtr);
3686 } else {
3687 len = strlen(name);
3688 Tcl_DStringInit(&dStr);
3689 Tcl_DStringSetLength(&dStr, len + 1);
3690 cp = Tcl_DStringValue(&dStr);
3691 for (i=0; i<len; i++) {
3692 cp[i] = tolower(name[i]);
3693 }
3694 cp[len] = 0;
3695 namePtr = Tcl_NewStringObj(cp, len);
3696 result = Tcl_RegExpMatchObj(interp, namePtr, patternPtr);
3697 Tcl_DStringFree(&dStr);
3698 }
3699 Tcl_DecrRefCount(namePtr);
3700 return result;
3701 }
3702
3703 static int
InlistCompare(interp,name,patternPtr,nocase)3704 InlistCompare(interp, name, patternPtr, nocase)
3705 Tcl_Interp *interp; /* Not used. */
3706 char *name;
3707 Tcl_Obj *patternPtr;
3708 int nocase;
3709 {
3710 Tcl_Obj **objv;
3711 int objc, i;
3712 char *pattern;
3713
3714 if (Tcl_ListObjGetElements(interp, patternPtr, &objc, &objv) != TCL_OK) {
3715 return 1;
3716 }
3717 for (i = 0; i < objc; i++) {
3718 pattern = Tcl_GetString(objv[i]);
3719 if (!nocase) {
3720 if (strcmp(name, pattern) == 0) {
3721 return 1;
3722 }
3723 } else {
3724 if (strcasecmp(name, pattern) == 0) {
3725 return 1;
3726 }
3727 }
3728 }
3729 return 0;
3730 }
3731
3732 /*
3733 *----------------------------------------------------------------------
3734 *
3735 * FindOp --
3736 *
3737 * Find one or more nodes based upon the pattern provided.
3738 *
3739 * Results:
3740 * A standard Tcl result. The interpreter result will contain a
3741 * list of the node serial identifiers.
3742 *
3743 *----------------------------------------------------------------------
3744 */
3745 static int
FindOp(tvPtr,interp,objc,objv)3746 FindOp(tvPtr, interp, objc, objv)
3747 TreeView *tvPtr;
3748 Tcl_Interp *interp;
3749 int objc;
3750 Tcl_Obj *CONST *objv;
3751 {
3752 TreeViewEntry *firstPtr, *lastPtr, *afterPtr;
3753 TreeViewCompareProc *compareProc;
3754 TreeViewIterProc *nextProc;
3755 int invertMatch; /* normal search mode (matching entries) */
3756 Tcl_Obj *namePattern/*, *fullPattern*/;
3757 char *string, *addTag, *withTag, *withoutTag, *curValue;
3758 register int i;
3759 Blt_List options;
3760 Blt_ListNode node;
3761 register TreeViewEntry *entryPtr;
3762 TreeViewEntry *topPtr = NULL;
3763 Tcl_Obj *listObjPtr, *objPtr, *command, *iObj;
3764 Tcl_Obj *vObj = NULL, *execObj = NULL;
3765 TreeViewColumn *columnPtr = NULL, *retColPtr = NULL;
3766 char *retPctPtr = NULL;
3767 Tcl_DString fullName, dStr, fStr;
3768 int nMatches, maxMatches, result, length, ocnt, useformat,userow, isvis;
3769 int depth, maxdepth, mindepth, mask, istree, isleaf, invis, ismap, uselabel;
3770 int isopen, isclosed, notop, nocase, isfull, cmdLen, docount, optInd, reldepth;
3771 int isnull, retLabel, isret, cmdValue;
3772 char *colStr, *keysub;
3773 Tcl_Obj *cmdObj, *cmdArgs;
3774 Tcl_Obj **aobjv;
3775 int aobjc;
3776
3777 enum optInd {
3778 OP_ADDTAG, OP_AFTER, OP_CMDARGS,
3779 OP_COMMAND, OP_COLUMN, OP_COUNT, OP_DEPTH, OP_EXACT,
3780 OP_EXEC, OP_GLOB, OP_INLIST,
3781 OP_INVERT, OP_ISCLOSED, OP_ISNULL, OP_ISHIDDEN,
3782 OP_ISLEAF, OP_ISMAPPED, OP_ISOPEN, OP_ISTREE, OP_LIMIT,
3783 OP_MAXDEPTH, OP_MINDEPTH, OP_NAME, OP_NOCASE, OP_NOTOP,
3784 OP_OPTION, OP_REGEXP, OP_RELDEPTH, OP_RETURN, OP_TOP,
3785 OP_USEFORMAT, OP_USELABEL, OP_USEPATH, OP_USEROW,
3786 OP_VAR, OP_VISIBLE, OP_WITHTAG, OP_WITHOUTTAG
3787 };
3788 static char *optArr[] = {
3789 "-addtag", "-after", "-cmdargs",
3790 "-command", "-column", "-count", "-depth", "-exact",
3791 "-exec", "-glob", "-inlist", "-invert", "-isclosed", "-isempty", "-ishidden",
3792 "-isleaf", "-ismapped", "-isopen", "-istree", "-limit",
3793 "-maxdepth", "-mindepth", "-name", "-nocase", "-notop",
3794 "-option", "-regexp", "-reldepth", "-return", "-top",
3795 "-useformat", "-uselabel", "-usepath", "-userow",
3796 "-var", "-visible", "-withtag", "-withouttag",
3797 0
3798 };
3799 isnull = retLabel = isret = 0;
3800 afterPtr = NULL;
3801 listObjPtr = NULL;
3802 invertMatch = FALSE;
3803 maxMatches = 0;
3804 namePattern = NULL;
3805 command = NULL;
3806 compareProc = ExactCompare;
3807 nextProc = Blt_TreeViewNextEntry;
3808 options = Blt_ListCreate(BLT_ONE_WORD_KEYS);
3809 withTag = withoutTag = addTag = NULL;
3810 mask = istree = isleaf = isopen = isclosed = docount = 0;
3811 depth = maxdepth = mindepth = -1;
3812 uselabel = 0, userow = 0;
3813 invis = 0, isvis = 0;
3814 ismap = 0;
3815 reldepth = notop = 0;
3816 nocase = 0, isfull = 0, useformat = 0;
3817 keysub = colStr = NULL;
3818 cmdValue = 0;
3819 curValue = NULL;
3820 cmdObj = NULL;
3821 cmdArgs = NULL;
3822
3823 entryPtr = tvPtr->rootPtr;
3824 Blt_TreeViewOptsInit(tvPtr);
3825
3826 Tcl_DStringInit(&fullName);
3827 Tcl_DStringInit(&dStr);
3828 Tcl_DStringInit(&fStr);
3829 /*
3830 * Step 1: Process flags for find operation.
3831 */
3832 for (i = 2; i < objc; i++) {
3833 string = Tcl_GetStringFromObj(objv[i], &length);
3834 if (string[0] != '-') {
3835 break;
3836 }
3837 if (length == 2 && string[0] == '-' && string[0] == '-') {
3838 break;
3839 }
3840 if (Tcl_GetIndexFromObj(interp, objv[i], optArr, "option",
3841 TCL_EXACT, &optInd) != TCL_OK) {
3842 return TCL_ERROR;
3843 }
3844 switch (optInd) {
3845 case OP_RELDEPTH:
3846 reldepth = 1;
3847 break;
3848 case OP_EXACT:
3849 compareProc = ExactCompare;
3850 break;
3851 case OP_COUNT:
3852 docount = 1;
3853 break;
3854 case OP_NOCASE:
3855 nocase = 1;
3856 break;
3857 case OP_NOTOP:
3858 notop = 1;
3859 break;
3860 case OP_USELABEL:
3861 uselabel = 1;
3862 break;
3863 case OP_USEFORMAT:
3864 useformat = 1;
3865 break;
3866 case OP_ISOPEN:
3867 isopen = 1;
3868 break;
3869 case OP_ISLEAF:
3870 isleaf = 1;
3871 break;
3872 case OP_ISTREE:
3873 istree = 1;
3874 break;
3875 case OP_USEPATH:
3876 isfull = 1;
3877 break;
3878 case OP_USEROW:
3879 userow = 1;
3880 break;
3881 case OP_ISHIDDEN:
3882 invis = 1;
3883 break;
3884 case OP_ISMAPPED:
3885 ismap = 1;
3886 break;
3887 case OP_ISNULL:
3888 isnull = 1;
3889 break;
3890 case OP_VISIBLE:
3891 mask = ENTRY_MASK;
3892 isvis = 1;
3893 break;
3894 case OP_INLIST:
3895 compareProc = InlistCompare;
3896 break;
3897 case OP_REGEXP:
3898 compareProc = RegexpCompare;
3899 break;
3900 case OP_GLOB:
3901 compareProc = GlobCompare;
3902 break;
3903 case OP_INVERT:
3904 invertMatch = TRUE;
3905 break;
3906 case OP_ISCLOSED:
3907 isclosed = 1;
3908 break;
3909
3910 /* All the rest of these take an argument. */
3911 case OP_AFTER:
3912 if (++i >= objc) { goto missingArg; }
3913 if (Blt_TreeViewGetEntry(tvPtr, objv[i], &afterPtr) != TCL_OK) {
3914 goto error;
3915 }
3916 break;
3917 case OP_VAR:
3918 if (++i >= objc) { goto missingArg; }
3919 vObj = objv[i];
3920 break;
3921 case OP_EXEC:
3922 if (++i >= objc) { goto missingArg; }
3923 execObj = objv[i];
3924 break;
3925 case OP_TOP:
3926 if (++i >= objc) { goto missingArg; }
3927 if (Blt_TreeViewGetEntry(tvPtr, objv[i], &topPtr) != TCL_OK) {
3928 goto error;
3929 }
3930 break;
3931 case OP_RETURN:
3932 isret = 1;
3933 if (++i >= objc) { goto missingArg; }
3934 if (Blt_TreeViewGetColumn(NULL, tvPtr, objv[i], &retColPtr)
3935 != TCL_OK) {
3936 if (strlen(Tcl_GetString(objv[i]))==0) {
3937 retLabel = 1;
3938 } else if ('%' == *Tcl_GetString(objv[i])) {
3939 retPctPtr = Tcl_GetString(objv[i]);
3940 } else {
3941 Tcl_AppendResult(interp, "-return is not a column or a percent subst", 0);
3942
3943 goto error;
3944 }
3945 }
3946 if (retColPtr == &tvPtr->treeColumn) {
3947 retColPtr = NULL;
3948 }
3949 break;
3950 case OP_COLUMN:
3951 if (++i >= objc) { goto missingArg; }
3952 if (Blt_TreeViewGetColumnKey(interp, tvPtr, objv[i], &columnPtr, &keysub)
3953 != TCL_OK) {
3954 goto error;
3955 }
3956 if (columnPtr == &tvPtr->treeColumn) {
3957 columnPtr = NULL;
3958 } else if (keysub) {
3959 colStr = Tcl_GetString(objv[i]);
3960 }
3961 break;
3962 case OP_NAME:
3963 if (++i >= objc) { goto missingArg; }
3964 namePattern = objv[i];
3965 break;
3966 case OP_LIMIT:
3967 if (++i >= objc) { goto missingArg; }
3968 if (Tcl_GetIntFromObj(interp, objv[i], &maxMatches) != TCL_OK) {
3969 return TCL_ERROR;
3970 }
3971 if (maxMatches < 0) {
3972 Tcl_AppendResult(interp, "bad match limit \"",
3973 Tcl_GetString(objv[i]),
3974 "\": should be a positive number", (char *)NULL);
3975 goto error;
3976 }
3977 break;
3978
3979 case OP_WITHOUTTAG:
3980 if (++i >= objc) { goto missingArg; }
3981 withoutTag = Tcl_GetString(objv[i]);
3982 break;
3983
3984 case OP_WITHTAG:
3985 if (++i >= objc) { goto missingArg; }
3986 withTag = Tcl_GetString(objv[i]);
3987 break;
3988
3989 case OP_ADDTAG:
3990 if (++i >= objc) { goto missingArg; }
3991 addTag = Tcl_GetString(objv[i]);
3992 if (TagDefine(tvPtr, interp, addTag) != TCL_OK) {
3993 goto error;
3994 }
3995 break;
3996
3997 case OP_CMDARGS:
3998 if (cmdArgs != NULL) {
3999 Tcl_AppendResult(interp, "duplicate -cmdargs", 0);
4000 goto error;
4001 }
4002 if (++i >= objc) { goto missingArg; }
4003 cmdArgs = objv[i];
4004 break;
4005 case OP_COMMAND:
4006 if (cmdObj != NULL) {
4007 Tcl_AppendResult(interp, "duplicate -command", 0);
4008 goto error;
4009 }
4010 if (++i >= objc) { goto missingArg; }
4011 cmdObj = objv[i];
4012 break;
4013
4014 case OP_DEPTH:
4015 if (++i >= objc) { goto missingArg; }
4016 if (Tcl_GetIntFromObj(interp,objv[i],&depth) != TCL_OK) {
4017 goto error;
4018 }
4019 break;
4020 case OP_MAXDEPTH:
4021 if (++i >= objc) { goto missingArg; }
4022 if (Tcl_GetIntFromObj(interp,objv[i],&maxdepth) != TCL_OK) {
4023 return TCL_OK;
4024 goto error;
4025 }
4026 break;
4027 case OP_MINDEPTH:
4028 if (++i >= objc) { goto missingArg; }
4029 if (Tcl_GetIntFromObj(interp,objv[i],&mindepth) != TCL_OK) {
4030 goto error;
4031 }
4032 break;
4033
4034 case OP_OPTION:
4035 /*
4036 * Verify that the switch is actually an entry configuration
4037 * option.
4038 */
4039 if ((i + 2) >= objc) {
4040 goto missingArg;
4041 }
4042 i++;
4043 if (Blt_ConfigureValueFromObj(interp, tvPtr->tkwin,
4044 bltTreeViewEntrySpecs, (char *)entryPtr, objv[i], 0)
4045 != TCL_OK) {
4046 Tcl_ResetResult(interp);
4047 goto error;
4048 }
4049 /* Save the option in the list of configuration options */
4050 node = Blt_ListGetNode(options, (char *)objv[i]);
4051 if (node == NULL) {
4052 node = Blt_ListCreateNode(options, (char *)objv[i]);
4053 Blt_ListAppendNode(options, node);
4054 }
4055 i++;
4056 Blt_ListSetValue(node, Tcl_GetString(objv[i]));
4057 }
4058 }
4059 if (isnull) {
4060 if (namePattern != NULL) {
4061 Tcl_AppendResult(interp, "can not use -isempty & -name", (char *)NULL);
4062 goto error;
4063 }
4064 if (columnPtr == NULL) {
4065 Tcl_AppendResult(interp, "must use -isempty with -column", (char *)NULL);
4066 goto error;
4067 }
4068 if (invertMatch) {
4069 Tcl_AppendResult(interp, "can not use -isempty & -invert", (char *)NULL);
4070 goto error;
4071 }
4072 if (isret) {
4073 Tcl_AppendResult(interp, "can not use -isempty & -return", (char *)NULL);
4074 goto error;
4075 }
4076 if (command) {
4077 Tcl_AppendResult(interp, "can not use -isempty & -command", (char *)NULL);
4078 goto error;
4079 }
4080 }
4081 if (docount && (retColPtr != NULL || retLabel)) {
4082 Tcl_AppendResult(interp, "can not use -count & -return", (char *)NULL);
4083 goto error;
4084 }
4085 if (cmdObj != NULL) {
4086 command = Tcl_DuplicateObj(cmdObj);
4087 Tcl_IncrRefCount(command);
4088 iObj = Tcl_NewIntObj(0);
4089 if (Tcl_ListObjAppendElement(interp, command, iObj) != TCL_OK) {
4090 Tcl_DecrRefCount(iObj);
4091 goto error;
4092 }
4093 Tcl_ListObjLength(interp, command, &cmdLen);
4094 aobjc = 0;
4095 if (cmdArgs != NULL) {
4096 int ai;
4097 if (Tcl_ListObjGetElements(interp, cmdArgs, &aobjc, &aobjv) != TCL_OK) {
4098 goto error;
4099 }
4100 for (ai = 0; ai < aobjc; ai++) {
4101 TreeViewColumn *sretColPtr;
4102 if (Blt_TreeViewGetColumn(interp, tvPtr, aobjv[ai], &sretColPtr) != TCL_OK) {
4103 goto error;
4104 }
4105
4106 iObj = Tcl_NewStringObj("",-1);
4107 if (Tcl_ListObjAppendElement(interp, command, iObj) != TCL_OK) {
4108 Tcl_DecrRefCount(iObj);
4109 goto error;
4110 }
4111 }
4112 }
4113 }
4114
4115 if (columnPtr) {
4116 if (namePattern && (userow|isfull)) {
4117 Tcl_AppendResult(interp, "can not use -usepath|-userow & -column", (char *)NULL);
4118 goto error;
4119 }
4120 /* if (namePattern == NULL && execObj == NULL && command == NULL) {
4121 Tcl_AppendResult(interp, "-column must use -name/-exec/-command", (char *)NULL);
4122 goto error;
4123 }*/
4124 if (uselabel) {
4125 Tcl_AppendResult(interp, "can not use -uselabel & -column", (char *)NULL);
4126 goto error;
4127 }
4128 }
4129 if (vObj != NULL) {
4130 if (execObj == NULL) {
4131 Tcl_AppendResult(interp, "must use -exec with -var", (char *)NULL);
4132 goto error;
4133 }
4134 }
4135 if (namePattern && isfull && uselabel) {
4136 Tcl_AppendResult(interp, "can not use -uselabel & -usepath", (char *)NULL);
4137 goto error;
4138 }
4139
4140 if ((objc - i) > 2) {
4141 Tcl_AppendResult(interp, "too many args", (char *)NULL);
4142 goto error;
4143 }
4144 /*
4145 * Step 2: Find the range of the search. Check the order of two
4146 * nodes and arrange the search accordingly.
4147 *
4148 * Note: Be careful to treat "end" as the end of all nodes, instead
4149 * of the end of visible nodes. That way, we can search the
4150 * entire tree, even if the last folder is closed.
4151 */
4152 if (topPtr != NULL) {
4153 firstPtr = topPtr;
4154 } else {
4155 firstPtr = tvPtr->rootPtr; /* Default to root node */
4156 }
4157 if (reldepth) {
4158 if (depth>=0) {
4159 depth += firstPtr->node->depth;
4160 }
4161 if (mindepth>=0) {
4162 mindepth += firstPtr->node->depth;
4163 }
4164 if (maxdepth>=0) {
4165 maxdepth += firstPtr->node->depth;
4166 }
4167 }
4168 lastPtr = LastEntry(tvPtr, firstPtr, 0);
4169 if (afterPtr != NULL) {
4170 TreeViewEntry *nfPtr;
4171 nfPtr = (*nextProc)(afterPtr, mask);
4172 if (nfPtr != NULL) { firstPtr = nfPtr; }
4173 }
4174
4175 if (i < objc) {
4176 string = Tcl_GetString(objv[i]);
4177 if ((string[0] == 'e') && (strcmp(string, "end") == 0)) {
4178 firstPtr = LastEntry(tvPtr, tvPtr->rootPtr, 0);
4179 } else if (Blt_TreeViewGetEntry(tvPtr, objv[i], &firstPtr) != TCL_OK) {
4180 goto error;
4181 }
4182 i++;
4183 }
4184 if (i < objc) {
4185 string = Tcl_GetString(objv[i]);
4186 if ((string[0] == 'e') && (strcmp(string, "end") == 0)) {
4187 lastPtr = LastEntry(tvPtr, tvPtr->rootPtr, 0);
4188 } else if (Blt_TreeViewGetEntry(tvPtr, objv[i], &lastPtr) != TCL_OK) {
4189 goto error;
4190 }
4191 }
4192 if (Blt_TreeIsBefore(lastPtr->node, firstPtr->node)) {
4193 nextProc = Blt_TreeViewPrevEntry;
4194 }
4195 if (notop || (mask && ((tvPtr->flags & TV_HIDE_ROOT)) && firstPtr == tvPtr->rootPtr)) {
4196 firstPtr = Blt_TreeViewNextEntry(firstPtr, mask);
4197 } else if (mask && (firstPtr->flags & mask)) {
4198 firstPtr = (*nextProc)(firstPtr, mask);
4199 }
4200 nMatches = 0;
4201
4202 /*
4203 * Step 3: Search through the tree and look for nodes that match the
4204 * current pattern specifications. Save the name of each of
4205 * the matching nodes.
4206 */
4207 if (!docount) {
4208 listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **)NULL);
4209 }
4210 for (entryPtr = firstPtr; entryPtr != NULL;
4211 entryPtr = (*nextProc) (entryPtr, mask)) {
4212
4213 if (topPtr != NULL && entryPtr != topPtr) {
4214 if (DEPTH(tvPtr, entryPtr->node) <= DEPTH(tvPtr, topPtr->node)) {
4215 break;
4216 }
4217 }
4218 if (invis && (!(entryPtr->flags & ENTRY_HIDDEN))) {
4219 goto nextEntry;
4220 }
4221
4222 if (ismap && !Blt_TreeViewEntryIsMapped(entryPtr)) {
4223 goto nextEntry;
4224 }
4225
4226 if (istree && Blt_TreeViewIsLeaf(entryPtr)) {
4227 goto nextEntry;
4228 }
4229 if (isleaf && !Blt_TreeViewIsLeaf(entryPtr)) {
4230 goto nextEntry;
4231 }
4232 if (depth >=0 && entryPtr->node && entryPtr->node->depth != depth) {
4233 goto nextEntry;
4234 }
4235 if (maxdepth >=0 && entryPtr->node && entryPtr->node->depth > maxdepth) {
4236 goto nextEntry;
4237 }
4238 if (mindepth >=0 && entryPtr->node && entryPtr->node->depth < mindepth) {
4239 goto nextEntry;
4240 }
4241 if (isopen && ((entryPtr->flags & ENTRY_CLOSED) != 0)) {
4242 goto nextEntry;
4243 }
4244 if (isclosed && ((entryPtr->flags & ENTRY_CLOSED) == 0)) {
4245 goto nextEntry;
4246 }
4247
4248 if (columnPtr) {
4249 TreeViewValue *valuePtr;
4250 if (useformat &&
4251 ((valuePtr = Blt_TreeViewFindValue(entryPtr, columnPtr))) &&
4252 valuePtr->textPtr) {
4253 Blt_TextLayoutValue( valuePtr->textPtr, &dStr);
4254 curValue = Tcl_DStringValue(&dStr);
4255
4256 } else {
4257 if (colStr != NULL) {
4258 if (Blt_TreeGetValue(NULL, tvPtr->tree, entryPtr->node,
4259 colStr, &objPtr) != TCL_OK) {
4260 if (!isnull) {
4261 goto nextEntry;
4262 } else {
4263 goto dochecks;
4264 }
4265 } else if (isnull) {
4266 goto nextEntry;
4267 }
4268 } else if (Blt_TreeGetValueByKey(NULL, tvPtr->tree, entryPtr->node,
4269 columnPtr->key, &objPtr) != TCL_OK) {
4270 if (!isnull) {
4271 goto nextEntry;
4272 } else {
4273 goto dochecks;
4274 }
4275 } else if (isnull) {
4276 goto nextEntry;
4277 }
4278 curValue = Tcl_GetString(objPtr);
4279 }
4280 } else if (useformat && entryPtr->textPtr != NULL) {
4281 Blt_TextLayoutValue( entryPtr->textPtr, &dStr);
4282 curValue = Tcl_DStringValue(&dStr);
4283 } else if (uselabel && entryPtr->labelUid != NULL) {
4284 curValue = entryPtr->labelUid;
4285 } else {
4286 curValue = Blt_TreeNodeLabel(entryPtr->node);
4287 }
4288 if (namePattern != NULL) {
4289 if (userow) {
4290 Blt_ChainLink *linkPtr;
4291 TreeViewColumn *colPtr;
4292
4293 Tcl_DStringSetLength(&fStr,0);
4294 for (linkPtr = Blt_ChainFirstLink(tvPtr->colChainPtr);
4295 linkPtr != NULL;
4296 linkPtr = Blt_ChainNextLink(linkPtr)) {
4297 colPtr = Blt_ChainGetValue(linkPtr);
4298 if (colPtr->hidden && (isvis)) continue;
4299 if (colPtr == &tvPtr->treeColumn) {
4300 Tcl_DStringAppend(&fStr, curValue, -1);
4301 continue;
4302 }
4303 if (Blt_TreeGetValue(tvPtr->interp, tvPtr->tree,
4304 entryPtr->node, colPtr->key, &objPtr) == TCL_OK) {
4305 Tcl_DStringAppend(&fStr, " ", -1);
4306 Tcl_DStringAppend(&fStr, Tcl_GetString(objPtr), -1);
4307 }
4308 }
4309
4310 curValue = Tcl_DStringValue(&fStr);
4311 result = (*compareProc) (interp, curValue, namePattern, nocase);
4312 } else if (isfull == 0) {
4313 result = (*compareProc)(interp, curValue, namePattern, nocase);
4314 } else {
4315 curValue = Blt_TreeViewGetFullName(tvPtr, entryPtr, FALSE, &fullName);
4316 result = (*compareProc) (interp, curValue, namePattern, nocase);
4317 }
4318 if (result == invertMatch) {
4319 goto nextEntry; /* Failed to match */
4320 }
4321 }
4322 dochecks:
4323 if (withTag != NULL) {
4324 result = Blt_TreeHasTag(tvPtr->tree, entryPtr->node, withTag);
4325 if (!result) {
4326 goto nextEntry; /* Failed to match */
4327 }
4328 }
4329 if (withoutTag != NULL) {
4330 result = Blt_TreeHasTag(tvPtr->tree, entryPtr->node, withoutTag);
4331 if (result) {
4332 goto nextEntry; /* Failed to match */
4333 }
4334 }
4335 Blt_TreeViewOptsInit(tvPtr);
4336 ocnt = 0;
4337 for (node = Blt_ListFirstNode(options); node != NULL;
4338 node = Blt_ListNextNode(node)) {
4339 Tcl_Obj *kPtr;
4340 ocnt++;
4341 kPtr = (Tcl_Obj *)Blt_ListGetKey(node);
4342 Tcl_ResetResult(interp);
4343 Blt_ConfigureValueFromObj(interp, tvPtr->tkwin,
4344 bltTreeViewEntrySpecs, (char *)entryPtr, kPtr, 0);
4345 Blt_TreeViewOptsInit(tvPtr);
4346 objPtr = Tcl_GetObjResult(interp);
4347 result = (*compareProc) (interp, Tcl_GetString(objPtr), kPtr, nocase);
4348 if (result == invertMatch) {
4349 break;
4350 }
4351 }
4352 if (ocnt && result == invertMatch) {
4353 goto nextEntry; /* Failed to match */
4354 }
4355 /*
4356 * Someone may actually delete the current node in the "exec"
4357 * callback. Preserve the entry.
4358 */
4359 Tcl_Preserve(entryPtr);
4360 if (execObj != NULL) {
4361 if (vObj != NULL) {
4362 Tcl_Obj *intObj;
4363 intObj = Tcl_NewIntObj(Blt_TreeNodeId(entryPtr->node));
4364 Tcl_IncrRefCount(intObj);
4365 if (Tcl_ObjSetVar2(interp, vObj, NULL, intObj, 0) == NULL) {
4366 Tcl_DecrRefCount(intObj);
4367 goto error;
4368 }
4369 Tcl_DecrRefCount(intObj);
4370 result = Tcl_EvalObjEx(interp, execObj, 0);
4371 } else {
4372 Tcl_DString cmdString;
4373
4374 Tcl_DStringFree(&cmdString);
4375 Blt_TreeViewPercentSubst(tvPtr, entryPtr, NULL, Tcl_GetString(execObj), curValue, &cmdString);
4376 result = Tcl_GlobalEval(interp, Tcl_DStringValue(&cmdString));
4377 Tcl_DStringFree(&cmdString);
4378 }
4379 if ((entryPtr->flags & ENTRY_DELETED) || (tvPtr->flags & TV_DELETED)) {
4380 Tcl_Release(entryPtr);
4381 goto error;
4382 }
4383 Blt_TreeViewOptsInit(tvPtr);
4384 if (result == TCL_CONTINUE) {
4385 Tcl_Release(entryPtr);
4386 goto nextEntry;
4387 }
4388 if (result != TCL_OK) {
4389 Tcl_Release(entryPtr);
4390 goto error;
4391 }
4392 if (!docount) {
4393 Tcl_ListObjAppendElement(interp, listObjPtr, Tcl_GetObjResult(interp));
4394 }
4395 goto finishnode;
4396 }
4397 if (command != NULL) {
4398 Tcl_Obj **cobjv;
4399 int cobjc, ai;
4400
4401 iObj = Tcl_NewIntObj(Blt_TreeNodeId(entryPtr->node));
4402 if (Tcl_ListObjReplace(interp, command, cmdLen-1, 1, 1, &iObj) != TCL_OK) {
4403 Tcl_Release(entryPtr);
4404 goto error;
4405 }
4406 for (ai = 0; ai < aobjc; ai++) {
4407 if (Blt_TreeGetValue(NULL, tvPtr->tree, entryPtr->node,
4408 Tcl_GetString(aobjv[ai]), &iObj) != TCL_OK) {
4409 iObj = Tcl_NewStringObj("", 0);
4410 }
4411 if (Tcl_ListObjReplace(interp, command, cmdLen+ai, 1, 1, &iObj) != TCL_OK) {
4412 Tcl_Release(entryPtr);
4413 goto error;
4414 }
4415 }
4416 if (Tcl_ListObjGetElements(interp, command, &cobjc, &cobjv) != TCL_OK) {
4417 Tcl_Release(entryPtr);
4418 goto error;
4419 }
4420 result = Tcl_EvalObjv(interp, cobjc, cobjv, 0);
4421 if ((entryPtr->flags & ENTRY_DELETED) || (tvPtr->flags & TV_DELETED)) {
4422 result = TCL_ERROR;
4423 } else if (result == TCL_RETURN) {
4424 int eRes;
4425 if (Tcl_GetIntFromObj(interp, Tcl_GetObjResult(interp),
4426 &eRes) != TCL_OK) {
4427 result = TCL_ERROR;
4428 goto error;
4429 }
4430 result = TCL_OK;
4431 if (eRes != 0) {
4432 if (!docount) {
4433 objPtr = NodeToObj(entryPtr->node);
4434 Tcl_ListObjAppendElement(interp, listObjPtr, objPtr);
4435 }
4436 goto finishnode;
4437 } else {
4438 goto nextEntry;
4439 }
4440 }
4441
4442 if (result != TCL_OK) {
4443 Tcl_Release(entryPtr);
4444 goto error;
4445 }
4446 goto finishnode;
4447 }
4448 /* A NULL node reference in an entry indicates that the entry
4449 * was deleted, but its memory not released yet. */
4450 if (entryPtr->node != NULL) {
4451 if (retLabel) {
4452 objPtr = Tcl_NewStringObj(Blt_TreeNodeLabel(entryPtr->node), -1);
4453 } else if (retColPtr != NULL) {
4454 if (Blt_TreeViewGetData(entryPtr, retColPtr->key, &objPtr)
4455 != TCL_OK) {
4456 objPtr = Tcl_NewStringObj("", -1);
4457 }
4458 } else if (retPctPtr != NULL) {
4459 Tcl_DString cmdString;
4460
4461 Tcl_DStringInit(&cmdString);
4462
4463 Blt_TreeViewPercentSubst(tvPtr, entryPtr, columnPtr, retPctPtr, curValue, &cmdString);
4464 objPtr = Tcl_NewStringObj(Tcl_DStringValue(&cmdString), -1);
4465 Tcl_DStringFree(&cmdString);
4466
4467 } else {
4468 /* Finally, save the matching node name. */
4469 objPtr = NodeToObj(entryPtr->node);
4470 }
4471 if (!docount) {
4472 Tcl_ListObjAppendElement(interp, listObjPtr, objPtr);
4473 }
4474 if (addTag != NULL) {
4475 if (AddTag(tvPtr, entryPtr->node, addTag) != TCL_OK) {
4476 Tcl_Release(entryPtr);
4477 goto error;
4478 }
4479 }
4480 }
4481 finishnode:
4482 Tcl_Release(entryPtr);
4483 nMatches++;
4484 if ((nMatches == maxMatches) && (maxMatches > 0)) {
4485 break;
4486 }
4487 nextEntry:
4488 if (entryPtr == lastPtr) {
4489 break;
4490 }
4491 }
4492 if (command != NULL) {
4493 Tcl_DecrRefCount(command);
4494 }
4495 Tcl_ResetResult(interp);
4496 Blt_ListDestroy(options);
4497 if (docount) {
4498 Tcl_SetObjResult(interp, Tcl_NewIntObj(nMatches));
4499 } else {
4500 Tcl_SetObjResult(interp, listObjPtr);
4501 }
4502 Tcl_DStringFree(&fStr);
4503 Tcl_DStringFree(&dStr);
4504 Tcl_DStringFree(&fullName);
4505 return TCL_OK;
4506
4507 missingArg:
4508 if (command != NULL) {
4509 Tcl_DecrRefCount(command);
4510 }
4511 Tcl_AppendResult(interp, "missing argument for find option \"",
4512 Tcl_GetString(objv[i]), "\"", (char *)NULL);
4513 error:
4514 if (listObjPtr != NULL) {
4515 Tcl_DecrRefCount(listObjPtr);
4516 }
4517 Tcl_DStringFree(&fStr);
4518 Tcl_DStringFree(&dStr);
4519 Tcl_DStringFree(&fullName);
4520 Blt_ListDestroy(options);
4521 return TCL_ERROR;
4522 }
4523
4524
4525 /*
4526 *----------------------------------------------------------------------
4527 *
4528 * GetOp --
4529 *
4530 * Converts one or more node identifiers to its path component.
4531 * The path may be either the single entry name or the full path
4532 * of the entry.
4533 *
4534 * Results:
4535 * A standard Tcl result. The interpreter result will contain a
4536 * list of the convert names.
4537 *
4538 *----------------------------------------------------------------------
4539 */
4540 static int
GetOp(tvPtr,interp,objc,objv)4541 GetOp(tvPtr, interp, objc, objv)
4542 TreeView *tvPtr;
4543 Tcl_Interp *interp;
4544 int objc;
4545 Tcl_Obj *CONST *objv;
4546 {
4547 TreeViewTagInfo info = {0};
4548 TreeViewEntry *entryPtr;
4549 int useFullName;
4550 int useLabels = 0;
4551 register int i;
4552 Tcl_DString dString1, dString2;
4553 int count, single;
4554 char *string;
4555
4556 useFullName = FALSE;
4557 while (objc > 2) {
4558
4559 string = Tcl_GetString(objv[2]);
4560 if ((string[0] == '-') && (strcmp(string, "-full") == 0)) {
4561 useFullName = TRUE;
4562 objv++, objc--;
4563 } else if ((string[0] == '-') && (strcmp(string, "-labels") == 0)) {
4564 useFullName = TRUE;
4565 useLabels = TRUE;
4566 objv++, objc--;
4567 } else {
4568 break;
4569 }
4570 }
4571 Tcl_DStringInit(&dString1);
4572 Tcl_DStringInit(&dString2);
4573 single = 0;
4574 count = 0;
4575 for (i = 2; i < objc; i++) {
4576 if (Blt_TreeViewFindTaggedEntries(tvPtr, objv[i], &info) != TCL_OK) {
4577 Tcl_DStringFree(&dString1);
4578 Tcl_DStringFree(&dString2);
4579 return TCL_ERROR;
4580 }
4581 if (i==2 && objc<=3) {
4582 string = Tcl_GetString(objv[2]);
4583 single = (isdigit(UCHAR(string[0])) && strchr(string,' ')==NULL);
4584 } else {
4585 single = 0;
4586 }
4587
4588 for (entryPtr = Blt_TreeViewFirstTaggedEntry(&info); entryPtr != NULL;
4589 entryPtr = Blt_TreeViewNextTaggedEntry(&info)) {
4590 Tcl_DStringSetLength(&dString2, 0);
4591 count++;
4592 if (entryPtr->node == NULL) {
4593 Tcl_DStringAppendElement(&dString1, "");
4594 continue;
4595 }
4596 if (useFullName) {
4597 Blt_TreeViewGetFullName(tvPtr, entryPtr, useLabels, &dString2);
4598 Tcl_DStringAppendElement(&dString1,
4599 Tcl_DStringValue(&dString2));
4600 } else {
4601 if (single && count == 1) {
4602 Tcl_DStringAppend(&dString2,
4603 Blt_TreeNodeLabel(entryPtr->node), -1);
4604 }
4605 Tcl_DStringAppendElement(&dString1,
4606 Blt_TreeNodeLabel(entryPtr->node));
4607 }
4608 }
4609 Blt_TreeViewDoneTaggedEntries(&info);
4610 }
4611 /* This handles the single element list problem. */
4612 if (count == 1 && single) {
4613 Tcl_DStringResult(interp, &dString2);
4614 Tcl_DStringFree(&dString1);
4615 } else {
4616 Tcl_DStringResult(interp, &dString1);
4617 Tcl_DStringFree(&dString2);
4618 }
4619 return TCL_OK;
4620 }
4621
4622 /*
4623 *----------------------------------------------------------------------
4624 *
4625 * SearchAndApplyToTree --
4626 *
4627 * Searches through the current tree and applies a procedure
4628 * to matching nodes. The search specification is taken from
4629 * the following command-line arguments:
4630 *
4631 * ?-exact? ?-glob? ?-regexp? ?-invert?
4632 * ?-data string?
4633 * ?-name string?
4634 * ?-path?
4635 * ?-depth N?
4636 * ?-mindepth N?
4637 * ?-maxdepth N?
4638 * ?--?
4639 * ?inode...?
4640 *
4641 * Results:
4642 * A standard Tcl result. If the result is valid, and if the
4643 * nonmatchPtr is specified, it returns a boolean value
4644 * indicating whether or not the search was inverted. This
4645 * is needed to fix things properly for the "hide invert"
4646 * case.
4647 *
4648 *----------------------------------------------------------------------
4649 */
4650
4651 static int
SearchAndApplyToTree(tvPtr,interp,objc,objv,proc,nonMatchPtr)4652 SearchAndApplyToTree(tvPtr, interp, objc, objv, proc, nonMatchPtr)
4653 TreeView *tvPtr;
4654 Tcl_Interp *interp;
4655 int objc;
4656 Tcl_Obj *CONST *objv;
4657 TreeViewApplyProc *proc;
4658 int *nonMatchPtr; /* returns: inverted search indicator */
4659 {
4660 TreeViewCompareProc *compareProc;
4661 int invertMatch; /* normal search mode (matching entries) */
4662 Tcl_Obj *namePattern;
4663 register int i;
4664 int length, depth = -1, maxdepth = -1, mindepth = -1, noArgs, usefull = 0;
4665 int result, nocase, uselabel = 0, optInd, ocnt;
4666 char *pattern, *curValue;
4667 Blt_List options;
4668 TreeViewEntry *entryPtr;
4669 register Blt_ListNode node;
4670 char *string, *colStr = NULL, *keysub = NULL;
4671 char *withTag, *withoutTag;
4672 Tcl_Obj *objPtr;
4673 TreeViewTagInfo info = {0};
4674 TreeViewColumn *columnPtr;
4675 Tcl_DString fullName;
4676
4677 enum optInd {
4678 OP_COLUMN, OP_DEPTH, OP_EXACT, OP_GLOB, OP_INLIST, OP_INVERT,
4679 OP_MAXDEPTH, OP_MINDEPTH, OP_NAME, OP_NOCASE, OP_OPTION,
4680 OP_REGEXP, OP_USELABEL, OP_USEPATH,
4681 OP_WITHTAG, OP_WITHOUTTAG
4682 };
4683 static char *optArr[] = {
4684 "-column", "-depth", "-exact", "-glob", "-inlist", "-invert",
4685 "-maxdepth", "-mindepth", "-name", "-nocase", "-option",
4686 "-regexp", "-uselabel", "-usepath",
4687 "-withtag", "-withouttag",
4688 0
4689 };
4690
4691
4692 Tcl_DStringInit(&fullName);
4693
4694 options = Blt_ListCreate(BLT_ONE_WORD_KEYS);
4695 invertMatch = FALSE;
4696 namePattern = NULL;
4697 compareProc = ExactCompare;
4698 withTag = NULL;
4699 withoutTag = NULL;
4700 columnPtr = NULL;
4701 nocase = 0;
4702
4703 entryPtr = tvPtr->rootPtr;
4704 for (i = 2; i < objc; i++) {
4705 string = Tcl_GetStringFromObj(objv[i], &length);
4706 if (string[0] != '-') {
4707 break;
4708 }
4709 if (length == 2 && string[0] == '-' && string[0] == '-') {
4710 break;
4711 }
4712 if (Tcl_GetIndexFromObj(interp, objv[i], optArr, "option",
4713 0, &optInd) != TCL_OK) {
4714 return TCL_ERROR;
4715 }
4716 switch (optInd) {
4717 case OP_EXACT:
4718 compareProc = ExactCompare;
4719 break;
4720 case OP_NOCASE:
4721 nocase = 1;
4722 break;
4723 case OP_USELABEL:
4724 uselabel = 1;
4725 break;
4726 case OP_USEPATH:
4727 usefull = 1;
4728 break;
4729 case OP_REGEXP:
4730 compareProc = RegexpCompare;
4731 break;
4732 case OP_INLIST:
4733 compareProc = InlistCompare;
4734 break;
4735 case OP_GLOB:
4736 compareProc = GlobCompare;
4737 break;
4738 case OP_INVERT:
4739 invertMatch = TRUE;
4740 break;
4741
4742 /* All the rest of these take arguments. */
4743 case OP_COLUMN:
4744 if (++i >= objc) { goto missingArg; }
4745 if (Blt_TreeViewGetColumnKey(interp, tvPtr, objv[i], &columnPtr, &keysub)
4746 != TCL_OK) {
4747 goto error;
4748 }
4749 if (columnPtr == &tvPtr->treeColumn) {
4750 columnPtr = NULL;
4751 } else if (keysub) {
4752 colStr = Tcl_GetString(objv[i]);
4753 }
4754 break;
4755
4756 case OP_NAME:
4757 if (++i >= objc) { goto missingArg; }
4758 namePattern = objv[i];
4759 break;
4760
4761 case OP_WITHOUTTAG:
4762 if (++i >= objc) { goto missingArg; }
4763 withoutTag = Tcl_GetString(objv[i]);
4764 break;
4765
4766 case OP_WITHTAG:
4767 if (++i >= objc) { goto missingArg; }
4768 withTag = Tcl_GetString(objv[i]);
4769 break;
4770
4771 case OP_DEPTH:
4772 if (++i >= objc) { goto missingArg; }
4773 if (Tcl_GetIntFromObj(interp,objv[i],&depth) != TCL_OK) {
4774 goto error;
4775 }
4776 break;
4777 case OP_MAXDEPTH:
4778 if (++i >= objc) { goto missingArg; }
4779 if (Tcl_GetIntFromObj(interp,objv[i],&maxdepth) != TCL_OK) {
4780 return TCL_OK;
4781 goto error;
4782 }
4783 break;
4784 case OP_MINDEPTH:
4785 if (++i >= objc) { goto missingArg; }
4786 if (Tcl_GetIntFromObj(interp,objv[i],&mindepth) != TCL_OK) {
4787 goto error;
4788 }
4789 break;
4790
4791 case OP_OPTION:
4792 /*
4793 * Verify that the switch is actually an entry configuration
4794 * option.
4795 */
4796 if ((i + 2) >= objc) {
4797 goto missingArg;
4798 }
4799 i++;
4800 if (Blt_ConfigureValueFromObj(interp, tvPtr->tkwin,
4801 bltTreeViewEntrySpecs, (char *)entryPtr, objv[i], 0)
4802 != TCL_OK) {
4803 Tcl_ResetResult(interp);
4804 goto error;
4805 }
4806 /* Save the option in the list of configuration options */
4807 node = Blt_ListGetNode(options, (char *)objv[i]);
4808 if (node == NULL) {
4809 node = Blt_ListCreateNode(options, (char *)objv[i]);
4810 Blt_ListAppendNode(options, node);
4811 }
4812 i++;
4813 Blt_ListSetValue(node, Tcl_GetString(objv[i]));
4814 }
4815 }
4816
4817 noArgs = (i >= objc);
4818 if (columnPtr) {
4819 if (!namePattern) {
4820 Tcl_AppendResult(interp, "must use -name with -column", (char *)NULL);
4821 goto error;
4822 }
4823 if (namePattern && usefull) {
4824 Tcl_AppendResult(interp, "can not use -usepath & -column", (char *)NULL);
4825 goto error;
4826 }
4827 if (uselabel) {
4828 Tcl_AppendResult(interp, "can not use -uselabel & -column", (char *)NULL);
4829 goto error;
4830 }
4831 }
4832 if (namePattern && usefull && uselabel) {
4833 Tcl_AppendResult(interp, "can not use -uselabel & -usepath", (char *)NULL);
4834 goto error;
4835 }
4836
4837 for ( ;; i++) {
4838 if (noArgs) {
4839 if (i>objc) break;
4840 info.entryPtr = tvPtr->rootPtr;
4841 info.tagType = TAG_ALL;
4842 info.node = info.entryPtr->node;
4843 } else {
4844 if (i>=objc) break;
4845 if (Blt_TreeViewFindTaggedEntries(tvPtr, objv[i], &info) != TCL_OK) {
4846 goto error;
4847 }
4848 }
4849 for (entryPtr = Blt_TreeViewFirstTaggedEntry(&info); entryPtr != NULL;
4850 entryPtr = Blt_TreeViewNextTaggedEntry(&info)) {
4851
4852 if (entryPtr == tvPtr->rootPtr && (info.tagType & TAG_ALL)) {
4853 entryPtr = Blt_TreeViewNextTaggedEntry(&info);
4854 if (entryPtr == NULL) break;
4855 }
4856 if (depth >=0 && entryPtr->node && entryPtr->node->depth != depth) {
4857 continue;
4858 }
4859 if (maxdepth >=0 && entryPtr->node && entryPtr->node->depth > maxdepth) {
4860 continue;
4861 }
4862 if (mindepth >=0 && entryPtr->node && entryPtr->node->depth < mindepth) {
4863 continue;
4864 }
4865 if (columnPtr) {
4866 if (colStr) {
4867 if (Blt_TreeGetValue(NULL, tvPtr->tree, entryPtr->node, colStr,
4868 &objPtr) != TCL_OK)
4869 continue;
4870 } else if (Blt_TreeGetValueByKey(NULL, tvPtr->tree, entryPtr->node,
4871 columnPtr->key, &objPtr) != TCL_OK) {
4872 continue;
4873 }
4874
4875 curValue = Tcl_GetString(objPtr);
4876 } else if (uselabel && entryPtr->labelUid != NULL) {
4877 curValue = entryPtr->labelUid;
4878 } else {
4879 curValue = Blt_TreeNodeLabel(entryPtr->node);
4880 }
4881 if (namePattern != NULL) {
4882 if (usefull == 0) {
4883 result = (*compareProc) (interp, curValue, namePattern, nocase);
4884 if (result == invertMatch) {
4885 continue; /* Failed to match */
4886 }
4887 } else {
4888 Blt_TreeViewGetFullName(tvPtr, entryPtr, FALSE, &fullName);
4889 result = (*compareProc) (interp, Tcl_DStringValue(&fullName),
4890 namePattern, nocase);
4891 if (result == invertMatch) {
4892 continue; /* Failed to match */
4893 }
4894 }
4895 }
4896 if (withTag != NULL) {
4897 result = Blt_TreeHasTag(tvPtr->tree, entryPtr->node, withTag);
4898 if (!result) {
4899 continue; /* Failed to match */
4900 }
4901 }
4902 if (withoutTag != NULL) {
4903 result = Blt_TreeHasTag(tvPtr->tree, entryPtr->node, withoutTag);
4904 if (result) {
4905 continue; /* Failed to match */
4906 }
4907 }
4908 ocnt = 0;
4909 for (node = Blt_ListFirstNode(options); node != NULL;
4910 node = Blt_ListNextNode(node)) {
4911 Tcl_Obj *kPtr;
4912 ocnt++;
4913 kPtr = (Tcl_Obj *)Blt_ListGetKey(node);
4914 Tcl_ResetResult(interp);
4915 Blt_TreeViewOptsInit(tvPtr);
4916 if (Blt_ConfigureValueFromObj(interp, tvPtr->tkwin,
4917 bltTreeViewEntrySpecs, (char *)entryPtr, kPtr, 0)
4918 != TCL_OK) {
4919 goto error; /* This shouldn't happen. */
4920 }
4921 pattern = Blt_ListGetValue(node);
4922 objPtr = Tcl_GetObjResult(interp);
4923 result = (*compareProc)(interp, Tcl_GetString(objPtr), kPtr, nocase);
4924 if (result == invertMatch) {
4925 break; /* Failed to match */
4926 }
4927 }
4928 /* if (result == invertMatch) {
4929 continue;
4930 }*/
4931 /* Finally, apply the procedure to the node */
4932 (*proc) (tvPtr, entryPtr);
4933 }
4934 Blt_TreeViewDoneTaggedEntries(&info);
4935 Tcl_ResetResult(interp);
4936 }
4937 if (nonMatchPtr != NULL) {
4938 *nonMatchPtr = invertMatch; /* return "inverted search" status */
4939 }
4940 Blt_ListDestroy(options);
4941 Tcl_DStringFree(&fullName);
4942 return TCL_OK;
4943
4944 missingArg:
4945 Tcl_AppendResult(interp, "missing pattern for search option \"",
4946 Tcl_GetString(objv[i]), "\"", (char *)NULL);
4947 error:
4948 Blt_TreeViewDoneTaggedEntries(&info);
4949 Tcl_DStringFree(&fullName);
4950 Blt_ListDestroy(options);
4951 return TCL_ERROR;
4952
4953 }
4954
4955 static int
FixSelectionsApplyProc(tvPtr,entryPtr)4956 FixSelectionsApplyProc(tvPtr, entryPtr)
4957 TreeView *tvPtr;
4958 TreeViewEntry *entryPtr;
4959 {
4960 if (entryPtr->flags & ENTRY_HIDDEN) {
4961 Blt_TreeViewDeselectEntry(tvPtr, entryPtr, NULL);
4962 if ((tvPtr->focusPtr != NULL) &&
4963 (Blt_TreeIsAncestor(entryPtr->node, tvPtr->focusPtr->node))) {
4964 if (entryPtr != tvPtr->rootPtr) {
4965 entryPtr = Blt_TreeViewParentEntry(entryPtr);
4966 tvPtr->focusPtr = (entryPtr == NULL)
4967 ? tvPtr->focusPtr : entryPtr;
4968 Blt_SetFocusItem(tvPtr->bindTable, tvPtr->focusPtr, ITEM_ENTRY);
4969 }
4970 }
4971 if ((tvPtr->selAnchorPtr != NULL) &&
4972 (Blt_TreeIsAncestor(entryPtr->node, tvPtr->selAnchorPtr->node))) {
4973 tvPtr->selMarkPtr = tvPtr->selAnchorPtr = NULL;
4974 }
4975 if ((tvPtr->activePtr != NULL) &&
4976 (Blt_TreeIsAncestor(entryPtr->node, tvPtr->activePtr->node))) {
4977 tvPtr->activePtr = NULL;
4978 }
4979 Blt_TreeViewPruneSelection(tvPtr, entryPtr);
4980 }
4981 return TCL_OK;
4982 }
4983
4984 /*
4985 *----------------------------------------------------------------------
4986 *
4987 * HideOp --
4988 *
4989 * Hides one or more nodes. Nodes can be specified by their
4990 * inode, or by matching a name or data value pattern. By
4991 * default, the patterns are matched exactly. They can also
4992 * be matched using glob-style and regular expression rules.
4993 *
4994 * Results:
4995 * A standard Tcl result.
4996 *
4997 *----------------------------------------------------------------------
4998 */
4999 static int
HideOp(tvPtr,interp,objc,objv)5000 HideOp(tvPtr, interp, objc, objv)
5001 TreeView *tvPtr;
5002 Tcl_Interp *interp;
5003 int objc;
5004 Tcl_Obj *CONST *objv;
5005 {
5006 int status, nonmatching;
5007
5008 status = SearchAndApplyToTree(tvPtr, interp, objc, objv,
5009 HideEntryApplyProc, &nonmatching);
5010
5011 if (status != TCL_OK) {
5012 return TCL_ERROR;
5013 }
5014 /*
5015 * If this was an inverted search, scan back through the
5016 * tree and make sure that the parents for all visible
5017 * nodes are also visible. After all, if a node is supposed
5018 * to be visible, its parent can't be hidden.
5019 */
5020 if (nonmatching) {
5021 Blt_TreeViewApply(tvPtr, tvPtr->rootPtr, MapAncestorsApplyProc, 0);
5022 }
5023 /*
5024 * Make sure that selections are cleared from any hidden
5025 * nodes. This wasn't done earlier--we had to delay it until
5026 * we fixed the visibility status for the parents.
5027 */
5028 Blt_TreeViewApply(tvPtr, tvPtr->rootPtr, FixSelectionsApplyProc, 0);
5029
5030 /* Hiding an entry only effects the visible nodes. */
5031 tvPtr->flags |= (TV_LAYOUT | TV_SCROLL | TV_UPDATE | TV_RESORT);
5032 Blt_TreeViewEventuallyRedraw(tvPtr);
5033 return TCL_OK;
5034 }
5035
5036 /*
5037 *----------------------------------------------------------------------
5038 *
5039 * ShowOp --
5040 *
5041 * Mark one or more nodes to be exposed. Nodes can be specified
5042 * by their inode, or by matching a name or data value pattern. By
5043 * default, the patterns are matched exactly. They can also
5044 * be matched using glob-style and regular expression rules.
5045 *
5046 * Results:
5047 * A standard Tcl result.
5048 *
5049 *----------------------------------------------------------------------
5050 */
5051 static int
ShowOp(tvPtr,interp,objc,objv)5052 ShowOp(tvPtr, interp, objc, objv)
5053 TreeView *tvPtr;
5054 Tcl_Interp *interp;
5055 int objc;
5056 Tcl_Obj *CONST *objv;
5057 {
5058 if (SearchAndApplyToTree(tvPtr, interp, objc, objv, ShowEntryApplyProc,
5059 (int *)NULL) != TCL_OK) {
5060 return TCL_ERROR;
5061 }
5062 tvPtr->flags |= (TV_LAYOUT | TV_SCROLL | TV_UPDATE|TV_RESORT);
5063 Blt_TreeViewEventuallyRedraw(tvPtr);
5064 return TCL_OK;
5065 }
5066
5067 /*
5068 *----------------------------------------------------------------------
5069 *
5070 * IndexOp --
5071 *
5072 * Converts one of more words representing indices of the entries
5073 * in the treeview widget to their respective serial identifiers.
5074 *
5075 * Results:
5076 * A standard Tcl result. Interp->result will contain the
5077 * identifier of each inode found. If an inode could not be found,
5078 * then the serial identifier will be the empty string.
5079 *
5080 *----------------------------------------------------------------------
5081 */
5082 /*ARGSUSED*/
5083 static int
IndexOp(tvPtr,interp,objc,objv)5084 IndexOp(tvPtr, interp, objc, objv)
5085 TreeView *tvPtr;
5086 Tcl_Interp *interp;
5087 int objc; /* Not used. */
5088 Tcl_Obj *CONST *objv;
5089 {
5090 TreeViewEntry *entryPtr;
5091 char *string;
5092 TreeViewEntry *fromPtr;
5093 int usePath, quiet;
5094
5095 quiet = FALSE;
5096 usePath = FALSE;
5097 fromPtr = NULL;
5098 string = Tcl_GetString(objv[2]);
5099 while (string[0] == '-' && objc>3) {
5100 if ((strcmp(string, "-path") == 0)) {
5101 usePath = TRUE;
5102 objv++, objc--;
5103 } else if ((strcmp(string, "-quiet") == 0)) {
5104 quiet = TRUE;
5105 objv++, objc--;
5106 } else if ((strcmp(string, "-at") == 0)) {
5107 if (Blt_TreeViewGetEntry(tvPtr, objv[3], &fromPtr) != TCL_OK) {
5108 return TCL_ERROR;
5109 }
5110 objv += 2, objc -= 2;
5111 } else {
5112 break;
5113 }
5114 string = Tcl_GetString(objv[2]);
5115 }
5116 if (objc != 3) {
5117 Tcl_AppendResult(interp, "wrong # args: should be \"",
5118 Tcl_GetString(objv[0]),
5119 " ?-at tagOrId? ?-path? ?-quiet? index\"",
5120 (char *)NULL);
5121 return TCL_ERROR;
5122 }
5123 tvPtr->fromPtr = fromPtr;
5124 if (usePath) {
5125 if (fromPtr == NULL) {
5126 fromPtr = tvPtr->rootPtr;
5127 }
5128 string = Tcl_GetString(objv[2]);
5129 entryPtr = FindPath(tvPtr, fromPtr, string);
5130 if (entryPtr != NULL) {
5131 Tcl_SetObjResult(interp, NodeToObj(entryPtr->node));
5132 } else if (quiet) {
5133 Tcl_ResetResult(interp);
5134 return TCL_OK;
5135 } else {
5136 return TCL_ERROR;
5137 }
5138 } else {
5139 if (tvPtr->fromPtr == NULL) {
5140 tvPtr->fromPtr = tvPtr->focusPtr;
5141 }
5142 if (tvPtr->fromPtr == NULL) {
5143 tvPtr->fromPtr = tvPtr->rootPtr;
5144 }
5145 if ((GetEntryFromObj2(tvPtr, objv[2], &entryPtr) == TCL_OK)) {
5146 if (entryPtr != NULL && entryPtr->node != NULL) {
5147 Tcl_SetObjResult(interp, NodeToObj(entryPtr->node));
5148 }
5149 } else if (quiet) {
5150 Tcl_ResetResult(interp);
5151 return TCL_OK;
5152 } else {
5153 return TCL_ERROR;
5154 }
5155 }
5156 return TCL_OK;
5157 }
5158
5159 /*
5160 *----------------------------------------------------------------------
5161 *
5162 * InsertOp --
5163 *
5164 * Add new entries into a hierarchy. If no node is specified,
5165 * new entries will be added to the root of the hierarchy.
5166 *
5167 *----------------------------------------------------------------------
5168 */
5169 static int
InsertOp(tvPtr,interp,objc,objv)5170 InsertOp(tvPtr, interp, objc, objv)
5171 TreeView *tvPtr;
5172 Tcl_Interp *interp;
5173 int objc;
5174 Tcl_Obj *CONST *objv;
5175 {
5176 Blt_TreeNode node, parent;
5177 int insertPos;
5178 int depth, count;
5179 char *path;
5180 Tcl_Obj *CONST *options;
5181 Tcl_Obj *listObjPtr;
5182 char **compArr = NULL;
5183 register char **p;
5184 register int n;
5185 TreeViewEntry *rootPtr;
5186 char *string, *subPath;
5187 int nLen, idx, useid, oLen;
5188 int sobjc, tobjc;
5189 Tcl_Obj *CONST *sobjv;
5190 Tcl_Obj *CONST *tobjv;
5191 TreeViewStyle *stylePtr;
5192 TreeViewColumn *columnPtr;
5193 TreeViewEntry *entryPtr;
5194 Tcl_DString dStr;
5195 int optSkips, i, m, start, nOptions, inode;
5196
5197 useid = -1;
5198 inode = -1;
5199 optSkips = 0;
5200 sobjc = 0;
5201 tobjc = 0;
5202 entryPtr = NULL;
5203 rootPtr = tvPtr->rootPtr;
5204
5205 if (objc == 2) {
5206 Tcl_AppendResult(interp, "missing position argument", (char *)NULL);
5207 return TCL_ERROR;
5208 }
5209 if (Blt_GetPositionFromObj(interp, objv[2], &insertPos) != TCL_OK) {
5210 return TCL_ERROR;
5211 }
5212 for (i = 4; i < objc; i++) {
5213 char *cp = Tcl_GetString(objv[i]);
5214 if (cp[0] == '-') break;
5215 }
5216 start = i;
5217 nOptions = (objc<4?0:objc - i);
5218 options = objv + start;
5219
5220 if (nOptions%2) {
5221 Tcl_AppendResult(interp, "odd number of options", 0);
5222 return TCL_ERROR;
5223 }
5224 for (count = start; count < objc; count += 2) {
5225 string = Tcl_GetString(objv[count]);
5226 if (string[0] != '-') {
5227 Tcl_AppendResult(interp, "option must start with a dash: ", string, 0);
5228 return TCL_ERROR;
5229 }
5230 if (!strcmp("-tags", string)) {
5231 if (Tcl_ListObjGetElements(interp, objv[count+1], &tobjc, &tobjv) != TCL_OK) {
5232 return TCL_ERROR;
5233 }
5234
5235 } else if (!strcmp("-styles", string)) {
5236 if (Tcl_ListObjGetElements(interp, objv[count+1], &sobjc, &sobjv) != TCL_OK) {
5237 return TCL_ERROR;
5238 }
5239 if (sobjc%2) {
5240 Tcl_AppendResult(interp, "odd arguments for \"-styles\" flag", 0);
5241 return TCL_ERROR;
5242 }
5243 for (n=0; n<sobjc; n += 2) {
5244 if (Blt_TreeViewGetColumn(interp, tvPtr, sobjv[n], &columnPtr) != TCL_OK) {
5245 return TCL_ERROR;
5246 }
5247 if (columnPtr == &tvPtr->treeColumn) {
5248 Tcl_AppendResult(interp, "tree column invalid in \"-styles\" flag", 0);
5249 return TCL_ERROR;
5250 }
5251 if (Blt_TreeViewGetStyleMake(interp, tvPtr,
5252 Tcl_GetString(sobjv[n+1]), &stylePtr, columnPtr, NULL,
5253 NULL) != TCL_OK) {
5254 return TCL_ERROR;
5255 }
5256 stylePtr->refCount--;
5257 }
5258
5259 } else if (!strcmp("-at", string)) {
5260 if (Blt_TreeViewGetEntry(tvPtr, objv[count+1], &rootPtr) != TCL_OK) {
5261 return TCL_ERROR;
5262 }
5263
5264 } else if (!strcmp("-node", string)) {
5265 if (Tcl_GetIntFromObj(tvPtr->interp, objv[count+1], &useid) != TCL_OK) {
5266 return TCL_ERROR;
5267 }
5268 } else {
5269 continue;
5270 }
5271 optSkips++;
5272 }
5273 Tcl_DStringInit(&dStr);
5274 node = NULL;
5275 listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **)NULL);
5276 m = 2;
5277 if (objc == 3) {
5278 path = "#auto";
5279 options = NULL;
5280 oLen = 5;
5281 goto addpath;
5282 }
5283 while (++m < start && m<objc) {
5284 path = Tcl_GetStringFromObj(objv[m], &oLen);
5285
5286 if (oLen == 0) {
5287 path = "#auto";
5288 oLen = 5;
5289 }
5290 addpath:
5291 node = NULL;
5292 inode = -1;
5293 if (oLen == 5
5294 && (tvPtr->pathSep == SEPARATOR_NONE || tvPtr->pathSep == NULL)
5295 && path[0] == '#' && strcmp(path, "#auto") == 0) {
5296
5297 parent = rootPtr->node;
5298 if (useid>0) {
5299 node = Blt_TreeCreateNodeWithId(tvPtr->tree, parent,
5300 Blt_Itoa(useid), useid, insertPos);
5301 if (node != NULL) {
5302 goto makeent;
5303 }
5304 Tcl_AppendResult(interp, "node already exists", 0);
5305 goto error;
5306 }
5307 node = Blt_TreeCreateNode(tvPtr->tree, parent, NULL,
5308 insertPos);
5309 if (node == NULL) {
5310 Tcl_AppendResult(interp, "node create failed", 0);
5311 goto error;
5312 }
5313 if ((tvPtr->flags & TV_ALLOW_DUPLICATES) != 0) {
5314 if (Blt_TreeRelabelNode2(node, Blt_Itoa(Blt_TreeNodeId(node))) != TCL_OK) {
5315 goto error;
5316 }
5317 goto makeent;
5318 }
5319 if (Blt_TreeFindChildRev(parent, Blt_Itoa(Blt_TreeNodeId(node)),
5320 tvPtr->insertFirst) == NULL) {
5321 if (Blt_TreeRelabelNode2(node, Blt_Itoa(Blt_TreeNodeId(node))) != TCL_OK) {
5322 goto error;
5323 }
5324 goto makeent;
5325 }
5326 /* Should never happen. */
5327 idx = (parent == tvPtr->rootNode ? tvPtr->nextIdx : tvPtr->nextSubIdx);
5328 for (;;) {
5329 idx++;
5330 if (Blt_TreeFindChildRev(parent, Blt_Itoa(idx),
5331 tvPtr->insertFirst) == NULL) {
5332 if (Blt_TreeRelabelNode2(node, Blt_Itoa(idx)) != TCL_OK) {
5333 goto error;
5334 }
5335 goto makeent;
5336 }
5337 }
5338 }
5339 if (tvPtr->trimLeft != NULL) {
5340 register char *s1, *s2;
5341
5342 /* Trim off leading character string if one exists. */
5343 for (s1 = path, s2 = tvPtr->trimLeft; *s2 != '\0'; s2++, s1++) {
5344 if (*s1 != *s2) {
5345 break;
5346 }
5347 }
5348 if (*s2 == '\0') {
5349 path = s1;
5350 }
5351 }
5352 /*
5353 * Split the path and find the parent node of the path.
5354 */
5355 compArr = &path;
5356 depth = 1;
5357 if (tvPtr->pathSep != SEPARATOR_NONE) {
5358 if (SplitPath(tvPtr, path, &depth, &compArr) != TCL_OK) {
5359 goto error;
5360 }
5361 if (depth == 0 && compArr != &path) {
5362 if (compArr) { Blt_Free(compArr); }
5363 compArr = NULL;
5364 continue; /* Root already exists. */
5365 }
5366 }
5367 parent = rootPtr->node;
5368 depth--;
5369
5370 /* Verify each component in the path preceding the tail. */
5371 for (n = 0, p = compArr; n < depth; n++, p++) {
5372 node = Blt_TreeFindChildRev(parent, *p, tvPtr->insertFirst);
5373 if (node == NULL) {
5374 if ((tvPtr->flags & TV_FILL_ANCESTORS) == 0) {
5375 Tcl_AppendResult(interp, "can't find path component \"",
5376 *p, "\" in \"", path, "\"", (char *)NULL);
5377 goto error;
5378 }
5379 node = Blt_TreeCreateNode(tvPtr->tree, parent, *p, END);
5380 if (node == NULL) {
5381 goto error;
5382 }
5383 }
5384 parent = node;
5385 }
5386 node = NULL;
5387 subPath = *p;
5388 nLen = strlen(subPath);
5389 if (nLen>=5 && (tvPtr->flags & TV_ALLOW_DUPLICATES) == 0 && strcmp(subPath+nLen-5,"#auto") == 0) {
5390
5391 nLen -= 5;
5392 idx = (parent == tvPtr->rootNode ? tvPtr->nextIdx : tvPtr->nextSubIdx);
5393 for (;;) {
5394 Tcl_DStringSetLength(&dStr, 0);
5395 Tcl_DStringAppend(&dStr, *p, nLen);
5396 Tcl_DStringAppend(&dStr, Blt_Itoa(idx), -1);
5397 idx++;
5398 node = Blt_TreeFindChildRev(parent, Tcl_DStringValue(&dStr),
5399 tvPtr->insertFirst);
5400 if (node == NULL) break;
5401 }
5402 if (parent == tvPtr->rootNode) {
5403 tvPtr->nextIdx = idx;
5404 }
5405 subPath = Tcl_DStringValue(&dStr);
5406 } else if (((tvPtr->flags & TV_ALLOW_DUPLICATES) == 0) &&
5407 (Blt_TreeFindChildRev(parent, subPath, tvPtr->insertFirst) != NULL)) {
5408 Tcl_AppendResult(interp, "entry \"", subPath, "\" already exists in \"",
5409 path, "\"", (char *)NULL);
5410 goto error;
5411 }
5412 if (useid<=0) {
5413 node = Blt_TreeCreateNode(tvPtr->tree, parent, subPath, insertPos);
5414 } else {
5415 node = Blt_TreeCreateNodeWithId(tvPtr->tree, parent, subPath, useid, insertPos);
5416 useid++;
5417 }
5418 if (node == NULL) {
5419 Tcl_AppendResult(interp, "failed to create node: ", subPath, 0);
5420 goto error;
5421 }
5422 makeent:
5423 inode = node->inode;
5424 if (Blt_TreeViewCreateEntry(tvPtr, node, 0, options, BLT_CONFIG_OBJV_ONLY) != TCL_OK) {
5425 goto opterror;
5426 }
5427 entryPtr = Blt_NodeToEntry(tvPtr, node);
5428 Tcl_Preserve(entryPtr);
5429 for (i = 0; i<nOptions; i+=2) {
5430 char *str;
5431 int cRes;
5432
5433 str = Tcl_GetString(options[i]);
5434 if (strcmp("-tags",str) && strcmp("-styles",str) && strcmp("-at",str) && strcmp("-node",str)) {
5435 cRes = Blt_TreeViewConfigureEntry(tvPtr, entryPtr, 2, options+i, 0);
5436 if ((entryPtr->flags & ENTRY_DELETED) || (tvPtr->flags & TV_DELETED)) {
5437 Tcl_Release(entryPtr);
5438 node = NULL;
5439 goto error;
5440 }
5441
5442 if (cRes != TCL_OK) {
5443 Tcl_Release(entryPtr);
5444 Blt_TreeViewFreeEntry(tvPtr, entryPtr);
5445 goto error;
5446 }
5447 }
5448 }
5449 if (Blt_TreeInsertPost(tvPtr->tree, node) == NULL) {
5450 Tcl_Release(entryPtr);
5451 goto error;
5452 }
5453 if ((entryPtr->flags & ENTRY_DELETED) || (tvPtr->flags & TV_DELETED)) {
5454 Tcl_Release(entryPtr);
5455 node = NULL;
5456 goto error;
5457 }
5458 if (compArr != &path && compArr) {
5459 Blt_Free(compArr);
5460 compArr = NULL;
5461 }
5462 Tcl_ListObjAppendElement(interp, listObjPtr, NodeToObj(node));
5463 for (n=0; n<sobjc; n += 2) {
5464 TreeViewValue *valuePtr;
5465
5466 if (entryPtr == NULL) {
5467 entryPtr = Blt_NodeToEntry(tvPtr, node);
5468 }
5469
5470 Blt_TreeViewGetColumn(interp, tvPtr, sobjv[n], &columnPtr);
5471 for (valuePtr = entryPtr->values; valuePtr != NULL;
5472 valuePtr = valuePtr->nextPtr) {
5473 if (valuePtr->columnPtr == columnPtr) {
5474 if (Blt_TreeViewGetStyle(interp, tvPtr, Tcl_GetString(sobjv[n+1]), &stylePtr) == TCL_OK) {
5475 stylePtr->refCount++;
5476 valuePtr->stylePtr = stylePtr;
5477 }
5478 break;
5479 }
5480 }
5481 }
5482 for (n=0; n<tobjc; n++) {
5483 int tRes;
5484
5485 tRes = AddTag(tvPtr, node, Tcl_GetString(tobjv[n]));
5486 if ((entryPtr->flags & ENTRY_DELETED) || (tvPtr->flags & TV_DELETED)) {
5487 Tcl_Release(entryPtr);
5488 node = NULL;
5489 goto error;
5490 }
5491 if (tRes != TCL_OK) {
5492 Tcl_Release(entryPtr);
5493 goto error;
5494 }
5495 }
5496 Tcl_Release(entryPtr);
5497 }
5498 tvPtr->flags |= (TV_LAYOUT | TV_SCROLL | TV_DIRTY | TV_RESORT);
5499 if (compArr && compArr != &path) {
5500 Blt_Free(compArr);
5501 }
5502 Blt_TreeViewEventuallyRedraw(tvPtr);
5503 Tcl_SetObjResult(interp, listObjPtr);
5504 Tcl_DStringFree(&dStr);
5505 return TCL_OK;
5506
5507 opterror:
5508 if (strncmp(Tcl_GetStringResult(interp), "unknown option", 14) == 0) {
5509 Tcl_AppendResult(interp, "\nshould be one of one of the insert options: -at, -isopen, -node, -styles, -tags\n or one of the entry options: ", 0);
5510 Blt_FormatSpecOptions(interp, bltTreeViewEntrySpecs);
5511 }
5512 error:
5513 Tcl_DStringFree(&dStr);
5514 if (compArr && compArr != &path) {
5515 Blt_Free(compArr);
5516 }
5517 Tcl_DecrRefCount(listObjPtr);
5518 /* if (node != NULL && inode > = 0 && tvPtr->tree) {
5519 node = Blt_TreeGetNode(tvPtr->tree, inode)
5520 }*/
5521 if (node != NULL) {
5522 DeleteNode(tvPtr, node);
5523 }
5524 return TCL_ERROR;
5525 }
5526
5527 #ifdef notdef
5528 /*
5529 *----------------------------------------------------------------------
5530 *
5531 * AddOp -- UNUSED.
5532 *
5533 * Add new entries into a hierarchy. If no node is specified,
5534 * new entries will be added to the root of the hierarchy.
5535 *
5536 *----------------------------------------------------------------------
5537 */
5538
5539 static Blt_SwitchParseProc StringToChild;
5540 #define INSERT_BEFORE (ClientData)0
5541 #define INSERT_AFTER (ClientData)1
5542 static Blt_SwitchCustom beforeSwitch =
5543 {
5544 StringToChild, (Blt_SwitchFreeProc *)NULL, INSERT_BEFORE,
5545 };
5546 static Blt_SwitchCustom afterSwitch =
5547 {
5548 StringToChild, (Blt_SwitchFreeProc *)NULL, INSERT_AFTER,
5549 };
5550
5551 typedef struct {
5552 int insertPos;
5553 Blt_TreeNode parent;
5554 } InsertData;
5555
5556 static Blt_SwitchSpec insertSwitches[] =
5557 {
5558 {BLT_SWITCH_CUSTOM, "-after", Blt_Offset(InsertData, insertPos), 0,
5559 &afterSwitch},
5560 {BLT_SWITCH_INT_NONNEGATIVE, "-at", Blt_Offset(InsertData, insertPos), 0},
5561 {BLT_SWITCH_CUSTOM, "-before", Blt_Offset(InsertData, insertPos), 0,
5562 &beforeSwitch},
5563 {BLT_SWITCH_END, NULL, 0, 0}
5564 };
5565
5566 static int
AddOp(tvPtr,interp,objc,objv)5567 AddOp(tvPtr, interp, objc, objv)
5568 TreeView *tvPtr;
5569 Tcl_Interp *interp;
5570 int objc;
5571 Tcl_Obj *CONST *objv;
5572 {
5573 Blt_TreeNode node, parent;
5574 int insertPos;
5575 int depth, count;
5576 char *path;
5577 Tcl_Obj *CONST *options;
5578 Tcl_Obj *listObjPtr;
5579 char **compArr;
5580 register char **p;
5581 register int n;
5582 TreeViewEntry *rootPtr;
5583 char *string;
5584
5585 memset(&data, 0, sizeof(data));
5586 data.maxDepth = -1;
5587 data.cmdPtr = cmdPtr;
5588
5589 /* Process any leading switches */
5590 i = Blt_ProcessObjSwitches(interp, addSwitches, objc - 2, objv + 2,
5591 (char *)&data, BLT_CONFIG_OBJV_PARTIAL);
5592 if (i < 0) {
5593 return TCL_ERROR;
5594 }
5595 i += 2;
5596 /* Should have at the starting node */
5597 if (i >= objc) {
5598 Tcl_AppendResult(interp, "starting node argument is missing",
5599 (char *)NULL);
5600 return TCL_ERROR;
5601 }
5602 if (Blt_TreeViewGetEntry(tvPtr, objv[i], &rootPtr) != TCL_OK) {
5603 return TCL_ERROR;
5604 }
5605 objv += i, objc -= i;
5606 node = NULL;
5607
5608 /* Process sections of path ?options? */
5609 listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **)NULL);
5610 while (objc > 0) {
5611 path = Tcl_GetString(objv[0]);
5612 objv++, objc--;
5613 /*
5614 * Count the option-value pairs that follow. Count until we
5615 * spot one that looks like an entry name (i.e. doesn't start
5616 * with a minus "-").
5617 */
5618 for (count = 0; count < objc; count += 2) {
5619 if (!Blt_ObjIsOption(interp, bltTreeViewEntrySpecs, objv[count], 0)) {
5620 break;
5621 }
5622 }
5623 if (count > objc) {
5624 count = objc;
5625 }
5626 options = objv;
5627 objc -= count, objv += count;
5628
5629 if (tvPtr->trimLeft != NULL) {
5630 register char *s1, *s2;
5631
5632 /* Trim off leading character string if one exists. */
5633 for (s1 = path, s2 = tvPtr->trimLeft; *s2 != '\0'; s2++, s1++) {
5634 if (*s1 != *s2) {
5635 break;
5636 }
5637 }
5638 if (*s2 == '\0') {
5639 path = s1;
5640 }
5641 }
5642 /*
5643 * Split the path and find the parent node of the path.
5644 */
5645 compArr = &path;
5646 depth = 1;
5647 if (tvPtr->pathSep != SEPARATOR_NONE) {
5648 if (SplitPath(tvPtr, path, &depth, &compArr) != TCL_OK) {
5649 goto error;
5650 }
5651 if (depth == 0) {
5652 Blt_Free(compArr);
5653 continue; /* Root already exists. */
5654 }
5655 }
5656 parent = rootPtr->node;
5657 depth--;
5658
5659 /* Verify each component in the path preceding the tail. */
5660 for (n = 0, p = compArr; n < depth; n++, p++) {
5661 node = Blt_TreeFindChildRev(parent, *p, tvPtr->insertFirst);
5662 if (node == NULL) {
5663 if ((tvPtr->flags & TV_FILL_ANCESTORS) == 0) {
5664 Tcl_AppendResult(interp, "can't find path component \"",
5665 *p, "\" in \"", path, "\"", (char *)NULL);
5666 goto error;
5667 }
5668 node = Blt_TreeCreateNode(tvPtr->tree, parent, *p, END);
5669 if (node == NULL) {
5670 goto error;
5671 }
5672 }
5673 parent = node;
5674 }
5675 node = NULL;
5676 if (((tvPtr->flags & ) == 0) &&
5677 (Blt_TreeFindChildRev(parent, *p, tvPtr->insertFirst) != NULL)) {
5678 Tcl_AppendResult(interp, "entry \"", *p, "\" already exists in \"",
5679 path, "\"", (char *)NULL);
5680 goto error;
5681 }
5682 node = Blt_TreeCreateNode(tvPtr->tree, parent, *p, insertPos);
5683 if (node == NULL) {
5684 goto error;
5685 }
5686 if (Blt_TreeViewCreateEntry(tvPtr, node, count, options, 0) != TCL_OK) {
5687 goto error;
5688 }
5689 if (compArr != &path) {
5690 Blt_Free(compArr);
5691 }
5692 Tcl_ListObjAppendElement(interp, listObjPtr, NodeToObj(node));
5693 }
5694 tvPtr->flags |= (TV_LAYOUT | TV_SCROLL | TV_DIRTY | TV_RESORT);
5695 Blt_TreeViewEventuallyRedraw(tvPtr);
5696 Tcl_SetObjResult(interp, listObjPtr);
5697 return TCL_OK;
5698
5699 error:
5700 if (compArr != &path) {
5701 Blt_Free(compArr);
5702 }
5703 Tcl_DecrRefCount(listObjPtr);
5704 if (node != NULL) {
5705 DeleteNode(tvPtr, node);
5706 }
5707 return TCL_ERROR;
5708 }
5709 #endif
5710
5711 /*
5712 *----------------------------------------------------------------------
5713 *
5714 * DeleteOp --
5715 *
5716 * Deletes nodes from the hierarchy. Deletes one or more entries
5717 * (except root). In all cases, nodes are removed recursively.
5718 *
5719 * Note: There's no need to explicitly clean up Entry structures
5720 * or request a redraw of the widget. When a node is
5721 * deleted in the tree, all of the Tcl_Objs representing
5722 * the various data fields are also removed. The treeview
5723 * widget store the Entry structure in a data field. So it's
5724 * automatically cleaned up when FreeEntryInternalRep is
5725 * called.
5726 *
5727 *----------------------------------------------------------------------
5728 */
5729 /*ARGSUSED*/
5730 static int
DeleteOp(tvPtr,interp,objc,objv)5731 DeleteOp(tvPtr, interp, objc, objv)
5732 TreeView *tvPtr;
5733 Tcl_Interp *interp;
5734 int objc; /* Not used. */
5735 Tcl_Obj *CONST *objv;
5736 {
5737 TreeViewTagInfo info = {0};
5738 TreeViewEntry *entryPtr;
5739 register int i;
5740
5741 for (i = 2; i < objc; i++) {
5742 if (Blt_TreeViewFindTaggedEntries(tvPtr, objv[i], &info) != TCL_OK) {
5743 return TCL_ERROR;
5744 }
5745 for (entryPtr = Blt_TreeViewFirstTaggedEntry(&info); entryPtr != NULL;
5746 entryPtr = Blt_TreeViewNextTaggedEntry(&info)) {
5747 if (entryPtr == tvPtr->rootPtr) {
5748 Blt_TreeNode next, node;
5749
5750 /*
5751 * Don't delete the root node. We implicitly assume
5752 * that even an empty tree has at a root. Instead
5753 * delete all the children regardless if they're closed
5754 * or hidden.
5755 */
5756 for (node = Blt_TreeFirstChild(entryPtr->node); node != NULL;
5757 node = next) {
5758 next = Blt_TreeNextSibling(node);
5759 DeleteNode(tvPtr, node);
5760 }
5761 } else {
5762 DeleteNode(tvPtr, entryPtr->node);
5763 }
5764 }
5765 Blt_TreeViewDoneTaggedEntries(&info);
5766 }
5767 if (objc == 3 && !strcmp(Tcl_GetString(objv[2]), "all")) {
5768 tvPtr->nextIdx = 1;
5769 tvPtr->nextSubIdx = 1;
5770 }
5771 return TCL_OK;
5772 }
5773
5774 /*
5775 *----------------------------------------------------------------------
5776 *
5777 * MoveOp --
5778 *
5779 * Move an entry into a new location in the hierarchy.
5780 *
5781 *
5782 *----------------------------------------------------------------------
5783 */
5784 /*ARGSUSED*/
5785 static int
MoveOp(tvPtr,interp,objc,objv)5786 MoveOp(tvPtr, interp, objc, objv)
5787 TreeView *tvPtr;
5788 Tcl_Interp *interp;
5789 int objc; /* Not used. */
5790 Tcl_Obj *CONST *objv;
5791 {
5792 Blt_TreeNode parent;
5793 TreeViewEntry *srcPtr, *destPtr;
5794 char c;
5795 int action;
5796 char *string;
5797 TreeViewTagInfo info = {0};
5798
5799 #define MOVE_INTO (1<<0)
5800 #define MOVE_BEFORE (1<<1)
5801 #define MOVE_AFTER (1<<2)
5802 string = Tcl_GetString(objv[3]);
5803 c = string[0];
5804 if ((c == 'i') && (strcmp(string, "into") == 0)) {
5805 action = MOVE_INTO;
5806 } else if ((c == 'b') && (strcmp(string, "before") == 0)) {
5807 action = MOVE_BEFORE;
5808 } else if ((c == 'a') && (strcmp(string, "after") == 0)) {
5809 action = MOVE_AFTER;
5810 } else {
5811 Tcl_AppendResult(interp, "bad position \"", string,
5812 "\": should be into, before, or after", (char *)NULL);
5813 return TCL_ERROR;
5814 }
5815 if (Blt_TreeViewGetEntry(tvPtr, objv[4], &destPtr) != TCL_OK) {
5816 return TCL_ERROR;
5817 }
5818 if (Blt_TreeViewFindTaggedEntries(tvPtr, objv[2], &info) != TCL_OK) {
5819 return TCL_ERROR;
5820 }
5821 for (srcPtr = Blt_TreeViewFirstTaggedEntry(&info); srcPtr != NULL;
5822 srcPtr = Blt_TreeViewNextTaggedEntry(&info)) {
5823 /* Verify they aren't ancestors. */
5824 if (Blt_TreeIsAncestor(srcPtr->node, destPtr->node)) {
5825 Tcl_DString dString;
5826 char *path;
5827
5828 Tcl_DStringInit(&dString);
5829 path = Blt_TreeViewGetFullName(tvPtr, srcPtr, 1, &dString);
5830 Tcl_AppendResult(interp, "can't move node: \"", path,
5831 "\" is an ancestor of \"", Tcl_GetString(objv[4]),
5832 "\"", (char *)NULL);
5833 Tcl_DStringFree(&dString);
5834 Blt_TreeViewDoneTaggedEntries(&info);
5835 return TCL_ERROR;
5836 }
5837 parent = Blt_TreeNodeParent(destPtr->node);
5838 if (parent == NULL) {
5839 action = MOVE_INTO;
5840 }
5841 switch (action) {
5842 case MOVE_INTO:
5843 Blt_TreeMoveNode(tvPtr->tree, srcPtr->node, destPtr->node,
5844 (Blt_TreeNode)NULL);
5845 break;
5846
5847 case MOVE_BEFORE:
5848 Blt_TreeMoveNode(tvPtr->tree, srcPtr->node, parent, destPtr->node);
5849 break;
5850
5851 case MOVE_AFTER:
5852 Blt_TreeMoveNode(tvPtr->tree, srcPtr->node, parent,
5853 Blt_TreeNextSibling(destPtr->node));
5854 break;
5855 }
5856 }
5857 Blt_TreeViewDoneTaggedEntries(&info);
5858 tvPtr->flags |= (TV_LAYOUT | TV_DIRTY | TV_RESORT);
5859 Blt_TreeViewEventuallyRedraw(tvPtr);
5860 return TCL_OK;
5861 }
5862
5863 /* .t nearest ?-root? ?-strict? x y ?var? */
5864 /*ARGSUSED*/
5865 static int
NearestOp(tvPtr,interp,objc,objv)5866 NearestOp(tvPtr, interp, objc, objv)
5867 TreeView *tvPtr;
5868 Tcl_Interp *interp;
5869 int objc; /* Not used. */
5870 Tcl_Obj *CONST *objv;
5871 {
5872 TreeViewColumn *columnPtr = NULL;
5873 TreeViewButton *buttonPtr = &tvPtr->button;
5874 int x, y, ox, oy; /* Screen coordinates of the test point. */
5875 register TreeViewEntry *entryPtr;
5876 int isRoot, isStrict;
5877 char *string;
5878
5879 isRoot = FALSE;
5880 isStrict = TRUE;
5881 while (objc>2) {
5882 string = Tcl_GetString(objv[2]);
5883 if (strcmp("-root", string) == 0) {
5884 isRoot = TRUE;
5885 objv++, objc--;
5886 } else if (strcmp("-strict", string) == 0) {
5887 isStrict = FALSE;
5888 objv++, objc--;
5889 } else break;
5890 }
5891 if (objc < 4 || objc > 5) {
5892 Tcl_AppendResult(interp, "wrong # args: should be \"",
5893 Tcl_GetString(objv[0]), " ", Tcl_GetString(objv[1]),
5894 " ?-root? ?-strict? x y ?var?\"", (char *)NULL);
5895 return TCL_ERROR;
5896
5897 }
5898 if ((Tk_GetPixelsFromObj(interp, tvPtr->tkwin, objv[2], &x) != TCL_OK) ||
5899 (Tk_GetPixelsFromObj(interp, tvPtr->tkwin, objv[3], &y) != TCL_OK)) {
5900 return TCL_ERROR;
5901 }
5902 ox = x;
5903 oy = y;
5904 if (tvPtr->nVisible == 0) {
5905 return TCL_OK;
5906 }
5907 if (isRoot) {
5908 int rootX, rootY;
5909
5910 Tk_GetRootCoords(tvPtr->tkwin, &rootX, &rootY);
5911 x -= rootX;
5912 y -= rootY;
5913 }
5914 entryPtr = Blt_TreeViewNearestEntry(tvPtr, x, y, isStrict);
5915 if (entryPtr == NULL) {
5916 return TCL_OK;
5917 }
5918 columnPtr = Blt_TreeViewNearestColumn(tvPtr, x, y, NULL);
5919 x = WORLDX(tvPtr, x);
5920 y = WORLDY(tvPtr, y);
5921
5922 if (objc > 4) {
5923 char *where;
5924 int labelX, labelY, depth, height, ly, lx, butEnd = 0, entryHeight, isTree;
5925 TreeViewIcon icon;
5926
5927 entryHeight = MAX3(entryPtr->lineHeight, entryPtr->iconHeight,
5928 tvPtr->button.height);
5929 isTree = (columnPtr && columnPtr == &tvPtr->treeColumn);
5930
5931 where = "";
5932
5933 if ((tvPtr->flags & TV_SHOW_COLUMN_TITLES)
5934 && oy<(tvPtr->insetY+tvPtr->titleHeight)) {
5935 TreeViewColumn *cPtr = columnPtr;
5936
5937 ly = oy;
5938 lx = ox;
5939
5940 if (cPtr->tW && (lx >= cPtr->tX) && (lx < (cPtr->tX + cPtr->tW)) &&
5941 (ly >= cPtr->tY) && (ly < (cPtr->tY + cPtr->tH))) {
5942 where = "titlelabel";
5943 goto done;
5944 }
5945
5946 if (cPtr->iW && (lx >= cPtr->iX) && (lx < (cPtr->iX + cPtr->iW)) &&
5947 (ly >= cPtr->iY) && (ly < (cPtr->iY + cPtr->iH))) {
5948 where = "titleicon";
5949 goto done;
5950 }
5951
5952 where = "title";
5953 goto done;
5954 }
5955 if (isTree && entryPtr->flags & ENTRY_HAS_BUTTON) {
5956 int buttonX, buttonY;
5957
5958 buttonX = entryPtr->worldX + entryPtr->buttonX;
5959 buttonY = entryPtr->worldY + entryPtr->buttonY;
5960 butEnd = entryPtr->buttonX + buttonPtr->width;
5961 if ((x >= buttonX) && (x < (buttonX + buttonPtr->width)) &&
5962 (y >= buttonY) && (y < (buttonY + buttonPtr->height))) {
5963 where = "button";
5964 goto done;
5965 }
5966 }
5967 depth = DEPTH(tvPtr, entryPtr->node);
5968
5969 icon = Blt_TreeViewGetEntryIcon(tvPtr, entryPtr);
5970 if (isTree && icon != NULL) {
5971 int iconWidth, iconHeight;
5972 int iconX, iconY;
5973
5974 /* entryHeight = MAX(entryPtr->iconHeight, tvPtr->button.height); */
5975 butEnd = entryPtr->buttonX + buttonPtr->width;
5976 iconHeight = TreeViewIconHeight(icon);
5977 iconWidth = TreeViewIconWidth(icon);
5978 iconX = entryPtr->worldX + butEnd;
5979 iconY = entryPtr->worldY + tvPtr->leader/2;
5980 if (tvPtr->flatView) {
5981 iconX += (ICONWIDTH(0) - iconWidth) / 2;
5982 } else {
5983 iconX += (ICONWIDTH(depth + 1) - iconWidth) / 2;
5984 }
5985 iconY += (entryHeight - iconHeight) / 2;
5986 if ((x >= iconX) && (x <= (iconX + iconWidth)) &&
5987 (y >= iconY) && (y < (iconY + iconHeight))) {
5988 where = "icon";
5989 goto done;
5990 }
5991 }
5992 labelX = entryPtr->worldX + ICONWIDTH(depth);
5993 labelY = entryPtr->worldY + (icon == NULL ? 0 : tvPtr->leader/2);
5994 if (!tvPtr->flatView) {
5995 labelX += ICONWIDTH(depth + 1) + 4;
5996 }
5997 height = entryPtr->labelHeight;
5998 ly = y;
5999 if (height < entryHeight) {
6000 ly -= (entryHeight - height) / 2;
6001 }
6002
6003 if (isTree && (x >= labelX) && (x < (labelX + entryPtr->labelWidth)) &&
6004 (ly >= labelY) && (ly < (labelY + entryPtr->labelHeight))) {
6005 where = "label";
6006 }
6007
6008 if (columnPtr && isTree == 0) {
6009 TreeViewValue *vPtr;
6010
6011 vPtr = Blt_TreeViewFindValue(entryPtr, columnPtr);
6012 if (vPtr == NULL) goto done;
6013 ly = y - tvPtr->yOffset + tvPtr->titleHeight;
6014 lx = x - tvPtr->xOffset;
6015
6016 if (vPtr->tW && (lx >= vPtr->tX) && (lx < (vPtr->tX + vPtr->tW)) &&
6017 (ly >= vPtr->tY) && (ly < (vPtr->tY + vPtr->tH))) {
6018 where = "datalabel";
6019 goto done;
6020 }
6021
6022 if (vPtr->iW && (lx >= vPtr->iX) && (lx < (vPtr->iX + vPtr->iW)) &&
6023 (ly >= vPtr->iY) && (ly < (vPtr->iY + vPtr->iH))) {
6024 where = "dataicon";
6025 goto done;
6026 }
6027
6028 }
6029 done:
6030 if (Tcl_SetVar(interp, Tcl_GetString(objv[4]), where,
6031 TCL_LEAVE_ERR_MSG) == NULL) {
6032 return TCL_ERROR;
6033 }
6034 }
6035 Tcl_SetObjResult(interp, NodeToObj(entryPtr->node));
6036 return TCL_OK;
6037 }
6038
6039
6040 static int
OpenTreeEntry(TreeView * tvPtr,TreeViewEntry * entryPtr)6041 OpenTreeEntry(TreeView *tvPtr, TreeViewEntry *entryPtr) {
6042 if (!Blt_TreeViewIsLeaf(entryPtr)) {
6043 return Blt_TreeViewOpenEntry(tvPtr, entryPtr);
6044 }
6045 return TCL_OK;
6046 }
6047
6048 /*ARGSUSED*/
6049 static int
OpenOp(tvPtr,interp,objc,objv)6050 OpenOp(tvPtr, interp, objc, objv)
6051 TreeView *tvPtr;
6052 Tcl_Interp *interp; /* Not used. */
6053 int objc;
6054 Tcl_Obj *CONST *objv;
6055 {
6056 TreeViewEntry *entryPtr;
6057 TreeViewTagInfo info = {0};
6058 int recurse, trees, parent, result;
6059 register int i;
6060
6061 recurse = FALSE;
6062 trees = FALSE;
6063 parent = FALSE;
6064 while (objc > 2) {
6065 int length;
6066 char *string;
6067
6068 string = Tcl_GetStringFromObj(objv[2], &length);
6069 if ((string[0] == '-') && (length > 1) &&
6070 (strncmp(string, "-recurse", length) == 0)) {
6071 objv++, objc--;
6072 recurse = TRUE;
6073 } else if ((string[0] == '-') && (length > 1) &&
6074 (strncmp(string, "-trees", length) == 0)) {
6075 objv++, objc--;
6076 trees = TRUE;
6077 } else if ((string[0] == '-') && (length > 1) &&
6078 (strncmp(string, "-parent", length) == 0)) {
6079 objv++, objc--;
6080 parent = TRUE;
6081 } else break;
6082 }
6083 for (i = 2; i < objc; i++) {
6084 if (Blt_TreeViewFindTaggedEntries(tvPtr, objv[i], &info) != TCL_OK) {
6085 return TCL_ERROR;
6086 }
6087 for (entryPtr = Blt_TreeViewFirstTaggedEntry(&info); entryPtr != NULL;
6088 entryPtr = Blt_TreeViewNextTaggedEntry(&info)) {
6089 if (parent) {
6090 while ((entryPtr = Blt_TreeViewParentEntry(entryPtr))) {
6091 if (entryPtr) {
6092 result = Blt_TreeViewOpenEntry(tvPtr, entryPtr);
6093 }
6094 }
6095 continue;
6096 }
6097
6098 if (trees) {
6099 result = Blt_TreeViewApply(tvPtr, entryPtr,
6100 OpenTreeEntry, 0);
6101 } else if (recurse) {
6102 result = Blt_TreeViewApply(tvPtr, entryPtr,
6103 Blt_TreeViewOpenEntry, 0);
6104 } else {
6105 result = Blt_TreeViewOpenEntry(tvPtr, entryPtr);
6106 }
6107 if (result != TCL_OK) {
6108 tvPtr->flags |= (TV_LAYOUT | TV_DIRTY | TV_RESORT);
6109 Blt_TreeViewDoneTaggedEntries(&info);
6110 return TCL_ERROR;
6111 }
6112 /* Make sure ancestors of this node aren't hidden. */
6113 MapAncestors(tvPtr, entryPtr);
6114 }
6115 Blt_TreeViewDoneTaggedEntries(&info);
6116 }
6117 /*FIXME: This is only for flattened entries. */
6118 tvPtr->flags |= (TV_LAYOUT | TV_DIRTY | TV_RESORT);
6119 Blt_TreeViewEventuallyRedraw(tvPtr);
6120 return TCL_OK;
6121 }
6122
6123 /*
6124 *----------------------------------------------------------------------
6125 *
6126 * RangeOp --
6127 *
6128 * Returns the node identifiers in a given range.
6129 *
6130 *----------------------------------------------------------------------
6131 */
6132 static int
RangeOp(tvPtr,interp,objc,objv)6133 RangeOp(tvPtr, interp, objc, objv)
6134 TreeView *tvPtr;
6135 Tcl_Interp *interp;
6136 int objc;
6137 Tcl_Obj *CONST *objv;
6138 {
6139 TreeViewEntry *entryPtr, *firstPtr, *lastPtr;
6140 unsigned int mask;
6141 int length;
6142 Tcl_Obj *listObjPtr, *objPtr;
6143 char *string;
6144
6145 mask = 0;
6146 string = Tcl_GetStringFromObj(objv[2], &length);
6147 if ((string[0] == '-') && (length > 1) &&
6148 (strncmp(string, "-open", length) == 0)) {
6149 objv++, objc--;
6150 mask |= ENTRY_CLOSED;
6151 }
6152 if (Blt_TreeViewGetEntry(tvPtr, objv[2], &firstPtr) != TCL_OK) {
6153 return TCL_ERROR;
6154 }
6155 if (objc > 3) {
6156 if (Blt_TreeViewGetEntry(tvPtr, objv[3], &lastPtr) != TCL_OK) {
6157 return TCL_ERROR;
6158 }
6159 } else {
6160 lastPtr = LastEntry(tvPtr, firstPtr, mask);
6161 }
6162 if (mask & ENTRY_CLOSED) {
6163 if (firstPtr->flags & ENTRY_HIDDEN) {
6164 Tcl_AppendResult(interp, "first node \"", Tcl_GetString(objv[2]),
6165 "\" is hidden.", (char *)NULL);
6166 return TCL_ERROR;
6167 }
6168 if (lastPtr->flags & ENTRY_HIDDEN) {
6169 Tcl_AppendResult(interp, "last node \"", Tcl_GetString(objv[3]),
6170 "\" is hidden.", (char *)NULL);
6171 return TCL_ERROR;
6172 }
6173 }
6174
6175 /*
6176 * The relative order of the first/last markers determines the
6177 * direction.
6178 */
6179 listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **)NULL);
6180 if (Blt_TreeIsBefore(lastPtr->node, firstPtr->node)) {
6181 for (entryPtr = lastPtr; entryPtr != NULL;
6182 entryPtr = Blt_TreeViewPrevEntry(entryPtr, mask)) {
6183 objPtr = NodeToObj(entryPtr->node);
6184 Tcl_ListObjAppendElement(interp, listObjPtr, objPtr);
6185 if (entryPtr == firstPtr) {
6186 break;
6187 }
6188 }
6189 } else {
6190 for (entryPtr = firstPtr; entryPtr != NULL;
6191 entryPtr = Blt_TreeViewNextEntry(entryPtr, mask)) {
6192 objPtr = NodeToObj(entryPtr->node);
6193 Tcl_ListObjAppendElement(interp, listObjPtr, objPtr);
6194 if (entryPtr == lastPtr) {
6195 break;
6196 }
6197 }
6198 }
6199 Tcl_SetObjResult(interp, listObjPtr);
6200 return TCL_OK;
6201 }
6202
6203 /*
6204 *----------------------------------------------------------------------
6205 *
6206 * ScanOp --
6207 *
6208 * Implements the quick scan.
6209 *
6210 *----------------------------------------------------------------------
6211 */
6212 /*ARGSUSED*/
6213 static int
ScanOp(tvPtr,interp,objc,objv)6214 ScanOp(tvPtr, interp, objc, objv)
6215 TreeView *tvPtr;
6216 Tcl_Interp *interp;
6217 int objc; /* Not used. */
6218 Tcl_Obj *CONST *objv;
6219 {
6220 int x, y;
6221 char c;
6222 int length;
6223 int oper;
6224 char *string;
6225 Tk_Window tkwin;
6226
6227 #define SCAN_MARK 1
6228 #define SCAN_DRAGTO 2
6229 string = Tcl_GetStringFromObj(objv[2], &length);
6230 c = string[0];
6231 tkwin = tvPtr->tkwin;
6232 if ((c == 'm') && (strncmp(string, "mark", length) == 0)) {
6233 oper = SCAN_MARK;
6234 } else if ((c == 'd') && (strncmp(string, "dragto", length) == 0)) {
6235 oper = SCAN_DRAGTO;
6236 } else {
6237 Tcl_AppendResult(interp, "bad scan operation \"", string,
6238 "\": should be either \"mark\" or \"dragto\"", (char *)NULL);
6239 return TCL_ERROR;
6240 }
6241 if ((Blt_GetPixelsFromObj(interp, tkwin, objv[3], 0, &x) != TCL_OK) ||
6242 (Blt_GetPixelsFromObj(interp, tkwin, objv[4], 0, &y) != TCL_OK)) {
6243 return TCL_ERROR;
6244 }
6245 if (oper == SCAN_MARK) {
6246 tvPtr->scanAnchorX = x;
6247 tvPtr->scanAnchorY = y;
6248 tvPtr->scanX = tvPtr->xOffset;
6249 tvPtr->scanY = tvPtr->yOffset;
6250 } else {
6251 int worldX, worldY;
6252 int dx, dy;
6253
6254 dx = tvPtr->scanAnchorX - x;
6255 dy = tvPtr->scanAnchorY - y;
6256 worldX = tvPtr->scanX + (10 * dx);
6257 worldY = tvPtr->scanY + (10 * dy);
6258
6259 if (worldX < 0) {
6260 worldX = 0;
6261 } else if (worldX >= tvPtr->worldWidth) {
6262 worldX = tvPtr->worldWidth - tvPtr->xScrollUnits;
6263 }
6264 if (worldY < 0) {
6265 worldY = 0;
6266 } else if (worldY >= tvPtr->worldHeight) {
6267 worldY = tvPtr->worldHeight - tvPtr->yScrollUnits;
6268 }
6269 tvPtr->xOffset = worldX;
6270 tvPtr->yOffset = worldY;
6271 tvPtr->flags |= TV_SCROLL;
6272 Blt_TreeViewEventuallyRedraw(tvPtr);
6273 }
6274 return TCL_OK;
6275 }
6276
6277 /*ARGSUSED*/
6278 static int
SeeOp(tvPtr,interp,objc,objv)6279 SeeOp(tvPtr, interp, objc, objv)
6280 TreeView *tvPtr;
6281 Tcl_Interp *interp; /* Not used. */
6282 int objc;
6283 Tcl_Obj *CONST *objv;
6284 {
6285 TreeViewEntry *entryPtr;
6286 int width, height;
6287 int x, y;
6288 Tk_Anchor anchor;
6289 int left, right, top, bottom;
6290 char *string;
6291
6292 string = Tcl_GetString(objv[2]);
6293 anchor = TK_ANCHOR_W; /* Default anchor is West */
6294 if ((string[0] == '-') && (strcmp(string, "-anchor") == 0)) {
6295 if (objc == 3) {
6296 Tcl_AppendResult(interp, "missing \"-anchor\" argument",
6297 (char *)NULL);
6298 return TCL_ERROR;
6299 }
6300 if (Tk_GetAnchorFromObj(interp, objv[3], &anchor) != TCL_OK) {
6301 return TCL_ERROR;
6302 }
6303 objc -= 2, objv += 2;
6304 }
6305 if (objc == 2) {
6306 Tcl_AppendResult(interp, "wrong # args: should be \"",
6307 Tcl_GetString(objv[0]),
6308 "see ?-anchor anchor? tagOrId\"", (char *)NULL);
6309 return TCL_ERROR;
6310 }
6311 if (GetEntryFromObj(tvPtr, objv[2], &entryPtr) != TCL_OK) {
6312 return TCL_ERROR;
6313 }
6314 if (entryPtr == NULL || tvPtr->noScroll) {
6315 return TCL_OK;
6316 }
6317 if (entryPtr->flags & ENTRY_HIDDEN) {
6318 MapAncestors(tvPtr, entryPtr);
6319 tvPtr->flags |= TV_SCROLL;
6320 /*
6321 * If the entry wasn't previously exposed, its world coordinates
6322 * aren't likely to be valid. So re-compute the layout before
6323 * we try to see the viewport to the entry's location.
6324 */
6325 Blt_TreeViewComputeLayout(tvPtr);
6326 }
6327 width = VPORTWIDTH(tvPtr);
6328 height = VPORTHEIGHT(tvPtr);
6329
6330 /*
6331 * XVIEW: If the entry is left or right of the current view, adjust
6332 * the offset. If the entry is nearby, adjust the view just
6333 * a bit. Otherwise, center the entry.
6334 */
6335 left = tvPtr->xOffset;
6336 right = tvPtr->xOffset + width;
6337
6338 switch (anchor) {
6339 case TK_ANCHOR_W:
6340 case TK_ANCHOR_NW:
6341 case TK_ANCHOR_SW:
6342 x = 0;
6343 break;
6344 case TK_ANCHOR_E:
6345 case TK_ANCHOR_NE:
6346 case TK_ANCHOR_SE:
6347 x = entryPtr->worldX + entryPtr->width +
6348 ICONWIDTH(DEPTH(tvPtr, entryPtr->node)) - width;
6349 break;
6350 default:
6351 if (entryPtr->worldX < left) {
6352 x = entryPtr->worldX;
6353 } else if ((entryPtr->worldX + entryPtr->width) > right) {
6354 x = entryPtr->worldX + entryPtr->width - width;
6355 } else {
6356 x = tvPtr->xOffset;
6357 }
6358 break;
6359 }
6360 /*
6361 * YVIEW: If the entry is above or below the current view, adjust
6362 * the offset. If the entry is nearby, adjust the view just
6363 * a bit. Otherwise, center the entry.
6364 */
6365 top = tvPtr->yOffset;
6366 bottom = tvPtr->yOffset + height;
6367
6368 switch (anchor) {
6369 case TK_ANCHOR_N:
6370 case TK_ANCHOR_NE:
6371 case TK_ANCHOR_NW:
6372 y = entryPtr->worldY;
6373 break;
6374 case TK_ANCHOR_CENTER:
6375 y = entryPtr->worldY - (height / 2);
6376 break;
6377 case TK_ANCHOR_S:
6378 case TK_ANCHOR_SE:
6379 case TK_ANCHOR_SW:
6380 y = entryPtr->worldY + entryPtr->height - height;
6381 break;
6382 default:
6383 if (entryPtr->worldY < top) {
6384 y = entryPtr->worldY;
6385 } else if ((entryPtr->worldY + entryPtr->height) > bottom) {
6386 y = entryPtr->worldY + entryPtr->height - height;
6387 } else {
6388 y = tvPtr->yOffset;
6389 }
6390 break;
6391 }
6392 if ((y != tvPtr->yOffset) || (x != tvPtr->xOffset)) {
6393 /* tvPtr->xOffset = x; */
6394 tvPtr->yOffset = y;
6395 tvPtr->flags |= TV_SCROLL;
6396 }
6397 Blt_TreeViewEventuallyRedraw(tvPtr);
6398 return TCL_OK;
6399 }
6400
6401 void
Blt_TreeViewClearSelection(tvPtr)6402 Blt_TreeViewClearSelection(tvPtr)
6403 TreeView *tvPtr;
6404 {
6405 if (tvPtr->selectMode & SELECT_MODE_CELLMASK) {
6406 Blt_HashEntry *hPtr;
6407 Blt_HashSearch cursor;
6408 TreeViewValue *valuePtr;
6409 TreeViewEntry *entryPtr;
6410 TreeViewColumn *columnPtr;
6411 Blt_ChainLink *linkPtr;
6412
6413 for (hPtr = Blt_FirstHashEntry(&tvPtr->selectTable, &cursor);
6414 hPtr != NULL; hPtr = Blt_NextHashEntry(&cursor)) {
6415 entryPtr = (TreeViewEntry *)Blt_GetHashKey(&tvPtr->selectTable, hPtr);
6416 for (linkPtr = Blt_ChainFirstLink(tvPtr->colChainPtr);
6417 linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) {
6418 columnPtr = Blt_ChainGetValue(linkPtr);
6419 valuePtr = (TreeViewValue *)Blt_TreeViewFindValue(entryPtr, columnPtr);
6420 if (valuePtr != NULL) {
6421 valuePtr->selected = 0;
6422 }
6423 }
6424 }
6425 }
6426 Blt_DeleteHashTable(&tvPtr->selectTable);
6427 Blt_InitHashTable(&tvPtr->selectTable, BLT_ONE_WORD_KEYS);
6428 Blt_ChainReset(tvPtr->selChainPtr);
6429 Blt_TreeViewEventuallyRedraw(tvPtr);
6430 if (tvPtr->selectCmd != NULL) {
6431 EventuallyInvokeSelectCmd(tvPtr);
6432 }
6433 }
6434
6435 /*
6436 *----------------------------------------------------------------------
6437 *
6438 * LostSelection --
6439 *
6440 * This procedure is called back by Tk when the selection is grabbed
6441 * away.
6442 *
6443 * Results:
6444 * None.
6445 *
6446 * Side effects:
6447 * The existing selection is unhighlighted, and the window is
6448 * marked as not containing a selection.
6449 *
6450 *----------------------------------------------------------------------
6451 */
6452 static void
LostSelection(clientData)6453 LostSelection(clientData)
6454 ClientData clientData; /* Information about the widget. */
6455 {
6456 TreeView *tvPtr = clientData;
6457
6458 if ((tvPtr->flags & TV_SELECT_EXPORT) == 0) {
6459 return;
6460 }
6461 Blt_TreeViewClearSelection(tvPtr);
6462 }
6463
6464 /*
6465 *----------------------------------------------------------------------
6466 *
6467 * SelectRange --
6468 *
6469 * Sets the selection flag for a range of nodes. The range is
6470 * determined by two pointers which designate the first/last
6471 * nodes of the range.
6472 *
6473 * Results:
6474 * Always returns TCL_OK.
6475 *
6476 *----------------------------------------------------------------------
6477 */
6478 static int
SelectRange(tvPtr,fromPtr,toPtr)6479 SelectRange(tvPtr, fromPtr, toPtr)
6480 TreeView *tvPtr;
6481 TreeViewEntry *fromPtr, *toPtr;
6482 {
6483 if (tvPtr->flatView) {
6484 register int i;
6485
6486 if (fromPtr->flatIndex > toPtr->flatIndex) {
6487 for (i = fromPtr->flatIndex; i >= toPtr->flatIndex; i--) {
6488 SelectEntryApplyProc(tvPtr, tvPtr->flatArr[i], NULL);
6489 }
6490 } else {
6491 for (i = fromPtr->flatIndex; i <= toPtr->flatIndex; i++) {
6492 SelectEntryApplyProc(tvPtr, tvPtr->flatArr[i], NULL);
6493 }
6494 }
6495 } else {
6496 TreeViewEntry *entryPtr;
6497 TreeViewIterProc *proc;
6498 /* From the range determine the direction to select entries. */
6499
6500 proc = (Blt_TreeIsBefore(toPtr->node, fromPtr->node))
6501 ? Blt_TreeViewPrevEntry : Blt_TreeViewNextEntry;
6502 for (entryPtr = fromPtr; entryPtr != NULL;
6503 entryPtr = (*proc)(entryPtr, ENTRY_MASK)) {
6504 SelectEntryApplyProc(tvPtr, entryPtr, NULL);
6505 if (entryPtr == toPtr) {
6506 break;
6507 }
6508 }
6509 }
6510 return TCL_OK;
6511 }
6512
6513 /*
6514 *----------------------------------------------------------------------
6515 *
6516 * SelectionAnchorOp --
6517 *
6518 * Sets the selection anchor to the element given by a index.
6519 * The selection anchor is the end of the selection that is fixed
6520 * while dragging out a selection with the mouse. The index
6521 * "anchor" may be used to refer to the anchor element.
6522 *
6523 * Results:
6524 * None.
6525 *
6526 * Side effects:
6527 * The selection changes.
6528 *
6529 *----------------------------------------------------------------------
6530 */
6531 /*ARGSUSED*/
6532 static int
SelectionAnchorOp(tvPtr,interp,objc,objv)6533 SelectionAnchorOp(tvPtr, interp, objc, objv)
6534 TreeView *tvPtr;
6535 Tcl_Interp *interp; /* Not used. */
6536 int objc; /* Not used. */
6537 Tcl_Obj *CONST *objv;
6538 {
6539 TreeViewEntry *entryPtr;
6540 TreeViewColumn *columnPtr;
6541
6542 columnPtr = NULL;
6543
6544 if (objc<=3) {
6545 Tcl_Obj *listObjPtr, *objPtr;
6546 if (tvPtr->selAnchorPtr == NULL) return TCL_OK;
6547 listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **)NULL);
6548 objPtr = NodeToObj(tvPtr->selAnchorPtr);
6549 Tcl_ListObjAppendElement(interp, listObjPtr, objPtr);
6550 if (tvPtr->selAnchorCol != NULL) {
6551 objPtr = Tcl_NewStringObj( tvPtr->selAnchorCol->key, -1);
6552 Tcl_ListObjAppendElement(interp, listObjPtr, objPtr);
6553 }
6554 Tcl_SetObjResult(interp, listObjPtr);
6555 return TCL_OK;
6556 }
6557 if (GetEntryFromObj(tvPtr, objv[3], &entryPtr) != TCL_OK) {
6558 return TCL_ERROR;
6559 }
6560 if (objc > 4) {
6561 if (Blt_TreeViewGetColumn(interp, tvPtr, objv[4], &columnPtr) != TCL_OK) {
6562 return TCL_ERROR;
6563 }
6564 }
6565 /* Set both the anchor and the mark. Indicates that a single entry
6566 * is selected. */
6567 tvPtr->selAnchorPtr = entryPtr;
6568 tvPtr->selMarkPtr = NULL;
6569 tvPtr->selAnchorCol = columnPtr;
6570 if (entryPtr != NULL) {
6571 Tcl_SetObjResult(interp, NodeToObj(entryPtr->node));
6572 }
6573 Blt_TreeViewEventuallyRedraw(tvPtr);
6574 return TCL_OK;
6575 }
6576
6577
6578 /*
6579 *----------------------------------------------------------------------
6580 *
6581 * SelectionClearallOp
6582 *
6583 * Clears the entire selection.
6584 *
6585 * Results:
6586 * None.
6587 *
6588 * Side effects:
6589 * The selection changes.
6590 *
6591 *----------------------------------------------------------------------
6592 */
6593 /*ARGSUSED*/
6594 static int
SelectionClearallOp(tvPtr,interp,objc,objv)6595 SelectionClearallOp(tvPtr, interp, objc, objv)
6596 TreeView *tvPtr;
6597 Tcl_Interp *interp; /* Not used. */
6598 int objc; /* Not used. */
6599 Tcl_Obj *CONST *objv; /* Not used. */
6600 {
6601 Blt_TreeViewClearSelection(tvPtr);
6602 return TCL_OK;
6603 }
6604
6605 /*
6606 *----------------------------------------------------------------------
6607 *
6608 * SelectionIncludesOp
6609 *
6610 * Returns 1 if the element indicated by index is currently
6611 * selected, 0 if it isn't.
6612 *
6613 * Results:
6614 * None.
6615 *
6616 * Side effects:
6617 * The selection changes.
6618 *
6619 *----------------------------------------------------------------------
6620 */
6621 /*ARGSUSED*/
6622 static int
SelectionIncludesOp(tvPtr,interp,objc,objv)6623 SelectionIncludesOp(tvPtr, interp, objc, objv)
6624 TreeView *tvPtr;
6625 Tcl_Interp *interp;
6626 int objc; /* Not used. */
6627 Tcl_Obj *CONST *objv;
6628 {
6629 TreeViewEntry *entryPtr;
6630 int bool;
6631 TreeViewColumn *columnPtr;
6632
6633 columnPtr = NULL;
6634
6635 if (Blt_TreeViewGetEntry(tvPtr, objv[3], &entryPtr) != TCL_OK) {
6636 return TCL_ERROR;
6637 }
6638 if (objc > 4) {
6639 if (Blt_TreeViewGetColumn(interp, tvPtr, objv[4], &columnPtr) != TCL_OK) {
6640 return TCL_ERROR;
6641 }
6642 }
6643 bool = Blt_TreeViewEntryIsSelected(tvPtr, entryPtr, columnPtr);
6644 Tcl_SetObjResult(interp, Tcl_NewBooleanObj(bool));
6645 return TCL_OK;
6646 }
6647
6648 /*
6649 *----------------------------------------------------------------------
6650 *
6651 * SelectionCellsOp
6652 *
6653 * Returns pairs of node and col for selected cells.
6654 *
6655 * Results:
6656 * None.
6657 *
6658 *----------------------------------------------------------------------
6659 */
6660 /*ARGSUSED*/
6661 static int
SelectionCellsOp(tvPtr,interp,objc,objv)6662 SelectionCellsOp(tvPtr, interp, objc, objv)
6663 TreeView *tvPtr;
6664 Tcl_Interp *interp;
6665 int objc; /* Not used. */
6666 Tcl_Obj *CONST *objv;
6667 {
6668 TreeViewEntry *entryPtr;
6669 TreeViewColumn *columnPtr;
6670 Tcl_Obj *listObjPtr, *objPtr;
6671
6672 Blt_HashEntry *hPtr;
6673 Blt_HashSearch cursor;
6674 TreeViewValue *valuePtr;
6675 Blt_ChainLink *linkPtr;
6676
6677 if (!(tvPtr->selectMode & SELECT_MODE_CELLMASK)) {
6678 Tcl_AppendResult(interp, "-selectmode not 'cell' or 'multicell'", 0);
6679 return TCL_ERROR;
6680 }
6681 listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **)NULL);
6682
6683 for (hPtr = Blt_FirstHashEntry(&tvPtr->selectTable, &cursor);
6684 hPtr != NULL; hPtr = Blt_NextHashEntry(&cursor)) {
6685 entryPtr = (TreeViewEntry *)Blt_GetHashKey(&tvPtr->selectTable, hPtr);
6686 for (linkPtr = Blt_ChainFirstLink(tvPtr->colChainPtr);
6687 linkPtr != NULL; linkPtr = Blt_ChainNextLink(linkPtr)) {
6688
6689 columnPtr = Blt_ChainGetValue(linkPtr);
6690 valuePtr = (TreeViewValue *)Blt_TreeViewFindValue(entryPtr, columnPtr);
6691 if (valuePtr != NULL && valuePtr->selected) {
6692 objPtr = NodeToObj(entryPtr->node);
6693 Tcl_ListObjAppendElement(interp, listObjPtr, objPtr);
6694 objPtr = Tcl_NewStringObj(columnPtr->key, -1);
6695 Tcl_ListObjAppendElement(interp, listObjPtr, objPtr);
6696 }
6697 }
6698 }
6699
6700
6701 Tcl_SetObjResult(interp, listObjPtr);
6702
6703 return TCL_OK;
6704 }
6705 /*
6706 *----------------------------------------------------------------------
6707 *
6708 * SelectionMarkOp --
6709 *
6710 * Sets the selection mark to the element given by a index.
6711 * The selection anchor is the end of the selection that is movable
6712 * while dragging out a selection with the mouse. The index
6713 * "mark" may be used to refer to the anchor element.
6714 *
6715 * Results:
6716 * None.
6717 *
6718 * Side effects:
6719 * The selection changes.
6720 *
6721 *----------------------------------------------------------------------
6722 */
6723 /*ARGSUSED*/
6724 static int
SelectionMarkOp(tvPtr,interp,objc,objv)6725 SelectionMarkOp(tvPtr, interp, objc, objv)
6726 TreeView *tvPtr;
6727 Tcl_Interp *interp; /* Not used. */
6728 int objc; /* Not used. */
6729 Tcl_Obj *CONST *objv;
6730 {
6731 TreeViewEntry *entryPtr;
6732 TreeViewColumn *columnPtr;
6733
6734 columnPtr = NULL;
6735
6736 if (GetEntryFromObj(tvPtr, objv[3], &entryPtr) != TCL_OK) {
6737 return TCL_ERROR;
6738 }
6739 if (objc > 4) {
6740 if (Blt_TreeViewGetColumn(interp, tvPtr, objv[5], &columnPtr) != TCL_OK) {
6741 return TCL_ERROR;
6742 }
6743 }
6744 if (tvPtr->selAnchorPtr == NULL) {
6745 Tcl_AppendResult(interp, "selection anchor must be set first",
6746 (char *)NULL);
6747 return TCL_ERROR;
6748 }
6749 if (tvPtr->selMarkPtr != entryPtr) {
6750 Blt_ChainLink *linkPtr, *nextPtr;
6751 TreeViewEntry *selectPtr;
6752
6753 /* Deselect entry from the list all the way back to the anchor. */
6754 for (linkPtr = Blt_ChainLastLink(tvPtr->selChainPtr); linkPtr != NULL;
6755 linkPtr = nextPtr) {
6756 nextPtr = Blt_ChainPrevLink(linkPtr);
6757 selectPtr = Blt_ChainGetValue(linkPtr);
6758 if (selectPtr == tvPtr->selAnchorPtr) {
6759 break;
6760 }
6761 Blt_TreeViewDeselectEntry(tvPtr, selectPtr, NULL);
6762 }
6763 tvPtr->flags &= ~TV_SELECT_MASK;
6764 tvPtr->flags |= TV_SELECT_SET;
6765 SelectRange(tvPtr, tvPtr->selAnchorPtr, entryPtr);
6766 Tcl_SetObjResult(interp, NodeToObj(entryPtr->node));
6767 tvPtr->selMarkPtr = entryPtr;
6768
6769 Blt_TreeViewEventuallyRedraw(tvPtr);
6770 if (tvPtr->selectCmd != NULL) {
6771 EventuallyInvokeSelectCmd(tvPtr);
6772 }
6773 }
6774 return TCL_OK;
6775 }
6776
6777 /*
6778 *----------------------------------------------------------------------
6779 *
6780 * SelectionPresentOp
6781 *
6782 * Returns 1 if there is a selection and 0 if it isn't.
6783 *
6784 * Results:
6785 * A standard Tcl result. interp->result will contain a
6786 * boolean string indicating if there is a selection.
6787 *
6788 *----------------------------------------------------------------------
6789 */
6790 /*ARGSUSED*/
6791 static int
SelectionPresentOp(tvPtr,interp,objc,objv)6792 SelectionPresentOp(tvPtr, interp, objc, objv)
6793 TreeView *tvPtr;
6794 Tcl_Interp *interp;
6795 int objc; /* Not used. */
6796 Tcl_Obj *CONST *objv;
6797 {
6798 int bool;
6799
6800 bool = (Blt_ChainGetLength(tvPtr->selChainPtr) > 0);
6801 Tcl_SetObjResult(interp, Tcl_NewBooleanObj(bool));
6802 return TCL_OK;
6803 }
6804
6805 /*
6806 *----------------------------------------------------------------------
6807 *
6808 * SelectionSetOp
6809 *
6810 * Selects, deselects, or toggles all of the elements in the
6811 * range between first and last, inclusive, without affecting the
6812 * selection state of elements outside that range.
6813 *
6814 * Results:
6815 * None.
6816 *
6817 * Side effects:
6818 * The selection changes.
6819 *
6820 *----------------------------------------------------------------------
6821 */
6822 /*ARGSUSED*/
6823 static int
SelectionSetOp(tvPtr,interp,objc,objv)6824 SelectionSetOp(tvPtr, interp, objc, objv)
6825 TreeView *tvPtr;
6826 Tcl_Interp *interp;
6827 int objc; /* Not used. */
6828 Tcl_Obj *CONST *objv;
6829 {
6830 TreeViewEntry *firstPtr, *lastPtr;
6831 TreeViewColumn *columnPtr;
6832 char *string;
6833
6834 columnPtr = NULL;
6835 tvPtr->flags &= ~TV_SELECT_MASK;
6836 string = Tcl_GetString(objv[2]);
6837 switch (string[0]) {
6838 case 's':
6839 tvPtr->flags |= TV_SELECT_SET;
6840 break;
6841 case 'c':
6842 tvPtr->flags |= TV_SELECT_CLEAR;
6843 break;
6844 case 't':
6845 tvPtr->flags |= TV_SELECT_TOGGLE;
6846 break;
6847 }
6848 if (Blt_TreeViewGetEntry(tvPtr, objv[3], &firstPtr) != TCL_OK) {
6849 return TCL_ERROR;
6850 }
6851 if ((firstPtr->flags & ENTRY_HIDDEN) &&
6852 (!(tvPtr->flags & TV_SELECT_CLEAR))) {
6853 Tcl_AppendResult(interp, "can't select hidden node \"",
6854 Tcl_GetString(objv[3]), "\"", (char *)NULL);
6855 return TCL_ERROR;
6856 }
6857 lastPtr = firstPtr;
6858 if (objc > 4) {
6859 if (Blt_TreeViewGetEntry(tvPtr, objv[4], &lastPtr) != TCL_OK) {
6860 return TCL_ERROR;
6861 }
6862 if ((lastPtr->flags & ENTRY_HIDDEN) &&
6863 (!(tvPtr->flags & TV_SELECT_CLEAR))) {
6864 Tcl_AppendResult(interp, "can't select hidden node \"",
6865 Tcl_GetString(objv[4]), "\"", (char *)NULL);
6866 return TCL_ERROR;
6867 }
6868 }
6869 if (objc > 5) {
6870 if (Blt_TreeViewGetColumn(interp, tvPtr, objv[5], &columnPtr) != TCL_OK) {
6871 return TCL_ERROR;
6872 }
6873 }
6874 if (firstPtr == lastPtr) {
6875 SelectEntryApplyProc(tvPtr, firstPtr, columnPtr);
6876 } else {
6877 SelectRange(tvPtr, firstPtr, lastPtr, columnPtr);
6878 }
6879 /* Set both the anchor and the mark. Indicates that a single entry
6880 * is selected. */
6881 if (tvPtr->selAnchorPtr == NULL) {
6882 tvPtr->selAnchorPtr = firstPtr;
6883 }
6884 if (tvPtr->flags & TV_SELECT_EXPORT) {
6885 Tk_OwnSelection(tvPtr->tkwin, XA_PRIMARY, LostSelection, tvPtr);
6886 }
6887 Blt_TreeViewEventuallyRedraw(tvPtr);
6888 if (tvPtr->selectCmd != NULL) {
6889 EventuallyInvokeSelectCmd(tvPtr);
6890 }
6891 return TCL_OK;
6892 }
6893
6894 /*
6895 *----------------------------------------------------------------------
6896 *
6897 * SelectionOp --
6898 *
6899 * This procedure handles the individual options for text
6900 * selections. The selected text is designated by start and end
6901 * indices into the text pool. The selected segment has both a
6902 * anchored and unanchored ends.
6903 *
6904 * Results:
6905 * None.
6906 *
6907 * Side effects:
6908 * The selection changes.
6909 *
6910 *----------------------------------------------------------------------
6911 */
6912 static Blt_OpSpec selectionOps[] =
6913 {
6914 {"anchor", 1, (Blt_Op)SelectionAnchorOp, 3, 5, "?tagOrId? ?column?",},
6915 {"cells", 1, (Blt_Op)SelectionCellsOp, 3, 3, "",},
6916 {"clear", 5, (Blt_Op)SelectionSetOp, 4, 6, "first ?last? ?column?",},
6917 {"clearall", 6, (Blt_Op)SelectionClearallOp, 3, 3, "",},
6918 {"includes", 1, (Blt_Op)SelectionIncludesOp, 4, 5, "tagOrId ?column?",},
6919 {"mark", 1, (Blt_Op)SelectionMarkOp, 4, 5, "tagOrId ?column?",},
6920 {"present", 1, (Blt_Op)SelectionPresentOp, 3, 3, "",},
6921 {"set", 1, (Blt_Op)SelectionSetOp, 4, 6, "first ?last? ?column?",},
6922 {"toggle", 1, (Blt_Op)SelectionSetOp, 4, 6, "first ?last? ?column?",},
6923 };
6924 static int nSelectionOps = sizeof(selectionOps) / sizeof(Blt_OpSpec);
6925
6926 static int
SelectionOp(tvPtr,interp,objc,objv)6927 SelectionOp(tvPtr, interp, objc, objv)
6928 TreeView *tvPtr;
6929 Tcl_Interp *interp;
6930 int objc;
6931 Tcl_Obj *CONST *objv;
6932 {
6933 Blt_Op proc;
6934 int result;
6935
6936 proc = Blt_GetOpFromObj(interp, nSelectionOps, selectionOps, BLT_OP_ARG2,
6937 objc, objv, 0);
6938 if (proc == NULL) {
6939 return TCL_ERROR;
6940 }
6941 result = (*proc) (tvPtr, interp, objc, objv);
6942 return result;
6943 }
6944
6945
6946 /*
6947 *----------------------------------------------------------------------
6948 *
6949 * TagForgetOp --
6950 *
6951 *----------------------------------------------------------------------
6952 */
6953 /*ARGSUSED*/
6954 static int
TagForgetOp(tvPtr,interp,objc,objv)6955 TagForgetOp(tvPtr, interp, objc, objv)
6956 TreeView *tvPtr;
6957 Tcl_Interp *interp;
6958 int objc; /* Not used. */
6959 Tcl_Obj *CONST *objv;
6960 {
6961 register int i;
6962
6963 for (i = 3; i < objc; i++) {
6964 if (Blt_TreeForgetTag(tvPtr->tree, Tcl_GetString(objv[i])) != TCL_OK) {
6965 return TCL_ERROR;
6966 }
6967 }
6968 return TCL_OK;
6969 }
6970
6971 /*
6972 *----------------------------------------------------------------------
6973 *
6974 * TagNamesOp --
6975 *
6976 *----------------------------------------------------------------------
6977 */
6978 static int
TagNamesOp(tvPtr,interp,objc,objv)6979 TagNamesOp(tvPtr, interp, objc, objv)
6980 TreeView *tvPtr;
6981 Tcl_Interp *interp;
6982 int objc;
6983 Tcl_Obj *CONST *objv;
6984 {
6985 Tcl_Obj *listObjPtr, *objPtr;
6986
6987 listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **) NULL);
6988 /* objPtr = Tcl_NewStringObj("all", -1);
6989 Tcl_ListObjAppendElement(interp, listObjPtr, objPtr);
6990 objPtr = Tcl_NewStringObj("nonroot", -1);
6991 Tcl_ListObjAppendElement(interp, listObjPtr, objPtr);
6992 objPtr = Tcl_NewStringObj("rootchildren", -1);
6993 Tcl_ListObjAppendElement(interp, listObjPtr, objPtr);*/
6994 if (objc == 3) {
6995 Blt_HashEntry *hPtr;
6996 Blt_HashSearch cursor;
6997 Blt_TreeTagEntry *tPtr;
6998
6999 objPtr = Tcl_NewStringObj("root", -1);
7000 Tcl_ListObjAppendElement(interp, listObjPtr, objPtr);
7001 for (hPtr = Blt_TreeFirstTag(tvPtr->tree, &cursor); hPtr != NULL;
7002 hPtr = Blt_NextHashEntry(&cursor)) {
7003 tPtr = Blt_GetHashValue(hPtr);
7004 objPtr = Tcl_NewStringObj(tPtr->tagName, -1);
7005 Tcl_ListObjAppendElement(interp, listObjPtr, objPtr);
7006 }
7007 } else {
7008 register int i;
7009 TreeViewEntry *entryPtr;
7010 Blt_List list;
7011 Blt_ListNode listNode;
7012
7013 for (i = 3; i < objc; i++) {
7014 if (Blt_TreeViewGetEntry(tvPtr, objv[i], &entryPtr) != TCL_OK) {
7015 return TCL_ERROR;
7016 }
7017 list = Blt_ListCreate(BLT_ONE_WORD_KEYS);
7018 Blt_TreeViewGetTags(interp, tvPtr, entryPtr, list);
7019 for (listNode = Blt_ListFirstNode(list); listNode != NULL;
7020 listNode = Blt_ListNextNode(listNode)) {
7021 objPtr = Tcl_NewStringObj(Blt_ListGetKey(listNode), -1);
7022 Tcl_ListObjAppendElement(interp, listObjPtr, objPtr);
7023 }
7024 Blt_ListDestroy(list);
7025 }
7026 }
7027 Tcl_SetObjResult(interp, listObjPtr);
7028 return TCL_OK;
7029 }
7030
7031 /*
7032 *----------------------------------------------------------------------
7033 *
7034 * TagNodesOp --
7035 *
7036 *----------------------------------------------------------------------
7037 */
7038 static int
TagNodesOp(tvPtr,interp,objc,objv)7039 TagNodesOp(tvPtr, interp, objc, objv)
7040 TreeView *tvPtr;
7041 Tcl_Interp *interp;
7042 int objc;
7043 Tcl_Obj *CONST *objv;
7044 {
7045 Blt_HashEntry *hPtr;
7046 Blt_HashSearch cursor;
7047 Blt_HashTable nodeTable;
7048 Blt_TreeNode node;
7049 TreeViewTagInfo info = {0};
7050 Tcl_Obj *listObjPtr;
7051 Tcl_Obj *objPtr;
7052 TreeViewEntry *entryPtr;
7053 int isNew;
7054 register int i;
7055
7056 Blt_InitHashTable(&nodeTable, BLT_ONE_WORD_KEYS);
7057 for (i = 3; i < objc; i++) {
7058 if (Blt_TreeViewFindTaggedEntries(tvPtr, objv[i], &info) != TCL_OK) {
7059 Tcl_ResetResult(interp);
7060 Blt_TreeViewDoneTaggedEntries(&info);
7061 continue;
7062 }
7063 for (entryPtr = Blt_TreeViewFirstTaggedEntry(&info); entryPtr != NULL;
7064 entryPtr = Blt_TreeViewNextTaggedEntry(&info)) {
7065 Blt_CreateHashEntry(&nodeTable, (char *)entryPtr->node, &isNew);
7066 }
7067 Blt_TreeViewDoneTaggedEntries(&info);
7068 }
7069 listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **) NULL);
7070 for (hPtr = Blt_FirstHashEntry(&nodeTable, &cursor); hPtr != NULL;
7071 hPtr = Blt_NextHashEntry(&cursor)) {
7072 node = (Blt_TreeNode)Blt_GetHashKey(&nodeTable, hPtr);
7073 objPtr = Tcl_NewIntObj(Blt_TreeNodeId(node));
7074 Tcl_ListObjAppendElement(interp, listObjPtr, objPtr);
7075 }
7076 Tcl_SetObjResult(interp, listObjPtr);
7077 Blt_DeleteHashTable(&nodeTable);
7078 return TCL_OK;
7079 }
7080
7081 static int
TagDefine(tvPtr,interp,tagName)7082 TagDefine(tvPtr, interp, tagName)
7083 TreeView *tvPtr;
7084 Tcl_Interp *interp;
7085 char *tagName;
7086 {
7087 TreeViewEntry *entryPtr;
7088
7089 if (strcmp(tagName, "root") == 0 || strcmp(tagName, "all") == 0 ||
7090 strcmp(tagName, "nonroot") == 0 || strcmp(tagName, "rootchildren") == 0) {
7091 Tcl_AppendResult(interp, "can't add reserved tag \"", tagName, "\"",
7092 (char *)NULL);
7093 return TCL_ERROR;
7094 }
7095 if (isdigit(UCHAR(tagName[0]))) {
7096 Tcl_AppendResult(interp, "invalid tag \"", tagName,
7097 "\": can't start with digit", (char *)NULL);
7098 return TCL_ERROR;
7099 }
7100 if (strstr(tagName,"->") != NULL) {
7101 Tcl_AppendResult(tvPtr->interp, "invalid tag \"", tagName,
7102 "\": can't contain \"->\"", (char *)NULL);
7103 return TCL_ERROR;
7104 }
7105 if (tagName[0] == '@') {
7106 Tcl_AppendResult(tvPtr->interp, "invalid tag \"", tagName,
7107 "\": can't start with \"@\"", (char *)NULL);
7108 return TCL_ERROR;
7109 }
7110 if (GetEntryFromSpecialId(tvPtr, tagName, &entryPtr) == TCL_OK) {
7111 Tcl_AppendResult(interp, "invalid tag \"", tagName,
7112 "\": is a special id", (char *)NULL);
7113 return TCL_ERROR;
7114 }
7115 return Blt_TreeAddTag(tvPtr->tree, NULL, tagName);
7116 }
7117
7118 /*
7119 *----------------------------------------------------------------------
7120 *
7121 * TagAddOp --
7122 *
7123 *----------------------------------------------------------------------
7124 */
7125 static int
TagAddOp(tvPtr,interp,objc,objv)7126 TagAddOp(tvPtr, interp, objc, objv)
7127 TreeView *tvPtr;
7128 Tcl_Interp *interp;
7129 int objc;
7130 Tcl_Obj *CONST *objv;
7131 {
7132 TreeViewEntry *entryPtr;
7133 register int i;
7134 char *tagName;
7135 TreeViewTagInfo info = {0};
7136
7137 tagName = Tcl_GetString(objv[3]);
7138 TagDefine(tvPtr, interp, tagName);
7139 for (i = 4; i < objc; i++) {
7140 if (Blt_TreeViewFindTaggedEntries(tvPtr, objv[i], &info) != TCL_OK) {
7141 return TCL_ERROR;
7142 }
7143 for (entryPtr = Blt_TreeViewFirstTaggedEntry(&info); entryPtr != NULL;
7144 entryPtr = Blt_TreeViewNextTaggedEntry(&info)) {
7145 if (AddTag(tvPtr, entryPtr->node, tagName) != TCL_OK) {
7146 Blt_TreeViewDoneTaggedEntries(&info);
7147 return TCL_ERROR;
7148 }
7149 }
7150 Blt_TreeViewDoneTaggedEntries(&info);
7151 }
7152 return TCL_OK;
7153 }
7154
7155 /*
7156 *----------------------------------------------------------------------
7157 *
7158 * TagExistsOp --
7159 *
7160 *----------------------------------------------------------------------
7161 */
7162 static int
TagExistsOp(tvPtr,interp,objc,objv)7163 TagExistsOp(tvPtr, interp, objc, objv)
7164 TreeView *tvPtr;
7165 Tcl_Interp *interp;
7166 int objc;
7167 Tcl_Obj *CONST *objv;
7168 {
7169 TreeViewEntry *entryPtr;
7170 char *tagName;
7171 TreeViewTagInfo info = {0};
7172 int exists = 0;
7173
7174 if (objc == 4) {
7175 if (Blt_TreeViewFindTaggedEntries(tvPtr, objv[3], &info) == TCL_OK) {
7176 exists = 1;
7177 } else {
7178 Tcl_ResetResult(interp);
7179 }
7180 Blt_TreeViewDoneTaggedEntries(&info);
7181 } else {
7182 tagName = Tcl_GetString(objv[3]);
7183 if (GetEntryFromObj(tvPtr, objv[4], &entryPtr) != TCL_OK) {
7184 return TCL_ERROR;
7185 }
7186 exists = Blt_TreeHasTag(tvPtr->tree, entryPtr->node, tagName);
7187 }
7188 Tcl_SetObjResult(interp, Tcl_NewIntObj(exists));
7189 return TCL_OK;
7190 }
7191
7192
7193 /*
7194 *----------------------------------------------------------------------
7195 *
7196 * TagDeleteOp --
7197 *
7198 *----------------------------------------------------------------------
7199 */
7200 /*ARGSUSED*/
7201 static int
TagDeleteOp(tvPtr,interp,objc,objv)7202 TagDeleteOp(tvPtr, interp, objc, objv)
7203 TreeView *tvPtr;
7204 Tcl_Interp *interp; /* Not used. */
7205 int objc;
7206 Tcl_Obj *CONST *objv;
7207 {
7208 char *tagName;
7209 int result;
7210 Blt_HashTable *tablePtr;
7211 TreeViewTagInfo info = {0};
7212
7213 tagName = Tcl_GetString(objv[3]);
7214 tablePtr = Blt_TreeTagHashTable(tvPtr->tree, tagName);
7215 if (tablePtr != NULL) {
7216 register int i;
7217 Blt_HashEntry *hPtr;
7218 TreeViewEntry *entryPtr;
7219
7220 for (i = 4; i < objc; i++) {
7221 if (Blt_TreeViewFindTaggedEntries(tvPtr, objv[i], &info)!= TCL_OK) {
7222 return TCL_ERROR;
7223 }
7224 for (entryPtr = Blt_TreeViewFirstTaggedEntry(&info);
7225 entryPtr != NULL;
7226 entryPtr = Blt_TreeViewNextTaggedEntry(&info)) {
7227 hPtr = Blt_FindHashEntry(tablePtr, (char *)entryPtr->node);
7228 if (hPtr != NULL) {
7229 result = Blt_TreeTagDelTrace(tvPtr->tree, entryPtr->node, tagName);
7230 if (result != TCL_OK) {
7231 if (result != TCL_BREAK) {
7232 Blt_TreeViewDoneTaggedEntries(&info);
7233 return TCL_ERROR;
7234 }
7235 continue;
7236 }
7237 Blt_DeleteHashEntry(tablePtr, hPtr);
7238 }
7239 }
7240 Blt_TreeViewDoneTaggedEntries(&info);
7241 }
7242 }
7243 return TCL_OK;
7244 }
7245
7246 /*
7247 *----------------------------------------------------------------------
7248 *
7249 * TagOp --
7250 *
7251 *----------------------------------------------------------------------
7252 */
7253 static Blt_OpSpec tagOps[] = {
7254 {"add", 1, (Blt_Op)TagAddOp, 4, 0, "tag id...",},
7255 {"delete", 2, (Blt_Op)TagDeleteOp, 5, 0, "tag id...",},
7256 {"exists", 2, (Blt_Op)TagExistsOp, 4, 5, "tag ?id?",},
7257 {"forget", 1, (Blt_Op)TagForgetOp, 4, 0, "tag...",},
7258 {"names", 2, (Blt_Op)TagNamesOp, 3, 0, "?id...?",},
7259 {"nodes", 2, (Blt_Op)TagNodesOp, 4, 0, "tag ?tag...?",},
7260 };
7261
7262 static int nTagOps = sizeof(tagOps) / sizeof(Blt_OpSpec);
7263
7264 static int
TagOp(tvPtr,interp,objc,objv)7265 TagOp(tvPtr, interp, objc, objv)
7266 TreeView *tvPtr;
7267 Tcl_Interp *interp;
7268 int objc;
7269 Tcl_Obj *CONST *objv;
7270 {
7271 Blt_Op proc;
7272 int result;
7273
7274 proc = Blt_GetOpFromObj(interp, nTagOps, tagOps, BLT_OP_ARG2, objc, objv,
7275 0);
7276 if (proc == NULL) {
7277 return TCL_ERROR;
7278 }
7279 result = (*proc)(tvPtr, interp, objc, objv);
7280 return result;
7281 }
7282
7283 /*ARGSUSED*/
7284 static int
ToggleOp(tvPtr,interp,objc,objv)7285 ToggleOp(tvPtr, interp, objc, objv)
7286 TreeView *tvPtr;
7287 Tcl_Interp *interp; /* Not used. */
7288 int objc;
7289 Tcl_Obj *CONST *objv;
7290 {
7291 TreeViewEntry *entryPtr;
7292 TreeViewTagInfo info = {0};
7293 int result = TCL_OK;
7294
7295 if (Blt_TreeViewFindTaggedEntries(tvPtr, objv[2], &info) != TCL_OK) {
7296 return TCL_ERROR;
7297 }
7298 for (entryPtr = Blt_TreeViewFirstTaggedEntry(&info); entryPtr != NULL && result == TCL_OK;
7299 entryPtr = Blt_TreeViewNextTaggedEntry(&info)) {
7300 if (entryPtr == NULL) {
7301 Blt_TreeViewDoneTaggedEntries(&info);
7302 return TCL_OK;
7303 }
7304 if (entryPtr->flags & ENTRY_CLOSED) {
7305 result = Blt_TreeViewOpenEntry(tvPtr, entryPtr);
7306 } else {
7307 Blt_TreeViewPruneSelection(tvPtr, entryPtr);
7308 if ((tvPtr->focusPtr != NULL) &&
7309 (Blt_TreeIsAncestor(entryPtr->node, tvPtr->focusPtr->node))) {
7310 tvPtr->focusPtr = entryPtr;
7311 Blt_SetFocusItem(tvPtr->bindTable, tvPtr->focusPtr, ITEM_ENTRY);
7312 }
7313 if ((tvPtr->selAnchorPtr != NULL) &&
7314 (Blt_TreeIsAncestor(entryPtr->node,
7315 tvPtr->selAnchorPtr->node))) {
7316 tvPtr->selAnchorPtr = NULL;
7317 }
7318 result = Blt_TreeViewCloseEntry(tvPtr, entryPtr);
7319 }
7320 }
7321 Blt_TreeViewDoneTaggedEntries(&info);
7322 if (result == TCL_OK) {
7323 tvPtr->flags |= TV_SCROLL;
7324 Blt_TreeViewEventuallyRedraw(tvPtr);
7325 }
7326 return result;
7327 }
7328
7329 static int
XViewOp(tvPtr,interp,objc,objv)7330 XViewOp(tvPtr, interp, objc, objv)
7331 TreeView *tvPtr;
7332 Tcl_Interp *interp;
7333 int objc;
7334 Tcl_Obj *CONST *objv;
7335 {
7336 int width, worldWidth;
7337
7338 width = VPORTWIDTH(tvPtr);
7339 worldWidth = tvPtr->worldWidth;
7340 if (objc == 2) {
7341 double fract;
7342 Tcl_Obj *listObjPtr;
7343
7344 /*
7345 * Note that we are bounding the fractions between 0.0 and 1.0
7346 * to support the "canvas"-style of scrolling.
7347 */
7348 listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **)NULL);
7349 fract = (double)tvPtr->xOffset / worldWidth;
7350 fract = CLAMP(fract, 0.0, 1.0);
7351 Tcl_ListObjAppendElement(interp, listObjPtr, Tcl_NewDoubleObj(fract));
7352 fract = (double)(tvPtr->xOffset + width) / worldWidth;
7353 fract = CLAMP(fract, 0.0, 1.0);
7354 Tcl_ListObjAppendElement(interp, listObjPtr, Tcl_NewDoubleObj(fract));
7355 Tcl_SetObjResult(interp, listObjPtr);
7356 return TCL_OK;
7357 }
7358 if (tvPtr->noScroll) { return TCL_OK; }
7359 if (Blt_GetScrollInfoFromObj(interp, objc - 2, objv + 2, &tvPtr->xOffset,
7360 worldWidth, width, tvPtr->xScrollUnits, tvPtr->scrollMode)
7361 != TCL_OK) {
7362 return TCL_ERROR;
7363 }
7364 tvPtr->flags |= TV_XSCROLL;
7365 Blt_TreeViewEventuallyRedraw(tvPtr);
7366 return TCL_OK;
7367 }
7368
7369 static int
YViewOp(tvPtr,interp,objc,objv)7370 YViewOp(tvPtr, interp, objc, objv)
7371 TreeView *tvPtr;
7372 Tcl_Interp *interp;
7373 int objc;
7374 Tcl_Obj *CONST *objv;
7375 {
7376 int height, worldHeight;
7377
7378 height = VPORTHEIGHT(tvPtr);
7379 worldHeight = tvPtr->worldHeight;
7380 if (objc == 2) {
7381 double fract;
7382 Tcl_Obj *listObjPtr;
7383
7384 listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **)NULL);
7385 /* Report first and last fractions */
7386 fract = (double)tvPtr->yOffset / worldHeight;
7387 fract = CLAMP(fract, 0.0, 1.0);
7388 Tcl_ListObjAppendElement(interp, listObjPtr, Tcl_NewDoubleObj(fract));
7389 fract = (double)(tvPtr->yOffset + height) / worldHeight;
7390 fract = CLAMP(fract, 0.0, 1.0);
7391 Tcl_ListObjAppendElement(interp, listObjPtr, Tcl_NewDoubleObj(fract));
7392 Tcl_SetObjResult(interp, listObjPtr);
7393 return TCL_OK;
7394 }
7395 if (tvPtr->noScroll) { return TCL_OK; }
7396 if (Blt_GetScrollInfoFromObj(interp, objc - 2, objv + 2, &tvPtr->yOffset,
7397 worldHeight, height, tvPtr->yScrollUnits, tvPtr->scrollMode)
7398 != TCL_OK) {
7399 return TCL_ERROR;
7400 }
7401 tvPtr->flags |= TV_SCROLL;
7402 Blt_TreeViewEventuallyRedraw(tvPtr);
7403 return TCL_OK;
7404 }
7405
7406 /*
7407 * --------------------------------------------------------------
7408 *
7409 * Blt_TreeViewWidgetInstCmd --
7410 *
7411 * This procedure is invoked to process commands on behalf of
7412 * the treeview widget.
7413 *
7414 * Results:
7415 * A standard Tcl result.
7416 *
7417 * Side effects:
7418 * See the user documentation.
7419 *
7420 * --------------------------------------------------------------
7421 */
7422 static Blt_OpSpec treeViewOps[] =
7423 {
7424 {"bbox", 2, (Blt_Op)BboxOp, 3, 0, "tagOrId...",},
7425 {"bind", 2, (Blt_Op)BindOp, 3, 5, "tagName ?sequence command?",},
7426 {"button", 2, (Blt_Op)ButtonOp, 2, 0, "args",},
7427 {"cget", 2, (Blt_Op)CgetOp, 3, 3, "option",},
7428 {"close", 2, (Blt_Op)CloseOp, 2, 0, "?-recurse? ?-parent? tagOrId...",},
7429 {"column", 3, (Blt_Op)Blt_TreeViewColumnOp, 2, 0, "oper args",},
7430 {"configure", 3, (Blt_Op)ConfigureOp, 2, 0, "?option value?...",},
7431 {"curselection", 2, (Blt_Op)CurselectionOp, 2, 2, "",},
7432 {"delete", 1, (Blt_Op)DeleteOp, 2, 0, "tagOrId ?tagOrId...?",},
7433 {"edit", 2, (Blt_Op)EditOp, 3, 0, "?-root|-test|-noscroll|-scroll? ?x y?",},
7434 {"entry", 2, (Blt_Op)EntryOp, 2, 0, "oper args",},
7435 {"find", 3, (Blt_Op)FindOp, 2, 0, "?switches? ?first last?",},
7436 {"focus", 2, (Blt_Op)FocusOp, 2, 3, "?tagOrId?",},
7437 {"get", 1, (Blt_Op)GetOp, 2, 0, "?-full? ?-labels? tagOrId ?tagOrId...?",},
7438 {"hide", 1, (Blt_Op)HideOp, 2, 0, "?switches? ?tagOrId...?",},
7439 {"index", 3, (Blt_Op)IndexOp, 3, 8, "?-at tagOrId? ?-path? ?-quiet? string",},
7440 {"insert", 3, (Blt_Op)InsertOp, 3, 0, "?-at tagOrId? ?-styles styleslist? ?-tags taglist? position label ?label...? ?option value?",},
7441 {"move", 1, (Blt_Op)MoveOp, 5, 5, "tagOrId into|before|after tagOrId",},
7442 {"nearest", 1, (Blt_Op)NearestOp, 4, 7, "?-root? ?-strict? x y ?varName?",},
7443 {"open", 1, (Blt_Op)OpenOp, 2, 0, "?-recurse? ?-parent? tagOrId...",},
7444 {"range", 1, (Blt_Op)RangeOp, 4, 5, "?-open? tagOrId tagOrId",},
7445 {"scan", 2, (Blt_Op)ScanOp, 5, 5, "dragto|mark x y",},
7446 {"see", 3, (Blt_Op)SeeOp, 3, 5, "?-anchor anchor? tagOrId",},
7447 {"selection", 3, (Blt_Op)SelectionOp, 2, 0, "oper args",},
7448 {"show", 2, (Blt_Op)ShowOp, 2, 0, "?switches? ?tagOrId...?",},
7449 {"sort", 2, (Blt_Op)Blt_TreeViewSortOp, 2, 0, "args",},
7450 {"style", 2, (Blt_Op)Blt_TreeViewStyleOp, 2, 0, "args",},
7451 {"tag", 2, (Blt_Op)TagOp, 2, 0, "oper args",},
7452 {"toggle", 2, (Blt_Op)ToggleOp, 3, 3, "tagOrId",},
7453 {"xview", 1, (Blt_Op)XViewOp, 2, 5, "?moveto fract? ?scroll number what?",},
7454 {"yview", 1, (Blt_Op)YViewOp, 2, 5, "?moveto fract? ?scroll number what?",},
7455 };
7456
7457 static int nTreeViewOps = sizeof(treeViewOps) / sizeof(Blt_OpSpec);
7458
7459 int
Blt_TreeViewWidgetInstCmd(clientData,interp,objc,objv)7460 Blt_TreeViewWidgetInstCmd(clientData, interp, objc, objv)
7461 ClientData clientData; /* Information about the widget. */
7462 Tcl_Interp *interp; /* Interpreter to report errors back to. */
7463 int objc; /* Number of arguments. */
7464 Tcl_Obj *CONST *objv; /* Vector of argument strings. */
7465 {
7466 Blt_Op proc;
7467 TreeView *tvPtr = clientData;
7468 int result;
7469
7470 proc = Blt_GetOpFromObj(interp, nTreeViewOps, treeViewOps, BLT_OP_ARG1,
7471 objc, objv, 0);
7472 if (proc == NULL) {
7473 return TCL_ERROR;
7474 }
7475 Blt_TreeViewChanged(tvPtr);
7476 Tcl_Preserve(tvPtr);
7477 result = (*proc) (tvPtr, interp, objc, objv);
7478 Tcl_Release(tvPtr);
7479 return result;
7480 }
7481
7482 #endif /* NO_TREEVIEW */
7483