Index: generic/ttk/ttkTreeview.c ================================================================== --- generic/ttk/ttkTreeview.c +++ generic/ttk/ttkTreeview.c @@ -2677,11 +2677,11 @@ static int TreeviewDeleteCommand( void *recordPtr, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]) { Treeview *tv = recordPtr; TreeItem **items, *delq; - int i, selItemDeleted = 0; + int i, selChange = 0; if (objc != 3) { Tcl_WrongNumArgs(interp, 2, objv, "items"); return TCL_ERROR; } @@ -2705,11 +2705,11 @@ /* Remove items from hash table. */ delq = 0; for (i=0; items[i]; ++i) { if (items[i]->state & TTK_STATE_SELECTED) { - selItemDeleted = 1; + selChange = 1; } delq = DeleteItems(items[i], delq); } /* Free items: @@ -2723,11 +2723,11 @@ FreeItem(delq); delq = next; } ckfree(items); - if (selItemDeleted) { + if (selChange) { TtkSendVirtualEvent(tv->core.tkwin, "TreeviewSelect"); } TtkRedisplayWidget(&tv->core); return TCL_OK; } @@ -2952,11 +2952,11 @@ static const char *selopStrings[] = { "set", "add", "remove", "toggle", NULL }; Treeview *tv = recordPtr; - int selop, i; + int selop, i, selChange = 0; TreeItem *item, **items; if (objc == 2) { Tcl_Obj *result = Tcl_NewListObj(0,0); for (item = tv->tree.root->children; item; item=NextPreorder(item)) { @@ -2983,33 +2983,64 @@ } switch (selop) { case SELECTION_SET: + for (item=tv->tree.root; item; item=NextPreorder(item)) { + int inSetList = 0; + + for (i=0; items[i]; ++i) { + if (item == items[i]) { + inSetList = 1; + if (!(item->state & TTK_STATE_SELECTED)) { + /* Item newly selected */ + selChange = 1; + } + break; + } + } + if (!inSetList && (item->state & TTK_STATE_SELECTED)) { + /* Item newly deselected */ + selChange = 1; + } + if (selChange) break; + } for (item=tv->tree.root; item; item=NextPreorder(item)) { item->state &= ~TTK_STATE_SELECTED; } - /*FALLTHRU*/ - case SELECTION_ADD: for (i=0; items[i]; ++i) { items[i]->state |= TTK_STATE_SELECTED; + } + break; + case SELECTION_ADD: + for (i=0; items[i]; ++i) { + if (!(items[i]->state & TTK_STATE_SELECTED)) { + items[i]->state |= TTK_STATE_SELECTED; + selChange = 1; + } } break; case SELECTION_REMOVE: for (i=0; items[i]; ++i) { - items[i]->state &= ~TTK_STATE_SELECTED; + if (items[i]->state & TTK_STATE_SELECTED) { + items[i]->state &= ~TTK_STATE_SELECTED; + selChange = 1; + } } break; case SELECTION_TOGGLE: for (i=0; items[i]; ++i) { items[i]->state ^= TTK_STATE_SELECTED; + selChange = 1; } break; } ckfree(items); - TtkSendVirtualEvent(tv->core.tkwin, "TreeviewSelect"); + if (selChange) { + TtkSendVirtualEvent(tv->core.tkwin, "TreeviewSelect"); + } TtkRedisplayWidget(&tv->core); return TCL_OK; } Index: tests/ttk/treeview.test ================================================================== --- tests/ttk/treeview.test +++ tests/ttk/treeview.test @@ -458,34 +458,113 @@ test treeview-8.5 "Selection - bad operation" -body { .tv selection badop foo } -returnCodes error -match glob -result {bad selection operation "badop": must be *} -test treeview-8.6 "Selection - <> on selection add" -body { - .tv selection set {} - bind .tv <> {set res 1} - set res 0 - .tv selection add newnode.n1 - update - set res -} -result {1} - -test treeview-8.7 "<> on selected item deletion" -body { - .tv selection set {} - .tv insert "" end -id selectedDoomed -text DeadItem - .tv insert "" end -id doomed -text AlsoDead - .tv selection add selectedDoomed - update - bind .tv <> {lappend res 1} - set res 0 - .tv delete doomed - update - set res [expr {$res == 0}] - .tv delete selectedDoomed - update - set res -} -result {1 1} +test treeview-8.7 "<> when deleting items" -body { + .tv delete [.tv children {}] + .tv insert "" end -id myItem1 -text FirstItem + .tv insert "" end -id myItem2 -text SecondItem + .tv selection add myItem1 + update + bind .tv <> {lappend res $val} + set res {} + set val 1 + .tv delete myItem2 ; # no <> (selection unchanged) + update + set val 2 + .tv delete myItem1 ; # <> triggers + update + set res +} -result {2} + +test treeview-8.8 "<> when setting the selection" -body { + .tv delete [.tv children {}] + .tv insert "" end -id myItem1 -text FirstItem + .tv insert "" end -id myItem2 -text SecondItem + update + bind .tv <> {lappend res $val} + set res {} + set val 1 + .tv selection set "" ; # no <> (selection unchanged) + update + set val 2 + .tv selection set myItem1 ; # <> triggers + update + set val 3 + .tv selection set myItem1 ; # no <> (already selected) + update + set val 4 + .tv selection set {myItem1 myItem2} ; # <> triggers + update + set val 5 + .tv selection set {myItem2} ; # <> triggers + update + set res +} -result {2 4 5} + +test treeview-8.9 "<> when removing items from the selection" -body { + .tv delete [.tv children {}] + .tv insert "" end -id myItem1 -text FirstItem + .tv selection set myItem1 + update + bind .tv <> {lappend res $val} + set res {} + set val 1 + .tv selection remove "" ; # no <> (selection unchanged) + update + set val 2 + .tv selection remove myItem1 ; # <> triggers + update + set val 3 + .tv selection remove myItem1 ; # no <> (selection unchanged) + update + set res +} -result {2} + +test treeview-8.10 "<> when adding items in the selection" -body { + .tv delete [.tv children {}] + .tv insert "" end -id myItem1 -text FirstItem + .tv insert "" end -id myItem2 -text SecondItem + .tv insert "" end -id myItem3 -text ThirdItem + update + bind .tv <> {lappend res $val} + set res {} + set val 1 + .tv selection add myItem2 ; # <> triggers + update + set val 2 + .tv selection add myItem2 ; # no <> (selection unchanged) + update + set val 3 + .tv selection add myItem3 ; # <> triggers + update + set res +} -result {1 3} + +test treeview-8.11 "<> when toggling" -body { + .tv delete [.tv children {}] + .tv insert "" end -id myItem1 -text FirstItem + .tv insert "" end -id myItem2 -text SecondItem + .tv insert "" end -id myItem3 -text ThirdItem + update + bind .tv <> {lappend res $val} + set res {} + set val 1 + .tv selection toggle "" ; # no <> (selection unchanged) + update + set val 2 + .tv selection toggle {myItem1 myItem3} ; # <> triggers + update + set val 3 + .tv selection toggle {myItem3 myItem2} ; # <> triggers + update + set val 4 + .tv selection toggle {myItem3 myItem2} ; # <> triggers + update + set res +} -result {2 3 4} ### NEED: more tests for see/yview/scrolling proc scrollcallback {args} { set ::scrolldata $args