You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

472 lines
15 KiB

# MIT License
#
# Copyright (c) 2025 Eugenio Parodi <ceccopierangiolieugenio AT googlemail DOT com>
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
import sys, os
import pytest
from typing import Union, Optional, List, Tuple
sys.path.append(os.path.join(sys.path[0],'../../libs/pyTermTk'))
import TermTk as ttk
def _gen_childs(num:int,prefix:str,nesting=2) -> List[ttk.TTkTreeWidgetItem]:
ret = []
for i in range(num):
_c = ttk.TTkTreeWidgetItem([f"{prefix} A {i}"+'\nabc'*i, f"{prefix} B {i}", f"{prefix} C {i}"])
ret.append(_c)
if i%2:
_c.setExpanded(True)
if nesting:
_c.addChildren(_gen_childs(num,f"{prefix}_X",nesting-1))
return ret
def _add_children(item:ttk.TTkTreeWidgetItem):
item.addChildren(_gen_childs(4,'l2',2))
def _create_tree() -> Tuple[ttk.TTkTreeWidgetItem,ttk.TTkTreeWidgetItem,ttk.TTkTreeWidgetItem]:
l0 = ttk.TTkTreeWidgetItem(["XX0","XX0","XX0"])
l1 = ttk.TTkTreeWidgetItem(["String A", "String B", "String C"])
l2 = ttk.TTkTreeWidgetItem(["String AA", "String BB", "String CC"])
l3 = ttk.TTkTreeWidgetItem(["String AAA", "String BBB", "String CCC"])
l4 = ttk.TTkTreeWidgetItem(["String AAAA", "String BBBB", "String CCCC"])
l5 = ttk.TTkTreeWidgetItem(["String AAAAA", "String BBBBB", "String CCCCC"])
l2.addChild(l5)
l1.addChildren(_gen_childs(2,'l1',1))
l2.addChildren(_gen_childs(4,'l2',2))
l3.addChildren(_gen_childs(3,'l3',1))
l4.addChildren(_gen_childs(2,'l4',1))
l5.addChildren(_gen_childs(2,'l5',1))
l0.addChild(l1)
l0.addChild(l2)
l0.addChild(l3)
l0.addChild(l4)
l0.setExpanded(True)
l2.setExpanded(True)
l5.setExpanded(True)
l4.setExpanded(True)
return l0, l2, l5
def _format_item(item:ttk.TTkTreeWidgetItem) -> str:
return f"{item.data(0)} h:{item.height()} {item.data(1)} {item.data(2)}".replace('\n','_\\n_')
def _print_tree(child:ttk.TTkTreeWidgetItem, level:int=0):
if child.isExpanded() and child.children():
print(' '*level, ' v ', _format_item(child))
for i,c in enumerate(child.children()):
_print_tree(c,level+1)
elif child.children():
print(' '*level, ' > ', _format_item(child))
else:
print(' '*level, ' - ', _format_item(child))
# def test_tree_item_iterate_skip():
# tree,_,_ = _create_tree()
# print('\nTree:')
# _print_tree(tree)
# # for i,(a,b) in enumerate(tree.iterate()):
# # print(f"{i:03} - ", b, ' '*b, _format_item(a))
# # print('\nSkip 3')
# # for i,(a,b) in enumerate(tree.iterate(skip=3),3):
# # print(f"{i:03} - ", b, ' '*b, _format_item(a))
# # print('\nSkip 7')
# # for i,(a,b) in enumerate(tree.iterate(skip=7),7):
# # print(f"{i:03} - ", b, ' '*b, _format_item(a))
# full = [(a,b) for a,b in tree._iterate()]
# assert full == [(a,b) for a,b in tree._iterate()]
# assert full == [(a,b) for a,b in tree._iterate(skip= 0)]
# assert full[ 3:] == [(a,b) for a,b in tree._iterate(skip= 3)]
# assert full[ 5:] == [(a,b) for a,b in tree._iterate(skip= 5)]
# assert full[ 6:] == [(a,b) for a,b in tree._iterate(skip= 6)]
# assert full[10:] == [(a,b) for a,b in tree._iterate(skip=10)]
# assert full[15:] == [(a,b) for a,b in tree._iterate(skip=15)]
# assert full[20:] == [(a,b) for a,b in tree._iterate(skip=20)]
# assert full[30:] == [(a,b) for a,b in tree._iterate(skip=30)]
# assert full[80:] == [(a,b) for a,b in tree._iterate(skip=80)]
# assert [] == [(a,b) for a,b in tree._iterate(skip=80)]
def test_tree_item_iterate_skip_2():
def my_gen():
for i in range(10):
yield i
# Save progress
gen = my_gen()
# Resume from saved_index
for i,item in enumerate(gen):
print(i, item)
if i==5:
break
for i,item in enumerate(gen):
print(i, item)
# def test_tree_item_listify():
# tree,c1,c2 = _create_tree()
# print('\nTree:')
# _print_tree(tree)
# for i,(a,b,c) in enumerate(tree.listify()):
# print(f"{i:03} - ", b, c, ' '*b, _format_item(a))
# full = [(a,b) for a,b in tree._iterate()]
# print('expand')
# c1.setExpanded(False)
# for i,(a,b,c) in enumerate(tree.listify()):
# print(f"{i:03} - ", b, c, ' '*b, _format_item(a))
# print('expand')
# c1.setExpanded(True)
# for i,(a,b,c) in enumerate(tree.listify()):
# print(f"{i:03} - ", b, c, ' '*b, _format_item(a))
# print('expand')
# c2.setExpanded(False)
# for i,(a,b,c) in enumerate(tree.listify()):
# print(f"{i:03} - ", b, c, ' '*b, _format_item(a))
# print('expand')
# c2.setExpanded(True)
# for i,(a,b,c) in enumerate(tree.listify()):
# print(f"{i:03} - ", b, c, ' '*b, _format_item(a))
# print('expand c1 False')
# c1.setExpanded(False)
# for i,(a,b,c) in enumerate(tree.listify()):
# print(f"{i:03} - ", b, c, ' '*b, _format_item(a))
# print('expand c2 False')
# c2.setExpanded(False)
# for i,(a,b,c) in enumerate(tree.listify()):
# print(f"{i:03} - ", b, c, ' '*b, _format_item(a))
# print('expand c2 True')
# c2.setExpanded(True)
# for i,(a,b,c) in enumerate(tree.listify()):
# print(f"{i:03} - ", b, c, ' '*b, _format_item(a))
# print('expand c1 True')
# c1.setExpanded(True)
# for i,(a,b,c) in enumerate(tree.listify()):
# print(f"{i:03} - ", b, c, ' '*b, _format_item(a))
def _get_node_size(item:ttk.TTkTreeWidgetItem):
size = item.height()
if item.isExpanded():
for _ch in item.children():
size += _get_node_size(_ch)
return size
def _test_size_ch(ch:ttk.TTkTreeWidgetItem):
print(_format_item(ch))
assert _get_node_size(ch) == ch.size() , _format_item(ch)
# Test first the children and the parent
def _loop_1(item:ttk.TTkTreeWidgetItem):
if item.isExpanded():
for _ch in item.children():
_loop_1(_ch)
_test_size_ch(item)
# Test first the parent and the children
def _loop_2(item:ttk.TTkTreeWidgetItem):
_test_size_ch(item)
if item.isExpanded():
for _ch in item.children():
_loop_2(_ch)
def test_tree_sizes_simple_1():
l0 = ttk.TTkTreeWidgetItem(["l0 XX0","XX0","XX0"], expanded=True)
l1 = ttk.TTkTreeWidgetItem(["l1 String A", "String B", "String C"], expanded=True)
l2 = ttk.TTkTreeWidgetItem(["l2 String AA", "String BB", "String CC"], expanded=True)
l3 = ttk.TTkTreeWidgetItem(["l3 String AAA\nAAA\nAAA", "String BBB", "String CCC"], expanded=False)
l4 = ttk.TTkTreeWidgetItem(["l4 String AAAA", "String BBBB", "String CCCC"], expanded=True)
l5 = ttk.TTkTreeWidgetItem(["l5 String AAAAA", "String BBBBB\nB\nB", "String CCCCC"], expanded=True)
l0.addChildren([l1,l2,l4])
l1.addChild(l3)
l3.addChild(l5)
_loop_1(l0)
def test_tree_sizes_simple_2():
l0 = ttk.TTkTreeWidgetItem(["XX0","XX0","XX0"], expanded=False)
l1 = ttk.TTkTreeWidgetItem(["String A", "String B", "String C"], expanded=False)
l2 = ttk.TTkTreeWidgetItem(["String AA", "String BB", "String CC"], expanded=False)
l0.addChild(l1)
l0.setExpanded(True)
l1.setExpanded(True)
l2.setExpanded(True)
l1.addChild(l2)
assert _get_node_size(l0) == l0.size() , _format_item(l0)
def test_tree_sizes_simple_3():
l0 = ttk.TTkTreeWidgetItem(["XX0","XX0","XX0"], expanded=True)
l1 = ttk.TTkTreeWidgetItem(["String A", "String B", "String C"], expanded=True)
l3 = ttk.TTkTreeWidgetItem(["String AAA\nAAA\nAAA", "String BBB", "String CCC"], expanded=False)
l5 = ttk.TTkTreeWidgetItem(["String AAAAA", "String BBBBB\nB\nB", "String CCCCC"], expanded=True)
l0.addChild(l1)
l1.addChild(l3)
l3.addChild(l5)
_loop_1(l0)
def test_tree_sizes_simple_4_expanding():
l0 = ttk.TTkTreeWidgetItem(["XX0","XX0","XX0"], expanded=True)
l1 = ttk.TTkTreeWidgetItem(["String A", "String B", "String C"], expanded=True)
l2 = ttk.TTkTreeWidgetItem(["String AA", "String BB", "String CC"], expanded=True)
l3 = ttk.TTkTreeWidgetItem(["String AAA\nAAA\nAAA", "String BBB", "String CCC"], expanded=False)
l4 = ttk.TTkTreeWidgetItem(["String AAAA", "String BBBB", "String CCCC"], expanded=True)
l5 = ttk.TTkTreeWidgetItem(["String AAAAA", "String BBBBB\nB\nB", "String CCCCC"], expanded=True)
l0.addChildren([l1,l2,l4])
l1.addChild(l3)
l3.addChild(l5)
def _expand_test(item:ttk.TTkTreeWidgetItem):
item.setExpanded(True)
_loop_1(item)
item.setExpanded(False)
_loop_1(item)
item.setExpanded(True)
_loop_1(item)
for ch in item.children():
ch.setExpanded(True)
_loop_1(item)
ch.setExpanded(False)
_loop_1(item)
ch.setExpanded(True)
_loop_1(item)
ch.collapseAll()
_loop_1(item)
ch.expandAll()
_loop_1(item)
item.collapseAll()
_loop_1(item)
item.expandAll()
_loop_1(item)
_expand_test(l0)
_expand_test(l1)
_expand_test(l2)
_expand_test(l3)
_expand_test(l4)
_expand_test(l5)
def test_tree_sizes_widgets_1():
btn_1 = ttk.TTkButton(text='Test B 1', border=True, height=5)
btn_2 = ttk.TTkButton(text='Test B 2', border=True, height=5)
btn_3 = ttk.TTkButton(text='Test B 3', border=True, height=5)
l0 = ttk.TTkTreeWidgetItem(["l0 XX0","XX0","XX0"], expanded=True)
l1 = ttk.TTkTreeWidgetItem(["l1 String A", "String B", "String C"], expanded=True)
l2 = ttk.TTkTreeWidgetItem(["l2 String AA", "String BB", "String CC"], expanded=True)
l3 = ttk.TTkTreeWidgetItem([btn_1, "l3 String BBB", "String CCC"], expanded=False)
l4 = ttk.TTkTreeWidgetItem(["l4 String AAAA", "String BBBB", btn_3], expanded=True)
l5 = ttk.TTkTreeWidgetItem(["l5 String AAAAA", btn_2, "String CCCCC"], expanded=True)
l0.addChildren([l1,l2,l4])
l1.addChild(l3)
l3.addChild(l5)
print('\nTree:')
_print_tree(l0)
_loop_1(l0)
assert l0.size() == 13
btn_1.resize(10,10)
assert l0.size() == 18
btn_2.resize(10,10)
assert l0.size() == 18
btn_3.resize(10,10)
assert l0.size() == 23
def test_tree_sizes_complex():
tree,c1,c2 = _create_tree()
_loop_1(tree)
tree,c1,c2 = _create_tree()
_loop_2(tree)
def test_tree_sizes_adding_nodes():
tree,c1,c2 = _create_tree()
_loop_1(tree)
_add_children(c1)
_loop_1(tree)
_add_children(c2)
_loop_1(tree)
tree,c1,c2 = _create_tree()
_loop_2(tree)
_add_children(c1)
_loop_1(tree)
_add_children(c2)
_loop_1(tree)
def _get_full_tree_page(item:ttk.TTkTreeWidgetItem) -> List[ttk.TTkTreeWidgetItem]:
ret = [item]*item._height
if item.isExpanded():
for ch in item.children():
ret.extend(_get_full_tree_page(ch))
return ret
def test_tree_get_page():
tree,c1,c2 = _create_tree()
full_page = _get_full_tree_page(tree)
print('\nTree:')
_print_tree(tree)
def _test_page(index,size):
page = tree._get_page(0,index,size)
# print(f"Testing: {index=} {size=} , page size={len(page)}")
assert (
[f"{c.isExpanded()} {c.data(0)}" for c in full_page[index:index+size]] ==
[f"{c.isExpanded()} {c.data(0)}" for _,_,c in page] )
# _test_page(0,1)
# _test_page(0,2)
# _test_page(0,3)
# _test_page(0,4)
# _test_page(0,5)
# _test_page(0,5)
# _test_page(0,6)
# _test_page(0,7)
# _test_page(0,10)
# _test_page(0,100)
for i in range(0,100,1):
for j in range(0,100,1):
_test_page(i,j)
print("\n - 0,10")
page = tree._get_page(0,0,10)
for a,b,c in page:
print(a, b, ' '*a, _format_item(c))
print("\n - 2,5")
page = tree._get_page(0,2,5)
for a,b,c in page:
print(a, b, ' '*a, _format_item(c))
def test_tree_sort():
tree,c1,c2 = _create_tree()
def _test():
full_page = _get_full_tree_page(tree)
page = tree._get_page(0,0,10000)
assert (
[f"{c.isExpanded()} {c.data(0)}" for c in full_page] ==
[f"{c.isExpanded()} {c.data(0)}" for _,_,c in page] )
_test()
tree.sortChildren(0,ttk.TTkK.AscendingOrder)
_test()
tree.sortChildren(0,ttk.TTkK.DescendingOrder)
_test()
tree.sortChildren(1,ttk.TTkK.AscendingOrder)
_test()
tree.sortChildren(1,ttk.TTkK.DescendingOrder)
_test()
tree.sortChildren(2,ttk.TTkK.AscendingOrder)
_test()
tree.sortChildren(2,ttk.TTkK.DescendingOrder)
_test()
def test_tree_take_child():
tree,c1,c2 = _create_tree()
print('\nTree:')
_print_tree(tree)
def _test_page():
full_page = _get_full_tree_page(tree)
page = tree._get_page(0,0,1000)
assert len(full_page) == tree.size() == len(page)
assert (
[f"{c.isExpanded()} {c.data(0)}" for c in full_page] ==
[f"{c.isExpanded()} {c.data(0)}" for _,_,c in page] )
print(f"Testing: size={len(page)},{tree.size()}")
_test_page()
c2.takeChild(1)
_test_page()
c1.takeChildren()
_test_page()
def test_tree_show_hide():
l0 = ttk.TTkTreeWidgetItem(["l0", "l0", "l0", "l0", "l0"],expanded=True)
l1 = ttk.TTkTreeWidgetItem(["l1", "l1", "l1", "l1", "l1"],expanded=True)
l2 = ttk.TTkTreeWidgetItem(["l2", "l2", "l2", "l2", "l2"],expanded=True)
l3 = ttk.TTkTreeWidgetItem(["l3", "l3", "l3", "l3", "l3"],expanded=True)
l4 = ttk.TTkTreeWidgetItem(["l4", "l4", "l4", "l4", "l4"],expanded=True)
l5 = ttk.TTkTreeWidgetItem(["l5", "l5", "l5", "l5", "l5"],expanded=True)
l0.addChildren([l1,l2,l4])
l1.addChild(l3)
l3.addChild(l5)
print(l0.size())
l5.setHidden(True)
print(l0.size())
l4.setHidden(True)
print(l0.size())
l5.setHidden(False)
print(l0.size())
l4.setHidden(False)
print(l0.size())