build git 2.17.1
[AROS-Contrib.git] / bgui / gadgets / TreeView / TVUtil.c
blob8eeb5ea2da25ec6beeda3429a5d36fd7802b1bb5
1 /*
2 * @(#) $Header$
4 * BGUI Tree List View class
6 * (C) Copyright 1999 Manuel Lemos.
7 * (C) Copyright 1996-1999 Nick Christie.
8 * All Rights Reserved.
10 * $Log$
11 * Revision 42.0 2000/05/09 22:22:05 mlemos
12 * Bumped to revision 42.0 before handing BGUI to AROS team
14 * Revision 41.11 2000/05/09 20:35:52 mlemos
15 * Bumped to revision 41.11
17 * Revision 1.2 2000/05/09 20:00:49 mlemos
18 * Merged with the branch Manuel_Lemos_fixes.
20 * Revision 1.1.2.2 1999/05/25 00:03:58 mlemos
21 * Fixed bug of not testing the end of the tree properly when fetching the
22 * next node.
24 * Revision 1.1.2.1 1999/02/21 04:08:07 mlemos
25 * Nick Christie sources.
31 /************************************************************************
32 ********************* TREEVIEW UTILITY ROUTINES ***********************
33 ************************************************************************/
35 /************************************************************************
36 ****************************** INCLUDES *******************************
37 ************************************************************************/
39 #include "TreeViewPrivate.h"
40 #include "TVUtil.h"
42 /************************************************************************
43 ************************** LOCAL DEFINITIONS **************************
44 *************************************************************************/
47 /************************************************************************
48 ***************************** REFERENCES ******************************
49 *************************************************************************/
52 /************************************************************************
53 ***************************** PROTOTYPES ******************************
54 ************************************************************************/
57 * All global, listed in TVUtil.h
60 /************************************************************************
61 ***************************** LOCAL DATA ******************************
62 ************************************************************************/
65 /************************************************************************
66 *************************** TV_DOSUPERNEW() ***************************
67 *************************************************************************
68 * Calls OM_NEW on the superclass, allowing a taglist to be built on
69 * the stack. Returns the new object, or NULL on failure.
71 *************************************************************************/
73 ULONG TV_DoSuperNew(Class *cl,Object *obj,Tag tag1,...)
75 AROS_SLOWSTACKTAGS_PRE_AS(tag1, ULONG)
76 retval = (ULONG)DoSuperMethod(cl,obj,OM_NEW,AROS_SLOWSTACKTAGS_ARG(tag1),NULL);
77 AROS_SLOWSTACKTAGS_POST
80 /************************************************************************
81 ************************ TV_NOTIFYATTRCHANGE() ************************
82 *************************************************************************
83 * Notify about an attribute change, allowing a taglist to be built on
84 * the stack. Returns the result of the OM_NOTIFY method.
86 *************************************************************************/
88 ULONG TV_NotifyAttrChange(Object *obj,struct GadgetInfo *gi,
89 ULONG flags,Tag tag1,...)
91 AROS_SLOWSTACKTAGS_PRE_AS(tag1, ULONG)
92 return (ULONG)DoMethod(obj,OM_NOTIFY,AROS_SLOWSTACKTAGS_ARG(tag1),gi,flags);
93 AROS_SLOWSTACKTAGS_POST
97 /************************************************************************
98 ****************************** GETXXXX() ******************************
99 *************************************************************************
100 * Small list/node manipulation routines.
102 * TV_GetHead: returns first node, NULL if empty list.
103 * TV_GetTail: returns last node, NULL if empty list.
104 * TV_GetSucc: returns next node, NULL if no next.
105 * TV_GetPred: returns prev node, NULL if no prev.
107 * In all cases, node passed in may not be NULL, list must be
108 * correctly initialized, and node must be node (not list header).
110 *************************************************************************/
112 #ifndef TV_NODE_INLINE
114 NODEPTR TV_GetHead(LISTPTR list)
116 return(list->lh_Head->ln_Succ ? list->lh_Head : NULL);
119 NODEPTR TV_GetTail(LISTPTR list)
121 return(list->lh_TailPred->ln_Pred ? list->lh_TailPred : NULL);
124 NODEPTR TV_GetSucc(NODEPTR node)
126 return(node->ln_Succ->ln_Succ ? node->ln_Succ : NULL);
129 NODEPTR TV_GetPred(NODEPTR node)
131 return(node->ln_Pred->ln_Pred ? node->ln_Pred : NULL);
134 #endif
136 /************************************************************************
137 **************************** TV_ALLOCVEC() ****************************
138 *************************************************************************
139 * Like Exec/AllocVec(), but in a memory pool attached to the TVData
140 * supplied, if available. Memory type returned is always MEMF_ANY and
141 * MEMF_CLEAR.
143 *************************************************************************/
145 void *TV_AllocVec(TVData *tv,ULONG size)
147 ULONG *mem;
149 #ifdef MEMDBG
151 static ULONG Cookie[] = { 0xdeadbeef, 0xabadcafe };
153 if (tv->tv_MemPool)
154 mem = AllocPooled(tv->tv_MemPool,size + 4 + 2 * 8);
155 else
156 mem = AllocMem(size + 4 + 2 * 8,MEMF_STD);
158 if (mem)
160 mem[0] = size;
161 memcpy(&mem[1],Cookie,8);
162 mem = &mem[3];
163 memcpy(((UBYTE *)mem) + size,Cookie,8);
166 #else /* !MEMDBG */
168 if (tv->tv_MemPool)
170 if ((mem = AllocPooled(tv->tv_MemPool,size + 4)))
171 *mem++ = size;
173 else
174 mem = AllocVec(size,MEMF_STD);
176 #endif /* !MEMDBG */
178 return((void *)mem);
181 /************************************************************************
182 **************************** TV_FREEVEC() *****************************
183 *************************************************************************
184 * Like Exec/FreeVec(), but in a memory pool attached to the TVData
185 * supplied, if available.
187 *************************************************************************/
189 void TV_FreeVec(TVData *tv,void *mem)
191 ULONG *p,size;
193 #ifdef MEMDBG
195 BOOL ok;
196 static ULONG Cookie[2] = { 0xdeadbeef, 0xabadcafe };
198 if (mem)
200 ok = FALSE;
201 p = (ULONG *) (((UBYTE *) mem) - 12);
202 size = p[0];
203 if ((p[1] == Cookie[0]) && (p[2] == Cookie[1]) &&
204 /* WARNING! These two might not be longword aligned! */
205 (*((ULONG *)(((UBYTE *)&p[3]) + size)) == Cookie[0]) &&
206 (*((ULONG *)(((UBYTE *)&p[4]) + size)) == Cookie[1]))
207 ok = TRUE;
209 if (tv->tv_MemPool)
210 FreePooled(tv->tv_MemPool,p,size + 4 + 2 * 8);
211 else
212 FreeMem(p,size + 4 + 2 * 8);
214 if (!ok)
215 KPrintF("Treeview: Memory (size %lu) munged at 0x%08lx!\n",size,p);
218 #else /* !MEMDBG */
220 if (mem)
222 if (tv->tv_MemPool)
224 p = (ULONG *)mem;
225 size = *(--p);
226 FreePooled(tv->tv_MemPool,p,size + 4);
228 else
229 FreeVec(mem);
232 #endif /* !MEMDBG */
235 /************************************************************************
236 *************************** TV_ALLOCHOOK() ****************************
237 ************************************************************************/
239 HOOKPTR TV_AllocHook(HOOKFUNC handler,APTR data)
241 HOOKPTR hook;
243 if ((hook = AllocMem(sizeof(struct Hook),MEMF_STD)))
245 hook->h_Entry = handler;
246 hook->h_Data = data;
249 return(hook);
252 /************************************************************************
253 **************************** TV_FREEHOOK() ****************************
254 ************************************************************************/
256 void TV_FreeHook(HOOKPTR hook)
258 if (hook)
259 FreeMem(hook,sizeof(struct Hook));
262 /************************************************************************
263 *************************** TV_ALLOCSTRCPY() **************************
264 *************************************************************************
265 * Copy a string to AllocPool'd memory. Returns the new copy or NULL if
266 * alloc failed. You can ask for 'extra' bytes to be allocated after the
267 * string as well, these will be initialized to NULL.
269 *************************************************************************/
271 STRPTR TV_AllocStrCpy(TVData *tv,STRPTR s,ULONG extra)
273 STRPTR t;
275 t = NULL;
277 if (s)
279 if ((t = TV_AllocVec(tv,strlen(s) + extra + 1)))
280 strcpy(t,s);
283 return(t);
286 /************************************************************************
287 ************************* TV_ALLOCTREENODE() **************************
288 *************************************************************************
289 * Allocate a new TreeNode, passing the supplied 'entry' through the
290 * user's resource hook. Places the translated entry and the supplied
291 * flags in the treenode, but doesn't set the node's parent, or attach
292 * it to any list. The treenode's child list is initialised. Returns the
293 * new TreeNode, or NULL on failure.
295 *************************************************************************/
297 TNPTR TV_AllocTreeNode(TVData *tv,APTR entry,ULONG flags)
299 struct tvResource tvr;
300 TNPTR tn;
301 IPTR xentry;
303 tvr.tvr_Command = TVRC_MAKE;
304 tvr.tvr_Entry = entry;
306 if ((tn = TV_AllocVec(tv,sizeof(struct TreeNode))))
308 if ((xentry = CallHookPkt(tv->tv_ResourceHook,tv->tv_TreeView,&tvr)))
310 tn->tn_Entry = (APTR) xentry;
311 tn->tn_Flags = flags;
312 NewList(ChildListOf(tn));
314 else
316 TV_FreeVec(tv,tn);
317 tn = NULL;
321 return(tn);
324 /************************************************************************
325 ************************** TV_FREETREENODE() **************************
326 *************************************************************************
327 * Free a TreeNode allocated by TV_AllocTreeNode(). Can be safely passed
328 * a NULL pointer. Does not detach the node from any list. Does not free
329 * any child treenodes that may be attached. Frees the node's entry via
330 * the user's custom resource hook.
332 *************************************************************************/
334 void TV_FreeTreeNode(TVData *tv,TNPTR tn)
336 struct tvResource tvr;
338 if (tn)
340 tvr.tvr_Command = TVRC_KILL;
341 tvr.tvr_Entry = (APTR) tn->tn_Entry;
342 CallHookPkt(tv->tv_ResourceHook,tv->tv_TreeView,&tvr);
343 TV_FreeVec(tv,tn);
347 /************************************************************************
348 ************************ TV_FREETREENODELIST() ************************
349 *************************************************************************
350 * Free a list of TreeNodes, and all children. Does not re-initialise
351 * the list.
353 *************************************************************************/
355 void TV_FreeTreeNodeList(TVData *tv,LISTPTR list)
357 TNPTR tn,tn2;
359 tn2 = FirstChildIn(list);
361 while((tn = tn2)) /* assign and test */
363 tn2 = NextSiblingOf(tn);
364 TV_FreeTreeNodeList(tv,ChildListOf(tn));
365 TV_FreeTreeNode(tv,tn);
369 /************************************************************************
370 ************************* TV_TREENODEDEPTH() **************************
371 *************************************************************************
372 * Return the 'depth' of the given TreeNode within its hierarchy, ie.
373 * how many parents it has.
375 *************************************************************************/
377 ULONG TV_TreeNodeDepth(TNPTR tn)
379 ULONG depth;
381 depth = 0;
383 while((tn = ParentOf(tn)))
384 depth++;
386 return(depth);
389 /************************************************************************
390 ************************ TV_INDEXTOTREENODE() *************************
391 *************************************************************************
392 * Convert a ULONG 0-based index into the set of entries displayed in the
393 * listview, into a pointer to the node at that index. Returns NULL if
394 * there is no node with that index.
396 *************************************************************************/
398 TNPTR TV_IndexToTreeNode(TVData *tv,ULONG idx)
400 TNPTR tn;
402 tn = FirstChildIn(RootList(tv));
404 while(tn && idx)
406 tn = TV_GetNextTreeNode(tn,TVF_VISIBLE,0,~0);
407 idx--;
410 return(tn);
413 /************************************************************************
414 ************************ TV_TREENODETOINDEX() *************************
415 *************************************************************************
416 * Given a ptr to a TreeNode, determine its 0-based index in the listview,
417 * returning ~0 if the node isn't displayed in the list.
419 *************************************************************************/
421 ULONG TV_TreeNodeToIndex(TVData *tv,TNPTR in)
423 TNPTR tn;
424 ULONG idx;
426 idx = 0;
427 tn = FirstChildIn(RootList(tv));
429 while(tn && (tn != in))
431 idx++;
432 tn = TV_GetNextTreeNode(tn,TVF_VISIBLE,0,~0);
435 return(tn ? idx : ~0);
438 /************************************************************************
439 ************************ TV_GETNEXTTREENODE() *************************
440 *************************************************************************
441 * Return the next node after the given one, descending into child nodes
442 * where available, and ascending back to parent nodes when the children
443 * run out. If TVF_VISIBLE is set in flags, descends only into child nodes
444 * when the parent node is expanded. If TVF_SELECTED is set in flags,
445 * repeats until a selected treenode is found. Stops if the depth of the
446 * search becomes less than mindepth, does not descend into child nodes
447 * when the depth would become greater than maxdepth. Returns a ptr to the
448 * next treenode, or NULL if at end.
450 *************************************************************************/
452 TNPTR TV_GetNextTreeNode(TNPTR tn,ULONG flags,ULONG mindepth,ULONG maxdepth)
454 TNPTR pn;
455 BOOL hidden;
456 BOOL selected;
458 hidden = (flags & TVF_VISIBLE) ? FALSE : TRUE;
459 selected = (flags & TVF_SELECTED) ? TRUE : FALSE;
463 if (HasChildren(tn) && (hidden || IsExpanded(tn))
464 && (TV_TreeNodeDepth(tn) < maxdepth))
466 /* descend into child nodes of current node */
467 tn = FirstChildOf(tn);
469 else
471 pn = ParentOf(tn);
473 /* get next node at current level */
474 tn = NextSiblingOf(tn);
476 /* end of nodes at current level? then get next of parent, if any */
477 while(!tn && pn)
479 if ((tn = NextSiblingOf(pn)))
481 pn = tn->tn_Parent;
483 /* don't rise above mindepth */
484 if (TV_TreeNodeDepth(tn) < mindepth)
485 { tn = pn = NULL; }
487 else
488 if((pn = ParentOf(pn))
489 && ParentOf(pn)==NULL)
490 break;
494 } while(tn && selected && !IsSelected(tn));
496 return(tn);
499 /************************************************************************
500 ************************ TV_GETPREVTREENODE() *************************
501 *************************************************************************
502 * Return the previous node after the given one, descending into child
503 * nodes where available, and ascending back to parent nodes when the
504 * children run out. If flags bit TVF_VISIBLE is set, descends only into
505 * child nodes when the parent node is expanded. If flags bit TVF_SELECTED
506 * is set, repeats until a selected treenode is found. Stops if the depth
507 * of the search becomes less than mindepthdoes not descend into child nodes
508 * when the depth would become greater than maxdepth. Returns a ptr to the
509 * suitable previous treenode, or NULL if none found.
511 *************************************************************************/
513 TNPTR TV_GetPrevTreeNode(TNPTR tn,ULONG flags,ULONG mindepth,ULONG maxdepth)
515 TNPTR tn2;
516 BOOL hidden;
517 BOOL selected;
519 hidden = (flags & TVF_VISIBLE) ? FALSE : TRUE;
520 selected = (flags & TVF_SELECTED) ? TRUE : FALSE;
521 tn2 = NULL;
525 /* get prev node at current level */
527 if ((tn2 = PrevSiblingOf(tn)))
529 tn = tn2;
532 * We got a prev node, see if it's got children and
533 * descend to the lowest (allowed) level of them if so.
536 while(tn && HasChildren(tn) && (hidden || IsExpanded(tn))
537 && (TV_TreeNodeDepth(tn) < maxdepth))
539 tn = LastChildOf(tn);
542 else
544 /* no prev at this level: ascend to parent */
545 if (TV_TreeNodeDepth(tn) > mindepth)
547 tn = ParentOf(tn);
548 /* disallow ascent to root node */
549 if (!ParentOf(tn))
550 tn = NULL;
552 else
553 tn = NULL;
556 } while(tn && selected && !IsSelected(tn));
558 return(tn);
561 /************************************************************************
562 ************************** TV_FINDTREENODE() **************************
563 *************************************************************************
564 * Find the treenode by entry, descending into all child nodes of the
565 * supplied list. Returns NULL if the entry isn't found. Matching is
566 * done by value, not content, ie. entries are matched for as pointers
567 * for equality.
569 *************************************************************************/
571 TNPTR TV_FindTreeNode(LISTPTR list,APTR entry)
573 TNPTR tn;
575 tn = FirstChildIn(list);
577 while(tn && (tn->tn_Entry != entry))
578 tn = TV_GetNextTreeNode(tn,TVF_ALL,0,~0);
580 return(tn);
583 /************************************************************************
584 ************************** TV_ISDISPLAYED() ***************************
585 *************************************************************************
586 * Returns TRUE if the given treenode is displayed, ie. all it's parents
587 * are expanded. FALSE otherwise.
589 *************************************************************************/
591 BOOL TV_IsDisplayed(TNPTR tn)
593 BOOL disp;
595 disp = TRUE;
597 while(disp && (tn = ParentOf(tn)))
598 disp = IsExpanded(tn) ? TRUE : FALSE;
600 return(disp);
603 /************************************************************************
604 *********************** TV_LASTDISPLAYEDCHILD() ***********************
605 *************************************************************************
606 * Given a parent TreeNode, find the last TreeNode among its children
607 * (and it's children's children, etc), which is displayed in the
608 * listview. Returns the parent if no children are present/displayed.
610 *************************************************************************/
612 TNPTR TV_LastDisplayedChild(TNPTR pn)
614 TNPTR tn,tn2;
615 ULONG depth;
617 if ((tn = FirstChildOf(pn)) && IsExpanded(pn))
619 depth = TV_TreeNodeDepth(tn);
621 while((tn2 = TV_GetNextTreeNode(tn,TVF_VISIBLE,depth,~0)))
622 tn = tn2;
624 else
625 tn = pn;
627 return(tn);
630 /************************************************************************
631 *************************** TV_SORTEDPREV() ***************************
632 *************************************************************************
633 * Returns the TreeNode in the supplied list that should be prior to
634 * the given treenode, when sorted alphabetically, or NULL if the TreeNode
635 * should go at the head of the list. Assumes the existing nodes are
636 * already in sort order. Uses the compare hook in the TreeView instance
637 * data to perform comparisons.
639 *************************************************************************/
641 TNPTR TV_SortedPrev(TVData *tv,LISTPTR list,TNPTR in)
643 struct tvCompare tvc;
644 TNPTR tn,pn;
646 tn = FirstChildIn(list);
647 pn = NULL;
648 tvc.tvc_EntryB = in->tn_Entry;
650 while(tn)
652 tvc.tvc_EntryA = tn->tn_Entry;
654 if (((LONG) CallHookPkt(tv->tv_CompareHook,tv->tv_TreeView,&tvc)) < 0)
656 pn = tn;
657 tn = NextSiblingOf(tn);
659 else
660 tn = NULL;
663 while(tn && (Stricmp(tn->tn_Entry,in->tn_Entry) < 0))
665 pn = tn;
666 tn = NextSiblingOf(tn);
669 return(pn);
672 /************************************************************************
673 ************************* TV_MATCHNEXTENTRY() *************************
674 *************************************************************************
675 * Find the next entry in the treeview, after the supplied entry,
676 * matching a given specification. Supply a tvAnchor cleared with zeros
677 * when calling this function for the first time. Then repeatedly call
678 * this function with that anchor to get all matching entries. When there
679 * are no more matches, this function returns NULL.
681 * The match specifications are:
683 * APTR refentry;
685 * This is a reference entry to start matching from. It is either a ptr
686 * to the parent entry, or a sibling entry, of the entries to consider for
687 * matching. It could also be one of these special values: TV_ROOT, to
688 * represent the root of the tree (a dummy entry); TV_SELECTED, for the
689 * (first) currently selected entry. If TVF_INTERNAL is set in flags,
690 * then refentry must be a ptr to a TreeNode, rather than the entry in
691 * a TreeNode.
693 * If the reference entry is TV_SELECTED, but no entry is currently
694 * selected, NULL is returned.
696 * ULONG which;
698 * This is a code that indicates the relationship between the entries to
699 * be considered for matching and the reference entry. It can take these
700 * values:
702 * TVW_ENTRY specified entry only
703 * TVW_PARENT parent of entry
704 * TVW_CHILD_FIRST first child of entry
705 * TVW_CHILD_LAST last child of entry
706 * TVW_CHILD_ALL all children of entry
707 * TVW_CHILD_TREE all children, recursively
708 * TVW_SIBLING_FIRST first sibling of entry
709 * TVW_SIBLING_LAST last sibling of entry
710 * TVW_SIBLING_NEXT next sibling of entry
711 * TVW_SIBLING_PREV prev. sibling of entry
712 * TVW_SIBLING_ALL entry and all siblings
713 * TVW_SIBLING_TREE entry, siblings and all children recursively
714 * TVW_TREE_FIRST first in tree, entry ignored
715 * TVW_TREE_LAST last in tree, entry ignored
716 * TVW_TREE_NEXT next in tree from entry
717 * TVW_TREE_PREV prev. in tree from entry
718 * TVW_TREE_PAGE_UP page up in tree from entry
719 * TVW_TREE_PAGE_DOWN page down in tree from entry
721 * If the relation entry is TV_ROOT, only the TVW_CHILD_??? codes, and
722 * TVW_TREE_FIRST/LAST are permitted. To have all entries in the treeview
723 * considered, pass TV_ROOT as the reference entry and TVW_CHILD_TREE
724 * as the code.
726 * ULONG flags;
728 * These flag bits are considered:
730 * TVF_SELECTED consider only selected entries
731 * TVF_VISIBLE consider only visible entries
732 * TVF_INTERNAL the reference entry is a TreeNode ptr, rather
733 * than a ptr to one of the user's entries.
735 * If TVF_SELECTED is used, then the first time this function is called
736 * the TNF_SELECTED bit of the tn_Flags member of all the TreeNodes in
737 * the treeview are updated, by interrogating the embedded listview.
739 * The TVF_VISIBLE flag is most useful when used with TVW_TREE_NEXT
740 * and TVW_TREE_PREV, to iterate through the treeview entries that are
741 * actually displayed in the gadget.
743 * STUB! TV_MatchNextEntry doesn't do tree page up or down yet.
745 *************************************************************************/
747 TNPTR TV_MatchNextEntry(TVData *tv,APTR refentry,ULONG which,ULONG flags,
748 struct tvAnchor *tva)
750 ULONG maxdepth = 0,mindepth = 0;
751 BOOL checkmatch,more,next;
754 * If this is the first call to this function, we have some initial
755 * setup work to do.
758 if (!tva->tva_Ref)
761 * If the TVF_SELECTED flag has been used, update the TNF_SELECTED
762 * flag of all TreeNodes by interrogating the listview.
765 if (flags & TVF_SELECTED)
766 TV_UpdateSelected(tv);
769 * Setup the anchor struct
772 tva->tva_Last = NULL;
773 tva->tva_Category = which & TVWC_MASK;
774 tva->tva_Style = which & TVWS_MASK;
775 tva->tva_Flags = flags;
776 tva->tva_Visible = (flags & TVF_VISIBLE) ? TRUE : FALSE;
777 tva->tva_Selected = (flags & TVF_SELECTED) ? TRUE : FALSE;
778 tva->tva_Multiple = FALSE;
780 if ((tva->tva_Style == TVWS_ALL) || (tva->tva_Style == TVWS_TREE))
781 tva->tva_Multiple = TRUE;
783 if (tva->tva_Category == TVWC_TREE)
785 switch(tva->tva_Style)
788 * TVW_TREE_FIRST and TVW_TREE_LAST are converted here
789 * into other categories/styles, with the supplied entry
790 * ignored.
793 case TVWS_FIRST:
794 refentry = &tv->tv_RootNode;
795 tva->tva_Category = TVWC_CHILD;
796 tva->tva_Flags |= TVF_INTERNAL;
797 break;
799 case TVWS_LAST:
800 refentry = LastChildOf(&tv->tv_RootNode);
801 if (tva->tva_Visible)
802 refentry = TV_LastDisplayedChild((TNPTR) refentry);
803 else
805 while(HasChildren(refentry))
806 refentry = LastChildOf(refentry);
808 tva->tva_Category = TVWC_ENTRY;
809 tva->tva_Flags |= TVF_INTERNAL;
810 break;
812 default:
813 break;
815 } /* endswitch style */
817 } /* endif TVWC_TREE */
820 * Determine what kind of reference entry has been given and obtain
821 * a ptr to its TreeNode, if necessary.
824 if (refentry == TV_ROOT)
827 * Reference is the dummy root node, only TVWS_CHILD_? permitted
830 if (tva->tva_Category == TVWC_CHILD)
831 tva->tva_Ref = &tv->tv_RootNode;
833 else if (refentry == TV_SELECTED)
834 /* reference is the first selected entry */
835 tva->tva_Ref = (TNPTR) DoMethod(tv->tv_Listview,LVM_FIRSTENTRY,NULL,LVGEF_SELECTED);
836 else if (tva->tva_Flags & TVF_INTERNAL)
837 /* internal reference, already a TreeNode ptr */
838 tva->tva_Ref = refentry;
839 else
840 /* a user's entry: find its TreeNode */
841 tva->tva_Ref = TV_FindTreeNode(RootList(tv),refentry);
843 if (tva->tva_Ref)
845 tva->tva_RefDepth = TV_TreeNodeDepth(tva->tva_Ref);
846 checkmatch = TRUE;
847 more = TRUE;
848 next = TRUE;
849 mindepth = 0;
850 maxdepth = ~0;
852 switch(tva->tva_Category)
854 case TVWC_ENTRY:
855 tva->tva_Last = tva->tva_Ref;
856 more = FALSE;
857 break;
859 case TVWC_PARENT:
860 tva->tva_Last = ParentOf(tva->tva_Ref);
861 more = FALSE;
862 break;
864 case TVWC_CHILD:
865 if (HasChildren(tva->tva_Ref))
867 switch(tva->tva_Style)
869 case TVWS_FIRST: /* first child of entry */
870 case TVWS_ALL: /* all children of entry */
871 tva->tva_Last = FirstChildOf(tva->tva_Ref);
872 mindepth = maxdepth = tva->tva_RefDepth + 1;
873 break;
875 case TVWS_LAST: /* last child of entry */
876 tva->tva_Last = LastChildOf(tva->tva_Ref);
877 next = FALSE;
878 mindepth = maxdepth = tva->tva_RefDepth + 1;
879 break;
881 case TVWS_TREE: /* all children, recursively */
882 tva->tva_Last = FirstChildOf(tva->tva_Ref);
883 mindepth = tva->tva_RefDepth + 1;
884 break;
886 default:
887 break;
889 } /* endswitch tva_Style */
891 } /* endif tva_Ref has children */
893 break; /* endcase TVWC_CHILD */
895 case TVWC_SIB:
896 mindepth = maxdepth = tva->tva_RefDepth;
898 switch(tva->tva_Style)
900 case TVWS_FIRST: /* first sibling of entry */
901 case TVWS_ALL: /* entry and all siblings */
902 tva->tva_Last = FirstSiblingOf(tva->tva_Ref);
903 break;
905 case TVWS_LAST: /* last sibling of entry */
906 tva->tva_Last = LastSiblingOf(tva->tva_Ref);
907 next = FALSE;
908 break;
910 case TVWS_NEXT: /* next sibling of entry */
911 checkmatch = FALSE;
912 tva->tva_Last = TV_GetNextTreeNode(tva->tva_Ref,
913 tva->tva_Flags,mindepth,maxdepth);
914 break;
916 case TVWS_PREV: /* prev. sibling of entry */
917 checkmatch = FALSE;
918 tva->tva_Last = TV_GetPrevTreeNode(tva->tva_Ref,
919 tva->tva_Flags,mindepth,maxdepth);
920 break;
922 case TVWS_TREE: /* entry, siblings and all children recursively */
923 tva->tva_Last = FirstSiblingOf(tva->tva_Ref);
924 maxdepth = ~0;
925 break;
927 default:
928 break;
931 break; /* endcase TVWC_SIB */
933 case TVWC_TREE:
934 checkmatch = FALSE;
936 switch(tva->tva_Style)
938 /*case TVWS_FIRST:*//* first in tree, entry ignored */
939 /*case TVWS_LAST:*/ /* first in tree, entry ignored */
940 /* these were converted to other forms, above */
942 case TVWS_NEXT: /* next in tree from entry */
943 tva->tva_Last = TV_GetNextTreeNode(tva->tva_Ref,tva->tva_Flags,0,~0);
944 break;
946 case TVWS_PREV: /* prev. in tree from entry */
947 tva->tva_Last = TV_GetPrevTreeNode(tva->tva_Ref,tva->tva_Flags,0,~0);
948 break;
950 case TVWS_PGUP: /* page up in tree from entry */
951 /* stub! */
952 break;
954 case TVWS_PGDN: /* page down in tree from entry */
955 /* stub! */
956 break;
958 default:
959 break;
961 } /* endswitch tva_Style */
963 break; /* endcase TVWC_TREE */
965 default:
966 break;
968 } /* endswitch tva_Category */
970 if (tva->tva_Last && checkmatch)
972 if ((tva->tva_Visible && !TV_IsDisplayed(tva->tva_Last)) ||
973 (tva->tva_Selected && !IsSelected(tva->tva_Last)))
975 if (more)
977 if (next)
978 tva->tva_Last = TV_GetNextTreeNode(tva->tva_Last,
979 tva->tva_Flags,mindepth,maxdepth);
980 else
981 tva->tva_Last = TV_GetPrevTreeNode(tva->tva_Last,
982 tva->tva_Flags,mindepth,maxdepth);
984 else
985 tva->tva_Last = NULL;
989 } /* endif tva_Ref */
991 } /* endif first time */
992 else
995 * If this is not the first call, check that the code
996 * specifies multiple entries and that there was a
997 * previous match if so. Simply return NULL if not.
1000 if (tva->tva_Multiple && tva->tva_Last)
1002 switch(tva->tva_Category | tva->tva_Style)
1004 case TVW_CHILD_ALL: /* all children */
1005 mindepth = maxdepth = tva->tva_RefDepth + 1;
1006 break;
1009 case TVW_SIBLING_ALL: /* all siblings */
1010 mindepth = maxdepth = tva->tva_RefDepth;
1011 break;
1013 case TVW_CHILD_TREE: /* all children, recursively */
1014 mindepth = tva->tva_RefDepth + 1;
1015 maxdepth = ~0;
1016 break;
1018 case TVW_SIBLING_TREE: /* siblings and all children recursively */
1019 mindepth = tva->tva_RefDepth;
1020 maxdepth = ~0;
1021 break;
1023 default:
1024 tva->tva_Last = NULL;
1025 break;
1027 } /* endswitch category|style */
1029 if (tva->tva_Last)
1030 tva->tva_Last = TV_GetNextTreeNode(tva->tva_Last,
1031 tva->tva_Flags,mindepth,maxdepth);
1033 } /* endif multiple and tva_Last */
1034 else
1035 tva->tva_Last = NULL;
1037 } /* endelse tva_Ref */
1039 return(tva->tva_Last);
1042 /************************************************************************
1043 ************************* TV_UPDATESELECTED() *************************
1044 *************************************************************************
1045 * Update the setting of the TNF_SELECTED flag in all the treeview's
1046 * TreeNodes by interrogating the listview. Returns the number of
1047 * selected entries.
1049 *************************************************************************/
1051 ULONG TV_UpdateSelected(TVData *tv)
1053 TNPTR tn;
1054 ULONG count;
1057 * First reset the selected bit of all treenodes.
1060 tn = FirstChildIn(RootList(tv));
1062 while(tn)
1064 tn->tn_Flags &= ~TNF_SELECTED;
1065 tn = TV_GetNextTreeNode(tn,TVF_ALL,0,~0);
1069 * Now step through every selected entry in the listview,
1070 * setting the selected bit.
1073 tn = (TNPTR) DoMethod(tv->tv_Listview,LVM_FIRSTENTRY,NULL,LVGEF_SELECTED);
1074 count = 0;
1076 while(tn)
1078 tn->tn_Flags |= TNF_SELECTED;
1079 count++;
1080 tn = (TNPTR) DoMethod(tv->tv_Listview,LVM_NEXTENTRY,tn,LVGEF_SELECTED);
1083 return(count);
1086 /************************************************************************
1087 ************************ TV_DEBUGDUMPMETHOD() *************************
1088 ************************************************************************/
1090 typedef struct {
1091 ULONG ID;
1092 STRPTR Name;
1093 } Pair;
1095 void TV_DebugDumpMethod(Msg msg)
1097 #ifdef DUMPMETHOD
1099 Pair *pair;
1100 STRPTR method,category,style,entry,relation;
1101 ULONG methodid,ginfo,whichid,relationid,entryid,flags;
1103 static Pair Methods[] = {
1104 TVM_INSERT, "TVM_INSERT", TVM_REMOVE, "TVM_REMOVE",
1105 TVM_REPLACE, "TVM_REPLACE", TVM_MOVE, "TVM_MOVE",
1106 TVM_GETENTRY, "TVM_GETENTRY", TVM_SELECT, "TVM_SELECT",
1107 TVM_VISIBLE, "TVM_VISIBLE", TVM_EXPAND, "TVM_EXPAND",
1108 TVM_CLEAR, "TVM_CLEAR", TVM_LOCK, "TVM_LOCK",
1109 TVM_UNLOCK, "TVM_UNLOCK", TVM_SORT, "TVM_SORT",
1110 TVM_REDRAW, "TVM_REDRAW", TVM_REFRESH, "TVM_REFRESH",
1111 TVM_REBUILD, "TVM_REBUILD", 0, NULL
1114 static Pair Categories[] = {
1115 TVWC_ENTRY, "TVW_ENTRY", TVWC_PARENT, "TVW_PARENT",
1116 TVWC_CHILD, "TVW_CHILD", TVWC_SIB, "TVW_SIB",
1117 TVWC_TREE, "TVW_TREE", 0, NULL
1120 static Pair Styles[] = {
1121 TVWS_FIRST, "_FIRST", TVWS_LAST, "_LAST", TVWS_NEXT, "_NEXT",
1122 TVWS_PREV, "_PREV", TVWS_PGUP, "_PGUP", TVWS_PGDN, "_PGDN",
1123 TVWS_SORT, "_SORT", TVWS_ALL, "_ALL", TVWS_TREE, "_TREE",
1124 0, NULL
1127 methodid = ((struct tvEntry *) msg)->tve_MethodID;
1128 ginfo = (ULONG) ((struct tvEntry *) msg)->tve_GInfo;
1130 switch(methodid)
1132 case TVM_INSERT:
1133 case TVM_MOVE:
1134 entryid = (ULONG) ((struct tvInsert *) msg)->tvi_Entry;
1135 relationid = (ULONG) ((struct tvInsert *) msg)->tvi_Relation;
1136 whichid = ((struct tvInsert *) msg)->tvi_Where;
1137 flags = ((struct tvInsert *) msg)->tvi_Flags;
1138 break;
1140 case TVM_REPLACE:
1141 relationid = (ULONG) ((struct tvReplace *) msg)->tvr_OldEntry;
1142 entryid = (ULONG) ((struct tvReplace *) msg)->tvr_NewEntry;
1143 whichid = ((struct tvReplace *) msg)->tvr_Where;
1144 flags = ((struct tvReplace *) msg)->tvr_Flags;
1145 break;
1147 case TVM_GETENTRY:
1148 relationid = ~0;
1149 entryid = (ULONG) ((struct tvGet *) msg)->tvg_Entry;
1150 whichid = ((struct tvGet *) msg)->tvg_Which;
1151 flags = ((struct tvGet *) msg)->tvg_Flags;
1152 break;
1154 case TVM_REMOVE:
1155 case TVM_SELECT:
1156 case TVM_VISIBLE:
1157 case TVM_EXPAND:
1158 relationid = ~0;
1159 entryid = (ULONG) ((struct tvEntry *) msg)->tve_Entry;
1160 whichid = ((struct tvEntry *) msg)->tve_Which;
1161 flags = ((struct tvEntry *) msg)->tve_Flags;
1162 break;
1164 default:
1165 entryid = relationid = whichid = ~0;
1166 flags = 0;
1167 break;
1170 pair = Methods;
1171 while(pair->Name && (pair->ID != methodid))
1172 pair++;
1174 method = pair->Name ? pair->Name : "Unknown!";
1176 pair = Categories;
1177 while(pair->Name && (pair->ID != (whichid & TVWC_MASK)))
1178 pair++;
1179 category = pair->Name ? pair->Name : "N/A!";
1181 pair = Styles;
1182 while(pair->Name && (pair->ID != (whichid & TVWS_MASK)))
1183 pair++;
1184 style = pair->Name ? pair->Name : "\0";
1186 if (entryid != ~0)
1188 if (entryid)
1190 if (entryid == (ULONG) TV_SELECTED)
1191 entry = "TV_SELECTED";
1192 else
1193 entry = flags & TVF_INTERNAL ?
1194 (STRPTR) ((TNPTR) entryid)->tn_Node.ln_Name :
1195 (STRPTR) entryid;
1197 else
1198 entry = "TV_ROOT";
1200 else
1201 entry = "N/A";
1203 if (relationid != ~0)
1205 if (relationid)
1207 if (relationid == (ULONG) TV_SELECTED)
1208 relation = "TV_SELECTED";
1209 else
1210 relation = flags & TVF_INTERNAL ?
1211 (STRPTR) ((TNPTR) relationid)->tn_Node.ln_Name :
1212 (STRPTR) relationid;
1214 else
1215 relation = "TV_ROOT";
1217 else
1218 relation = "N/A";
1220 KPrintF("%s: GI:%08lx Rel:%s Entry:%s %s%s ",
1221 method,ginfo,relation,entry,category,style);
1223 if (flags & TVF_SELECTED)
1224 KPrintF("TVF_SELECTED ");
1225 if (flags & TVF_SELECT)
1226 KPrintF("TVF_SELECT ");
1227 if (flags & TVF_DESELECT)
1228 KPrintF("TVF_DESELECT ");
1229 if (flags & TVF_MULTISELECT)
1230 KPrintF("TVF_MULTISELECT ");
1231 if (flags & TVF_MAKEVISIBLE)
1232 KPrintF("TVF_MAKEVISIBLE ");
1233 if (flags & TVF_EXPAND)
1234 KPrintF("TVF_EXPAND ");
1235 if (flags & TVF_CONTRACT)
1236 KPrintF("TVF_CONTRACT ");
1237 if (flags & TVF_TOGGLE)
1238 KPrintF("TVF_TOGGLE ");
1240 KPrintF("\n");
1242 #endif