4 * BGUI Tree List View class
6 * (C) Copyright 1999 Manuel Lemos.
7 * (C) Copyright 1996-1999 Nick Christie.
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
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"
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
);
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
143 *************************************************************************/
145 void *TV_AllocVec(TVData
*tv
,ULONG size
)
151 static ULONG Cookie
[] = { 0xdeadbeef, 0xabadcafe };
154 mem
= AllocPooled(tv
->tv_MemPool
,size
+ 4 + 2 * 8);
156 mem
= AllocMem(size
+ 4 + 2 * 8,MEMF_STD
);
161 memcpy(&mem
[1],Cookie
,8);
163 memcpy(((UBYTE
*)mem
) + size
,Cookie
,8);
170 if ((mem
= AllocPooled(tv
->tv_MemPool
,size
+ 4)))
174 mem
= AllocVec(size
,MEMF_STD
);
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
)
196 static ULONG Cookie
[2] = { 0xdeadbeef, 0xabadcafe };
201 p
= (ULONG
*) (((UBYTE
*) mem
) - 12);
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]))
210 FreePooled(tv
->tv_MemPool
,p
,size
+ 4 + 2 * 8);
212 FreeMem(p
,size
+ 4 + 2 * 8);
215 KPrintF("Treeview: Memory (size %lu) munged at 0x%08lx!\n",size
,p
);
226 FreePooled(tv
->tv_MemPool
,p
,size
+ 4);
235 /************************************************************************
236 *************************** TV_ALLOCHOOK() ****************************
237 ************************************************************************/
239 HOOKPTR
TV_AllocHook(HOOKFUNC handler
,APTR data
)
243 if ((hook
= AllocMem(sizeof(struct Hook
),MEMF_STD
)))
245 hook
->h_Entry
= handler
;
252 /************************************************************************
253 **************************** TV_FREEHOOK() ****************************
254 ************************************************************************/
256 void TV_FreeHook(HOOKPTR 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
)
279 if ((t
= TV_AllocVec(tv
,strlen(s
) + extra
+ 1)))
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
;
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
));
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
;
340 tvr
.tvr_Command
= TVRC_KILL
;
341 tvr
.tvr_Entry
= (APTR
) tn
->tn_Entry
;
342 CallHookPkt(tv
->tv_ResourceHook
,tv
->tv_TreeView
,&tvr
);
347 /************************************************************************
348 ************************ TV_FREETREENODELIST() ************************
349 *************************************************************************
350 * Free a list of TreeNodes, and all children. Does not re-initialise
353 *************************************************************************/
355 void TV_FreeTreeNodeList(TVData
*tv
,LISTPTR list
)
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
)
383 while((tn
= ParentOf(tn
)))
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
)
402 tn
= FirstChildIn(RootList(tv
));
406 tn
= TV_GetNextTreeNode(tn
,TVF_VISIBLE
,0,~0);
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
)
427 tn
= FirstChildIn(RootList(tv
));
429 while(tn
&& (tn
!= in
))
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
)
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
);
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 */
479 if ((tn
= NextSiblingOf(pn
)))
483 /* don't rise above mindepth */
484 if (TV_TreeNodeDepth(tn
) < mindepth
)
488 if((pn
= ParentOf(pn
))
489 && ParentOf(pn
)==NULL
)
494 } while(tn
&& selected
&& !IsSelected(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
)
519 hidden
= (flags
& TVF_VISIBLE
) ? FALSE
: TRUE
;
520 selected
= (flags
& TVF_SELECTED
) ? TRUE
: FALSE
;
525 /* get prev node at current level */
527 if ((tn2
= PrevSiblingOf(tn
)))
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
);
544 /* no prev at this level: ascend to parent */
545 if (TV_TreeNodeDepth(tn
) > mindepth
)
548 /* disallow ascent to root node */
556 } while(tn
&& selected
&& !IsSelected(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
569 *************************************************************************/
571 TNPTR
TV_FindTreeNode(LISTPTR list
,APTR entry
)
575 tn
= FirstChildIn(list
);
577 while(tn
&& (tn
->tn_Entry
!= entry
))
578 tn
= TV_GetNextTreeNode(tn
,TVF_ALL
,0,~0);
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
)
597 while(disp
&& (tn
= ParentOf(tn
)))
598 disp
= IsExpanded(tn
) ? TRUE
: FALSE
;
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
)
617 if ((tn
= FirstChildOf(pn
)) && IsExpanded(pn
))
619 depth
= TV_TreeNodeDepth(tn
);
621 while((tn2
= TV_GetNextTreeNode(tn
,TVF_VISIBLE
,depth
,~0)))
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
;
646 tn
= FirstChildIn(list
);
648 tvc
.tvc_EntryB
= in
->tn_Entry
;
652 tvc
.tvc_EntryA
= tn
->tn_Entry
;
654 if (((LONG
) CallHookPkt(tv
->tv_CompareHook
,tv
->tv_TreeView
,&tvc
)) < 0)
657 tn
= NextSiblingOf(tn
);
663 while(tn
&& (Stricmp(tn
->tn_Entry
,in
->tn_Entry
) < 0))
666 tn
= NextSiblingOf(tn
);
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:
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
693 * If the reference entry is TV_SELECTED, but no entry is currently
694 * selected, NULL is returned.
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
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
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
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
794 refentry
= &tv
->tv_RootNode
;
795 tva
->tva_Category
= TVWC_CHILD
;
796 tva
->tva_Flags
|= TVF_INTERNAL
;
800 refentry
= LastChildOf(&tv
->tv_RootNode
);
801 if (tva
->tva_Visible
)
802 refentry
= TV_LastDisplayedChild((TNPTR
) refentry
);
805 while(HasChildren(refentry
))
806 refentry
= LastChildOf(refentry
);
808 tva
->tva_Category
= TVWC_ENTRY
;
809 tva
->tva_Flags
|= TVF_INTERNAL
;
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
;
840 /* a user's entry: find its TreeNode */
841 tva
->tva_Ref
= TV_FindTreeNode(RootList(tv
),refentry
);
845 tva
->tva_RefDepth
= TV_TreeNodeDepth(tva
->tva_Ref
);
852 switch(tva
->tva_Category
)
855 tva
->tva_Last
= tva
->tva_Ref
;
860 tva
->tva_Last
= ParentOf(tva
->tva_Ref
);
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;
875 case TVWS_LAST
: /* last child of entry */
876 tva
->tva_Last
= LastChildOf(tva
->tva_Ref
);
878 mindepth
= maxdepth
= tva
->tva_RefDepth
+ 1;
881 case TVWS_TREE
: /* all children, recursively */
882 tva
->tva_Last
= FirstChildOf(tva
->tva_Ref
);
883 mindepth
= tva
->tva_RefDepth
+ 1;
889 } /* endswitch tva_Style */
891 } /* endif tva_Ref has children */
893 break; /* endcase TVWC_CHILD */
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
);
905 case TVWS_LAST
: /* last sibling of entry */
906 tva
->tva_Last
= LastSiblingOf(tva
->tva_Ref
);
910 case TVWS_NEXT
: /* next sibling of entry */
912 tva
->tva_Last
= TV_GetNextTreeNode(tva
->tva_Ref
,
913 tva
->tva_Flags
,mindepth
,maxdepth
);
916 case TVWS_PREV
: /* prev. sibling of entry */
918 tva
->tva_Last
= TV_GetPrevTreeNode(tva
->tva_Ref
,
919 tva
->tva_Flags
,mindepth
,maxdepth
);
922 case TVWS_TREE
: /* entry, siblings and all children recursively */
923 tva
->tva_Last
= FirstSiblingOf(tva
->tva_Ref
);
931 break; /* endcase TVWC_SIB */
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);
946 case TVWS_PREV
: /* prev. in tree from entry */
947 tva
->tva_Last
= TV_GetPrevTreeNode(tva
->tva_Ref
,tva
->tva_Flags
,0,~0);
950 case TVWS_PGUP
: /* page up in tree from entry */
954 case TVWS_PGDN
: /* page down in tree from entry */
961 } /* endswitch tva_Style */
963 break; /* endcase TVWC_TREE */
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
)))
978 tva
->tva_Last
= TV_GetNextTreeNode(tva
->tva_Last
,
979 tva
->tva_Flags
,mindepth
,maxdepth
);
981 tva
->tva_Last
= TV_GetPrevTreeNode(tva
->tva_Last
,
982 tva
->tva_Flags
,mindepth
,maxdepth
);
985 tva
->tva_Last
= NULL
;
989 } /* endif tva_Ref */
991 } /* endif first time */
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;
1009 case TVW_SIBLING_ALL
: /* all siblings */
1010 mindepth
= maxdepth
= tva
->tva_RefDepth
;
1013 case TVW_CHILD_TREE
: /* all children, recursively */
1014 mindepth
= tva
->tva_RefDepth
+ 1;
1018 case TVW_SIBLING_TREE
: /* siblings and all children recursively */
1019 mindepth
= tva
->tva_RefDepth
;
1024 tva
->tva_Last
= NULL
;
1027 } /* endswitch category|style */
1030 tva
->tva_Last
= TV_GetNextTreeNode(tva
->tva_Last
,
1031 tva
->tva_Flags
,mindepth
,maxdepth
);
1033 } /* endif multiple and tva_Last */
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
1049 *************************************************************************/
1051 ULONG
TV_UpdateSelected(TVData
*tv
)
1057 * First reset the selected bit of all treenodes.
1060 tn
= FirstChildIn(RootList(tv
));
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
);
1078 tn
->tn_Flags
|= TNF_SELECTED
;
1080 tn
= (TNPTR
) DoMethod(tv
->tv_Listview
,LVM_NEXTENTRY
,tn
,LVGEF_SELECTED
);
1086 /************************************************************************
1087 ************************ TV_DEBUGDUMPMETHOD() *************************
1088 ************************************************************************/
1095 void TV_DebugDumpMethod(Msg msg
)
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",
1127 methodid
= ((struct tvEntry
*) msg
)->tve_MethodID
;
1128 ginfo
= (ULONG
) ((struct tvEntry
*) msg
)->tve_GInfo
;
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
;
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
;
1149 entryid
= (ULONG
) ((struct tvGet
*) msg
)->tvg_Entry
;
1150 whichid
= ((struct tvGet
*) msg
)->tvg_Which
;
1151 flags
= ((struct tvGet
*) msg
)->tvg_Flags
;
1159 entryid
= (ULONG
) ((struct tvEntry
*) msg
)->tve_Entry
;
1160 whichid
= ((struct tvEntry
*) msg
)->tve_Which
;
1161 flags
= ((struct tvEntry
*) msg
)->tve_Flags
;
1165 entryid
= relationid
= whichid
= ~0;
1171 while(pair
->Name
&& (pair
->ID
!= methodid
))
1174 method
= pair
->Name
? pair
->Name
: "Unknown!";
1177 while(pair
->Name
&& (pair
->ID
!= (whichid
& TVWC_MASK
)))
1179 category
= pair
->Name
? pair
->Name
: "N/A!";
1182 while(pair
->Name
&& (pair
->ID
!= (whichid
& TVWS_MASK
)))
1184 style
= pair
->Name
? pair
->Name
: "\0";
1190 if (entryid
== (ULONG
) TV_SELECTED
)
1191 entry
= "TV_SELECTED";
1193 entry
= flags
& TVF_INTERNAL
?
1194 (STRPTR
) ((TNPTR
) entryid
)->tn_Node
.ln_Name
:
1203 if (relationid
!= ~0)
1207 if (relationid
== (ULONG
) TV_SELECTED
)
1208 relation
= "TV_SELECTED";
1210 relation
= flags
& TVF_INTERNAL
?
1211 (STRPTR
) ((TNPTR
) relationid
)->tn_Node
.ln_Name
:
1212 (STRPTR
) relationid
;
1215 relation
= "TV_ROOT";
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 ");