Index: doc/ttk_treeview.n ================================================================== --- doc/ttk_treeview.n +++ doc/ttk_treeview.n @@ -342,10 +342,15 @@ Modify or query the widget state; see \fIttk::widget(n)\fR. .TP \fIpathName \fBtag \fIargs...\fR .RS .TP +\fIpathName \fBtag add \fItag items\fR +Adds the specified \fItag\fR to each of the listed \fIitems\fR. +If \fItag\fR is already present for a particular item, +then the \fB\-tags\fR for that item are unchanged. +.TP \fIpathName \fBtag bind \fItagName \fR?\fIsequence\fR? ?\fIscript\fR? Add a Tk binding script for the event sequence \fIsequence\fR to the tag \fItagName\fR. When an X event is delivered to an item, binding scripts for each of the item's \fB\-tags\fR are evaluated in order as per \fIbindtags(n)\fR. @@ -370,24 +375,25 @@ (or the empty string if the option has not been specified for \fItagName\fR). With no additional arguments, returns a dictionary of the option settings for \fItagName\fR. See \fBTAG OPTIONS\fR for the list of available options. .TP +\fIpathName \fBtag delete \fItagName\fR +Deletes all tag information for the \fItagName\fR argument. The +command removes the tag from all items in the widget and also deletes any +other information associated with the tag, such as bindings and display +information. The command returns an empty string. +.TP \fIpathName \fBtag has \fItagName\fR ?\fIitem\fR? If \fIitem\fR is specified, returns 1 or 0 depending on whether the specified item has the named tag. Otherwise, returns a list of all items which have the specified tag. .TP \fIpathName \fBtag names\fR Returns a list of all tags used by the widget. .TP -\fIpathName \fBtag add \fItag items\fR -Adds the specified \fItag\fR to each of the listed \fIitems\fR. -If \fItag\fR is already present for a particular item, -then the \fB\-tags\fR for that item are unchanged. -.TP \fIpathName \fBtag remove \fItag\fR ?\fIitems\fR? Removes the specified \fItag\fR from each of the listed \fIitems\fR. If \fIitems\fR is omitted, removes \fItag\fR from each item in the tree. If \fItag\fR is not present for a particular item, then the \fB\-tags\fR for that item are unchanged. Index: generic/ttk/ttkTagSet.c ================================================================== --- generic/ttk/ttkTagSet.c +++ generic/ttk/ttkTagSet.c @@ -77,10 +77,21 @@ } Tcl_DeleteHashTable(&tagTable->tags); ckfree(tagTable); } + +void Ttk_DeleteTagFromTable(Ttk_TagTable tagTable, Ttk_Tag tag) +{ + Tcl_HashEntry *entryPtr; + + entryPtr = Tcl_FindHashEntry(&tagTable->tags, tag->tagName); + if (entryPtr != NULL) { + DeleteTag(tagTable, tag); + Tcl_DeleteHashEntry(entryPtr); + } +} Ttk_Tag Ttk_GetTag(Ttk_TagTable tagTable, const char *tagName) { int isNew = 0; Tcl_HashEntry *entryPtr = Tcl_CreateHashEntry( Index: generic/ttk/ttkTreeview.c ================================================================== --- generic/ttk/ttkTreeview.c +++ generic/ttk/ttkTreeview.c @@ -77,10 +77,13 @@ TK_OPTION_NULL_OK,0,ITEM_OPTION_TAGS_CHANGED }, {TK_OPTION_END, 0,0,0, NULL, TCL_AUTO_LENGTH,TCL_AUTO_LENGTH, 0,0,0} }; +/* Forward declaration */ +static void RemoveTag(TreeItem *, Ttk_Tag); + /* + NewItem -- * Allocate a new, uninitialized, unlinked item */ static TreeItem *NewItem(void) { @@ -2958,11 +2961,11 @@ int selop, i; TreeItem *item, **items; if (objc == 2) { Tcl_Obj *result = Tcl_NewListObj(0,0); - for (item = tv->tree.root->children; item; item=NextPreorder(item)) { + for (item = tv->tree.root->children; item; item = NextPreorder(item)) { if (item->state & TTK_STATE_SELECTED) Tcl_ListObjAppendElement(NULL, result, ItemID(tv, item)); } Tcl_SetObjResult(interp, result); return TCL_OK; @@ -2984,11 +2987,11 @@ } switch (selop) { case SELECTION_SET: - for (item=tv->tree.root; item; item=NextPreorder(item)) { + for (item=tv->tree.root; item; item = NextPreorder(item)) { item->state &= ~TTK_STATE_SELECTED; } /*FALLTHRU*/ case SELECTION_ADD: for (i=0; items[i]; ++i) { @@ -3099,10 +3102,38 @@ } /* else */ TtkRedisplayWidget(&tv->core); return Ttk_ConfigureTag(interp, tagTable, tag, objc - 4, objv + 4); } + +/* + $tv tag delete $tag + */ +static int TreeviewTagDeleteCommand( + void *recordPtr, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]) +{ + Treeview *tv = (Treeview *)recordPtr; + Ttk_TagTable tagTable = tv->tree.tagTable; + TreeItem *item = tv->tree.root; + Ttk_Tag tag; + + if (objc != 4) { + Tcl_WrongNumArgs(interp, 3, objv, "tagName"); + return TCL_ERROR; + } + + tag = Ttk_GetTagFromObj(tagTable, objv[3]); + /* remove the tag from all items */ + while (item) { + RemoveTag(item, tag); + item = NextPreorder(item); + } + /* then remove the tag from the tag table */ + Ttk_DeleteTagFromTable(tagTable, tag); + TtkRedisplayWidget(&tv->core); + + return TCL_OK; +} /* + $tv tag has $tag ?$item? */ static int TreeviewTagHasCommand( void *recordPtr, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]) @@ -3229,11 +3260,11 @@ } } else if (objc == 4) { TreeItem *item = tv->tree.root; while (item) { RemoveTag(item, tag); - item=NextPreorder(item); + item = NextPreorder(item); } } TtkRedisplayWidget(&tv->core); @@ -3242,10 +3273,11 @@ static const Ttk_Ensemble TreeviewTagCommands[] = { { "add", TreeviewTagAddCommand,0 }, { "bind", TreeviewTagBindCommand,0 }, { "configure", TreeviewTagConfigureCommand,0 }, + { "delete", TreeviewTagDeleteCommand,0 }, { "has", TreeviewTagHasCommand,0 }, { "names", TreeviewTagNamesCommand,0 }, { "remove", TreeviewTagRemoveCommand,0 }, { 0,0,0 } }; Index: generic/ttk/ttkWidget.h ================================================================== --- generic/ttk/ttkWidget.h +++ generic/ttk/ttkWidget.h @@ -223,10 +223,12 @@ MODULE_SCOPE int Ttk_EnumerateTagOptions( Tcl_Interp *, Ttk_TagTable, Ttk_Tag); MODULE_SCOPE int Ttk_EnumerateTags(Tcl_Interp *, Ttk_TagTable); + +MODULE_SCOPE void Ttk_DeleteTagFromTable(Ttk_TagTable, Ttk_Tag); MODULE_SCOPE int Ttk_ConfigureTag( Tcl_Interp *interp, Ttk_TagTable tagTable, Ttk_Tag tag, int objc, Tcl_Obj *const objv[]); Index: tests/ttk/treetags.test ================================================================== --- tests/ttk/treetags.test +++ tests/ttk/treetags.test @@ -9,16 +9,15 @@ proc assert {expr {message ""}} { if {![uplevel 1 [list expr $expr]]} { error "PANIC: $message ($expr failed)" } } -proc in {e l} { expr {[lsearch -exact $l $e] >= 0} } proc itemConstraints {tv item} { # $tag in [$tv item $item -tags] <==> [$tv tag has $tag $item] foreach tag [$tv item $item -tags] { - assert {[in $item [$tv tag has $tag]]} + assert {$item in [$tv tag has $tag]} } foreach child [$tv children $item] { itemConstraints $tv $child } } @@ -26,11 +25,11 @@ proc treeConstraints {tv} { # $item in [$tv tag has $tag] <==> [$tv tag has $tag $item] # foreach tag [$tv tag names] { foreach item [$tv tag has $tag] { - assert {[in $tag [$tv item $item -tags]]} + assert {$tag in [$tv item $item -tags]} } } itemConstraints $tv {} } @@ -111,10 +110,16 @@ test treetags-1.10 "tag names - tag configured" -body { $tv tag configure tag5 lsort [$tv tag names] } -result [list tag1 tag2 tag3 tag4 tag5] + +test treetags-1.11 "tag delete" -body { + $tv tag delete tag5 + $tv tag delete tag4 + lsort [$tv tag names] +} -result [list tag1 tag2 tag3] test treetags-1.end "cleanup" -body { $tv item item1 -tags tag1 $tv item item2 -tags tag2 list [$tv tag has tag1] [$tv tag has tag2] [$tv tag has tag3]