tksheet 7.4.9__py3-none-any.whl → 7.4.11__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- tksheet/__init__.py +1 -1
- tksheet/column_headers.py +16 -13
- tksheet/functions.py +18 -15
- tksheet/main_table.py +152 -131
- tksheet/row_index.py +286 -131
- tksheet/sheet.py +186 -236
- tksheet/sorting.py +61 -50
- tksheet/tksheet_types.py +0 -3
- {tksheet-7.4.9.dist-info → tksheet-7.4.11.dist-info}/METADATA +1 -1
- tksheet-7.4.11.dist-info/RECORD +22 -0
- tksheet-7.4.9.dist-info/RECORD +0 -22
- {tksheet-7.4.9.dist-info → tksheet-7.4.11.dist-info}/LICENSE.txt +0 -0
- {tksheet-7.4.9.dist-info → tksheet-7.4.11.dist-info}/WHEEL +0 -0
- {tksheet-7.4.9.dist-info → tksheet-7.4.11.dist-info}/top_level.txt +0 -0
tksheet/row_index.py
CHANGED
@@ -2,7 +2,7 @@ from __future__ import annotations
|
|
2
2
|
|
3
3
|
import tkinter as tk
|
4
4
|
from collections import defaultdict
|
5
|
-
from collections.abc import Callable, Generator, Hashable, Sequence
|
5
|
+
from collections.abc import Callable, Generator, Hashable, Iterator, Sequence
|
6
6
|
from functools import partial
|
7
7
|
from itertools import chain, cycle, islice, repeat
|
8
8
|
from math import ceil, floor
|
@@ -19,6 +19,7 @@ from .constants import (
|
|
19
19
|
)
|
20
20
|
from .formatters import is_bool_like, try_to_bool
|
21
21
|
from .functions import (
|
22
|
+
add_to_displayed,
|
22
23
|
consecutive_ranges,
|
23
24
|
del_placeholder_dict_key,
|
24
25
|
event_dict,
|
@@ -40,7 +41,6 @@ from .functions import (
|
|
40
41
|
from .other_classes import DotDict, DraggedRowColumn, DropdownStorage, EventDataDict, Node, TextEditorStorage
|
41
42
|
from .sorting import sort_columns_by_row, sort_row
|
42
43
|
from .text_editor import TextEditor
|
43
|
-
from .tksheet_types import AnyIter
|
44
44
|
|
45
45
|
|
46
46
|
class RowIndex(tk.Canvas):
|
@@ -891,7 +891,7 @@ class RowIndex(tk.Canvas):
|
|
891
891
|
def _sort_rows(
|
892
892
|
self,
|
893
893
|
event: tk.Event | None = None,
|
894
|
-
rows:
|
894
|
+
rows: Iterator[int] | None = None,
|
895
895
|
reverse: bool = False,
|
896
896
|
validation: bool = True,
|
897
897
|
key: Callable | None = None,
|
@@ -947,7 +947,7 @@ class RowIndex(tk.Canvas):
|
|
947
947
|
if row is None:
|
948
948
|
if not self.MT.selected:
|
949
949
|
return event_data
|
950
|
-
row = self.MT.selected.row
|
950
|
+
row = self.MT.datarn(self.MT.selected.row)
|
951
951
|
if try_binding(self.ri_extra_begin_sort_cols_func, event_data, "begin_move_columns"):
|
952
952
|
if key is None:
|
953
953
|
key = self.PAR.ops.sort_key
|
@@ -1012,7 +1012,7 @@ class RowIndex(tk.Canvas):
|
|
1012
1012
|
|
1013
1013
|
def select_row(
|
1014
1014
|
self,
|
1015
|
-
r: int |
|
1015
|
+
r: int | Iterator[int],
|
1016
1016
|
redraw: bool = False,
|
1017
1017
|
run_binding_func: bool = True,
|
1018
1018
|
ext: bool = False,
|
@@ -1207,7 +1207,7 @@ class RowIndex(tk.Canvas):
|
|
1207
1207
|
|
1208
1208
|
def get_index_text_width(
|
1209
1209
|
self,
|
1210
|
-
only_rows:
|
1210
|
+
only_rows: Iterator[int] | None = None,
|
1211
1211
|
) -> int:
|
1212
1212
|
self.fix_index()
|
1213
1213
|
w = self.ops.default_row_index_width
|
@@ -1770,7 +1770,7 @@ class RowIndex(tk.Canvas):
|
|
1770
1770
|
fill=tree_arrow_fg,
|
1771
1771
|
tag="ta",
|
1772
1772
|
indent=indent,
|
1773
|
-
has_children=bool(self.
|
1773
|
+
has_children=bool(self.MT._row_index[datarn].children),
|
1774
1774
|
open_=self.MT._row_index[datarn].iid in self.tree_open_ids,
|
1775
1775
|
level=level,
|
1776
1776
|
)
|
@@ -2584,9 +2584,8 @@ class RowIndex(tk.Canvas):
|
|
2584
2584
|
# Treeview Mode
|
2585
2585
|
|
2586
2586
|
def tree_reset(self) -> None:
|
2587
|
-
self.tree: dict[str, Node] = {}
|
2588
2587
|
self.tree_open_ids = set()
|
2589
|
-
self.
|
2588
|
+
self.rns = {}
|
2590
2589
|
if self.MT:
|
2591
2590
|
self.MT.displayed_rows = []
|
2592
2591
|
self.MT._row_index = []
|
@@ -2596,7 +2595,7 @@ class RowIndex(tk.Canvas):
|
|
2596
2595
|
|
2597
2596
|
def new_iid(self) -> str:
|
2598
2597
|
self.new_iid_ctr += 1
|
2599
|
-
while (iid := f"{num2alpha(self.new_iid_ctr)}") in self.
|
2598
|
+
while (iid := f"{num2alpha(self.new_iid_ctr)}") in self.rns:
|
2600
2599
|
self.new_iid_ctr += 1
|
2601
2600
|
return iid
|
2602
2601
|
|
@@ -2608,7 +2607,7 @@ class RowIndex(tk.Canvas):
|
|
2608
2607
|
|
2609
2608
|
def tree_del_rows(self, event_data: EventDataDict) -> EventDataDict:
|
2610
2609
|
event_data["treeview"]["nodes"] = {}
|
2611
|
-
for node in
|
2610
|
+
for node in event_data["deleted"]["index"].values():
|
2612
2611
|
iid = node.iid
|
2613
2612
|
if parent_node := self.parent_node(iid):
|
2614
2613
|
if parent_node.iid not in event_data["treeview"]["nodes"]:
|
@@ -2619,38 +2618,52 @@ class RowIndex(tk.Canvas):
|
|
2619
2618
|
children=parent_node.children.copy(),
|
2620
2619
|
)
|
2621
2620
|
self.remove_iid_from_parents_children(iid)
|
2622
|
-
for node in
|
2621
|
+
for node in event_data["deleted"]["index"].values():
|
2623
2622
|
iid = node.iid
|
2624
2623
|
for did in self.get_iid_descendants(iid):
|
2625
2624
|
self.tree_open_ids.discard(did)
|
2626
|
-
del self.tree[did]
|
2627
2625
|
self.tree_open_ids.discard(iid)
|
2628
|
-
|
2626
|
+
|
2627
|
+
for datarn in reversed(event_data["deleted"]["index"]):
|
2628
|
+
del self.MT._row_index[datarn]
|
2629
|
+
|
2629
2630
|
return event_data
|
2630
2631
|
|
2631
2632
|
def tree_add_rows(self, event_data: EventDataDict) -> EventDataDict:
|
2632
2633
|
for rn, node in event_data["added"]["rows"]["index"].items():
|
2633
|
-
self.
|
2634
|
-
|
2634
|
+
self.rns[node.iid] = rn
|
2635
|
+
|
2635
2636
|
if event_data["treeview"]["nodes"]:
|
2636
2637
|
self.restore_nodes(event_data=event_data)
|
2637
2638
|
else:
|
2638
|
-
row, a_node = next(
|
2639
|
+
row, a_node = next(iter(event_data["added"]["rows"]["index"].items()))
|
2639
2640
|
if parent := a_node.parent:
|
2640
|
-
if self.
|
2641
|
+
if self.iid_children(parent):
|
2641
2642
|
index = next(
|
2642
|
-
(i for i, cid in enumerate(self.
|
2643
|
-
len(self.
|
2643
|
+
(i for i, cid in enumerate(self.iid_children(parent)) if self.rns[cid] >= row),
|
2644
|
+
len(self.iid_children(parent)),
|
2644
2645
|
)
|
2645
|
-
self.
|
2646
|
-
n.iid for n in
|
2646
|
+
self.iid_children(parent)[index:index] = [
|
2647
|
+
n.iid for n in event_data["added"]["rows"]["index"].values()
|
2647
2648
|
]
|
2648
2649
|
else:
|
2649
|
-
self.
|
2650
|
-
|
2651
|
-
|
2652
|
-
|
2653
|
-
|
2650
|
+
self.iid_children(parent).extend(n.iid for n in event_data["added"]["rows"]["index"].values())
|
2651
|
+
|
2652
|
+
# handle displaying the new rows
|
2653
|
+
event_data["added"]["rows"]["row_heights"] = {}
|
2654
|
+
if parent and self.PAR.item_displayed(parent) and parent in self.tree_open_ids:
|
2655
|
+
self.MT.displayed_rows = add_to_displayed(self.MT.displayed_rows, event_data["added"]["rows"]["index"])
|
2656
|
+
disp_idx = self.MT.disprn(self.rns[a_node.iid]) # first node, they're contiguous because not undo
|
2657
|
+
h = self.MT.get_default_row_height()
|
2658
|
+
for i in range(len(event_data["added"]["rows"]["index"])):
|
2659
|
+
event_data["added"]["rows"]["row_heights"][disp_idx + i] = h
|
2660
|
+
|
2661
|
+
elif not parent:
|
2662
|
+
self.MT.displayed_rows = add_to_displayed(self.MT.displayed_rows, event_data["added"]["rows"]["index"])
|
2663
|
+
h = self.MT.get_default_row_height()
|
2664
|
+
for datarn in event_data["added"]["rows"]["index"]:
|
2665
|
+
event_data["added"]["rows"]["row_heights"][self.MT.disprn(datarn)] = h
|
2666
|
+
|
2654
2667
|
return event_data
|
2655
2668
|
|
2656
2669
|
def move_rows_mod_nodes(
|
@@ -2676,18 +2689,18 @@ class RowIndex(tk.Canvas):
|
|
2676
2689
|
elif event_data["moved"]["rows"]:
|
2677
2690
|
if node_change:
|
2678
2691
|
item = node_change[0]
|
2679
|
-
moved_rows = [self.
|
2692
|
+
moved_rows = [self.rns[item]]
|
2680
2693
|
new_parent = node_change[1]
|
2681
2694
|
move_to_index = node_change[2]
|
2682
2695
|
if new_parent:
|
2683
2696
|
if isinstance(move_to_index, int):
|
2684
|
-
move_to_index = min(move_to_index, len(self.
|
2697
|
+
move_to_index = min(move_to_index, len(self.iid_children(new_parent)))
|
2685
2698
|
else:
|
2686
|
-
move_to_index = len(self.
|
2687
|
-
move_to_row = self.
|
2688
|
-
_find = move_to_index + 1 if new_parent == self.
|
2699
|
+
move_to_index = len(self.iid_children(new_parent))
|
2700
|
+
move_to_row = self.rns[new_parent]
|
2701
|
+
_find = move_to_index + 1 if new_parent == self.iid_parent(item) else move_to_index
|
2689
2702
|
move_to_row += _find + sum(
|
2690
|
-
self.num_descendants(cid) for cid in islice(self.
|
2703
|
+
self.num_descendants(cid) for cid in islice(self.iid_children(new_parent), _find)
|
2691
2704
|
)
|
2692
2705
|
insert_row = move_to_row + 1
|
2693
2706
|
else:
|
@@ -2713,7 +2726,7 @@ class RowIndex(tk.Canvas):
|
|
2713
2726
|
|
2714
2727
|
# remove descendants in iids to move
|
2715
2728
|
iids -= set.union(*iids_descendants.values()) & iids
|
2716
|
-
moved_rows = sorted(map(self.
|
2729
|
+
moved_rows = sorted(map(self.rns.__getitem__, iids))
|
2717
2730
|
item = self.MT._row_index[moved_rows[0]].iid
|
2718
2731
|
|
2719
2732
|
if isinstance(event_data.value, int):
|
@@ -2735,7 +2748,7 @@ class RowIndex(tk.Canvas):
|
|
2735
2748
|
move_to_iid = self.MT._row_index[insert_row].iid
|
2736
2749
|
|
2737
2750
|
move_to_index = self.PAR.index(move_to_iid)
|
2738
|
-
new_parent = self.
|
2751
|
+
new_parent = self.iid_parent(move_to_iid)
|
2739
2752
|
|
2740
2753
|
event_data["moved"]["rows"]["data"] = {moved_rows[0]: insert_row}
|
2741
2754
|
|
@@ -2747,10 +2760,10 @@ class RowIndex(tk.Canvas):
|
|
2747
2760
|
if new_loc_is_displayed:
|
2748
2761
|
if disp_insert_row is None:
|
2749
2762
|
if new_parent or insert_row > move_to_row:
|
2750
|
-
disp_insert_row = self.MT.disprn(self.
|
2763
|
+
disp_insert_row = self.MT.disprn(self.rns[move_to_iid]) + 1
|
2751
2764
|
else:
|
2752
|
-
disp_insert_row = self.MT.disprn(self.
|
2753
|
-
if (disp_from_row := self.MT.try_disprn(self.
|
2765
|
+
disp_insert_row = self.MT.disprn(self.rns[move_to_iid])
|
2766
|
+
if (disp_from_row := self.MT.try_disprn(self.rns[item])) is not None:
|
2754
2767
|
event_data["moved"]["rows"]["displayed"] = {disp_from_row: disp_insert_row}
|
2755
2768
|
else:
|
2756
2769
|
event_data["moved"]["rows"]["displayed"] = {(): disp_insert_row}
|
@@ -2810,13 +2823,13 @@ class RowIndex(tk.Canvas):
|
|
2810
2823
|
) -> EventDataDict:
|
2811
2824
|
# also backs up nodes
|
2812
2825
|
if parent is None:
|
2813
|
-
parent = self.
|
2826
|
+
parent = self.iid_parent(item)
|
2814
2827
|
|
2815
|
-
item_node = self.
|
2828
|
+
item_node = self.iid_node(item)
|
2816
2829
|
|
2817
2830
|
# new parent is an item
|
2818
2831
|
if parent:
|
2819
|
-
parent_node = self.
|
2832
|
+
parent_node = self.iid_node(parent)
|
2820
2833
|
# its the same parent, we're just moving index
|
2821
2834
|
if parent == item_node.parent:
|
2822
2835
|
event_data = self.copy_nodes((item, parent), event_data)
|
@@ -2839,7 +2852,7 @@ class RowIndex(tk.Canvas):
|
|
2839
2852
|
else:
|
2840
2853
|
event_data = self.copy_nodes((item,), event_data)
|
2841
2854
|
self.remove_iid_from_parents_children(item)
|
2842
|
-
self.
|
2855
|
+
self.MT._row_index[self.rns[item]].parent = ""
|
2843
2856
|
|
2844
2857
|
# last row in mapping is where to start from +1
|
2845
2858
|
mapping = event_data["moved"]["rows"]["data"]
|
@@ -2851,7 +2864,7 @@ class RowIndex(tk.Canvas):
|
|
2851
2864
|
else:
|
2852
2865
|
disp_row_ctr = next(reversed(disp_mapping.values())) + 1
|
2853
2866
|
|
2854
|
-
rn = self.
|
2867
|
+
rn = self.rns[item]
|
2855
2868
|
if rn not in mapping:
|
2856
2869
|
mapping[rn] = row_ctr
|
2857
2870
|
row_ctr += 1
|
@@ -2860,9 +2873,9 @@ class RowIndex(tk.Canvas):
|
|
2860
2873
|
disp_row_ctr += 1
|
2861
2874
|
|
2862
2875
|
for did in self.get_iid_descendants(item):
|
2863
|
-
mapping[self.
|
2876
|
+
mapping[self.rns[did]] = row_ctr
|
2864
2877
|
row_ctr += 1
|
2865
|
-
if disp_mapping and (disp_from := self.MT.try_disprn(self.
|
2878
|
+
if disp_mapping and (disp_from := self.MT.try_disprn(self.rns[did])) is not None:
|
2866
2879
|
disp_mapping = del_placeholder_dict_key(disp_mapping, disp_from, disp_row_ctr)
|
2867
2880
|
disp_row_ctr += 1
|
2868
2881
|
|
@@ -2873,11 +2886,10 @@ class RowIndex(tk.Canvas):
|
|
2873
2886
|
|
2874
2887
|
def restore_nodes(self, event_data: EventDataDict) -> None:
|
2875
2888
|
for iid, node in event_data["treeview"]["nodes"].items():
|
2876
|
-
self.MT._row_index[self.
|
2877
|
-
self.tree[iid] = node
|
2889
|
+
self.MT._row_index[self.rns[iid]] = node
|
2878
2890
|
|
2879
2891
|
def copy_node(self, item: str) -> Node:
|
2880
|
-
n = self.
|
2892
|
+
n = self.iid_node(item)
|
2881
2893
|
return Node(
|
2882
2894
|
text=n.text,
|
2883
2895
|
iid=n.iid,
|
@@ -2885,11 +2897,11 @@ class RowIndex(tk.Canvas):
|
|
2885
2897
|
children=n.children.copy(),
|
2886
2898
|
)
|
2887
2899
|
|
2888
|
-
def copy_nodes(self, items:
|
2900
|
+
def copy_nodes(self, items: Iterator[str], event_data: EventDataDict) -> EventDataDict:
|
2889
2901
|
nodes = event_data["treeview"]["nodes"]
|
2890
2902
|
for iid in items:
|
2891
2903
|
if iid not in nodes:
|
2892
|
-
n = self.
|
2904
|
+
n = self.iid_node(iid)
|
2893
2905
|
nodes[iid] = Node(
|
2894
2906
|
text=n.text,
|
2895
2907
|
iid=n.iid,
|
@@ -2898,10 +2910,12 @@ class RowIndex(tk.Canvas):
|
|
2898
2910
|
)
|
2899
2911
|
return event_data
|
2900
2912
|
|
2901
|
-
def get_node_level(self, node: Node
|
2902
|
-
|
2903
|
-
|
2904
|
-
|
2913
|
+
def get_node_level(self, node: Node) -> int:
|
2914
|
+
level = 0
|
2915
|
+
while node.parent:
|
2916
|
+
level += 1
|
2917
|
+
node = self.MT._row_index[self.rns[node.parent]]
|
2918
|
+
return level
|
2905
2919
|
|
2906
2920
|
def ancestors_all_open(self, iid: str, stop_at: str = "") -> bool:
|
2907
2921
|
if stop_at:
|
@@ -2915,48 +2929,68 @@ class RowIndex(tk.Canvas):
|
|
2915
2929
|
|
2916
2930
|
def get_iid_ancestors(self, iid: str) -> Generator[str]:
|
2917
2931
|
current_iid = iid
|
2918
|
-
while self.
|
2919
|
-
parent_iid = self.
|
2932
|
+
while self.MT._row_index[self.rns[current_iid]].parent:
|
2933
|
+
parent_iid = self.MT._row_index[self.rns[current_iid]].parent
|
2920
2934
|
yield parent_iid
|
2921
2935
|
current_iid = parent_iid
|
2922
2936
|
|
2923
2937
|
def get_iid_descendants(self, iid: str, check_open: bool = False) -> Generator[str]:
|
2924
|
-
|
2925
|
-
stack = [iter(
|
2938
|
+
index = self.MT._row_index
|
2939
|
+
stack = [iter(index[self.rns[iid]].children)]
|
2926
2940
|
while stack:
|
2927
2941
|
top_iterator = stack[-1]
|
2928
2942
|
try:
|
2929
2943
|
ciid = next(top_iterator)
|
2930
2944
|
yield ciid
|
2931
|
-
if
|
2932
|
-
stack.append(iter(
|
2945
|
+
if index[self.rns[ciid]].children and (not check_open or ciid in self.tree_open_ids):
|
2946
|
+
stack.append(iter(index[self.rns[ciid]].children))
|
2933
2947
|
except StopIteration:
|
2934
2948
|
stack.pop()
|
2935
2949
|
|
2936
2950
|
def num_descendants(self, iid: str) -> int:
|
2937
|
-
|
2938
|
-
stack = [iter(
|
2951
|
+
index = self.MT._row_index
|
2952
|
+
stack = [iter(index[self.rns[iid]].children)]
|
2939
2953
|
num = 0
|
2940
2954
|
while stack:
|
2941
2955
|
top_iterator = stack[-1]
|
2942
2956
|
try:
|
2943
2957
|
ciid = next(top_iterator)
|
2944
2958
|
num += 1
|
2945
|
-
if
|
2946
|
-
stack.append(iter(
|
2959
|
+
if index[self.rns[ciid]].children:
|
2960
|
+
stack.append(iter(index[self.rns[ciid]].children))
|
2947
2961
|
except StopIteration:
|
2948
2962
|
stack.pop()
|
2949
2963
|
return num
|
2950
2964
|
|
2951
|
-
def
|
2952
|
-
|
2953
|
-
|
2954
|
-
|
2965
|
+
def iid_node(self, iid: str) -> Node:
|
2966
|
+
return self.MT._row_index[self.rns[iid]]
|
2967
|
+
|
2968
|
+
def iid_parent(self, iid: str) -> str:
|
2969
|
+
return self.MT._row_index[self.rns[iid]].parent
|
2955
2970
|
|
2956
|
-
def
|
2957
|
-
|
2958
|
-
|
2959
|
-
|
2971
|
+
def iid_children(self, iid: str) -> list[str]:
|
2972
|
+
return self.MT._row_index[self.rns[iid]].children
|
2973
|
+
|
2974
|
+
def parent_node(self, iid: str) -> Node | Literal[""]:
|
2975
|
+
if self.MT._row_index[self.rns[iid]].parent:
|
2976
|
+
return self.MT._row_index[self.rns[self.MT._row_index[self.rns[iid]].parent]]
|
2977
|
+
else:
|
2978
|
+
return ""
|
2979
|
+
|
2980
|
+
def rename_iid(self, old: str, new: str, event_data: EventDataDict) -> EventDataDict:
|
2981
|
+
event_data.treeview.renamed[old] = new
|
2982
|
+
for ciid in self.iid_children(old):
|
2983
|
+
self.MT._row_index[self.rns[ciid]].parent = new
|
2984
|
+
if self.iid_parent(old):
|
2985
|
+
parent_node = self.parent_node(old)
|
2986
|
+
item_index = parent_node.children.index(old)
|
2987
|
+
parent_node.children[item_index] = new
|
2988
|
+
self.MT._row_index[self.rns[old]].iid = new
|
2989
|
+
self.rns[new] = self.rns.pop(old)
|
2990
|
+
if old in self.tree_open_ids:
|
2991
|
+
self.tree_open_ids.discard(old)
|
2992
|
+
self.tree_open_ids.add(new)
|
2993
|
+
return event_data
|
2960
2994
|
|
2961
2995
|
def gen_top_nodes(self) -> Generator[Node]:
|
2962
2996
|
yield from (node for node in self.MT._row_index if node.parent == "")
|
@@ -2966,14 +3000,14 @@ class RowIndex(tk.Canvas):
|
|
2966
3000
|
indent = self.MT.index_txt_width * int(self.ops.treeview_indent)
|
2967
3001
|
else:
|
2968
3002
|
indent = self.ops.treeview_indent
|
2969
|
-
return indent *
|
3003
|
+
return indent * self.get_node_level(self.iid_node(iid))
|
2970
3004
|
|
2971
3005
|
def get_iid_level_indent(self, iid: str) -> tuple[int, int]:
|
2972
3006
|
if isinstance(self.ops.treeview_indent, str):
|
2973
3007
|
indent = self.MT.index_txt_width * int(self.ops.treeview_indent)
|
2974
3008
|
else:
|
2975
3009
|
indent = self.ops.treeview_indent
|
2976
|
-
level =
|
3010
|
+
level = self.get_node_level(self.iid_node(iid))
|
2977
3011
|
return level, indent * level
|
2978
3012
|
|
2979
3013
|
def remove_iid_from_parents_children(self, iid: str) -> None:
|
@@ -3004,80 +3038,182 @@ class RowIndex(tk.Canvas):
|
|
3004
3038
|
text_column: None | int | list[str] = None,
|
3005
3039
|
push_ops: bool = False,
|
3006
3040
|
row_heights: Sequence[int] | None | False = None,
|
3007
|
-
open_ids:
|
3008
|
-
safety: bool = True,
|
3041
|
+
open_ids: Iterator[str] | None = None,
|
3009
3042
|
ncols: int | None = None,
|
3010
3043
|
lower: bool = False,
|
3011
3044
|
include_iid_column: bool = True,
|
3012
3045
|
include_parent_column: bool = True,
|
3013
3046
|
include_text_column: bool = True,
|
3014
3047
|
) -> None:
|
3015
|
-
self.
|
3048
|
+
index = self.MT._row_index
|
3049
|
+
data_rns = {}
|
3016
3050
|
if text_column is None:
|
3017
3051
|
text_column = iid_column
|
3018
|
-
tally_of_ids = defaultdict(lambda: -1)
|
3019
3052
|
if not isinstance(ncols, int):
|
3020
3053
|
ncols = max(map(len, data), default=0)
|
3021
3054
|
for rn, row in enumerate(data):
|
3022
|
-
if safety and ncols > (lnr := len(row)):
|
3023
|
-
row += self.MT.get_empty_row_seq(rn, end=ncols, start=lnr)
|
3024
3055
|
if lower:
|
3025
3056
|
iid = row[iid_column].lower()
|
3026
3057
|
pid = row[parent_column].lower()
|
3027
3058
|
else:
|
3028
3059
|
iid = row[iid_column]
|
3029
3060
|
pid = row[parent_column]
|
3030
|
-
if
|
3031
|
-
if
|
3032
|
-
continue
|
3033
|
-
tally_of_ids[iid] += 1
|
3034
|
-
if tally_of_ids[iid]:
|
3035
|
-
x = 1
|
3036
|
-
while iid in tally_of_ids:
|
3037
|
-
new = f"{row[iid_column]}_DUPLICATED_{x}"
|
3038
|
-
iid = new.lower() if lower else new
|
3039
|
-
x += 1
|
3040
|
-
tally_of_ids[iid] += 1
|
3041
|
-
row[iid_column] = new
|
3042
|
-
if iid in self.tree:
|
3043
|
-
self.tree[iid].text = row[text_column] if isinstance(text_column, int) else text_column[rn]
|
3061
|
+
if iid in self.rns:
|
3062
|
+
index[self.rns[iid]].text = row[text_column] if isinstance(text_column, int) else text_column[rn]
|
3044
3063
|
else:
|
3045
|
-
|
3046
|
-
|
3047
|
-
|
3048
|
-
|
3064
|
+
index.append(
|
3065
|
+
Node(
|
3066
|
+
text=row[text_column] if isinstance(text_column, int) else text_column[rn],
|
3067
|
+
iid=iid,
|
3068
|
+
parent="",
|
3069
|
+
)
|
3070
|
+
)
|
3071
|
+
self.rns[iid] = len(index) - 1
|
3072
|
+
data_rns[iid] = rn
|
3049
3073
|
if pid:
|
3050
|
-
if pid in self.
|
3051
|
-
self.
|
3074
|
+
if pid in self.rns:
|
3075
|
+
index[self.rns[pid]].children.append(iid)
|
3052
3076
|
else:
|
3053
|
-
|
3054
|
-
|
3055
|
-
|
3056
|
-
|
3077
|
+
index.append(
|
3078
|
+
Node(
|
3079
|
+
text=pid,
|
3080
|
+
iid=pid,
|
3081
|
+
children=[iid],
|
3082
|
+
)
|
3057
3083
|
)
|
3058
|
-
|
3084
|
+
self.rns[pid] = len(index) - 1
|
3085
|
+
index[self.rns[iid]].parent = pid
|
3059
3086
|
else:
|
3060
|
-
self.
|
3061
|
-
|
3062
|
-
if
|
3063
|
-
|
3064
|
-
|
3065
|
-
|
3066
|
-
|
3067
|
-
|
3068
|
-
|
3069
|
-
|
3070
|
-
|
3071
|
-
|
3087
|
+
index[self.rns[iid]].parent = ""
|
3088
|
+
exclude = set()
|
3089
|
+
if not include_iid_column:
|
3090
|
+
exclude.add(iid_column)
|
3091
|
+
if not include_parent_column:
|
3092
|
+
exclude.add(parent_column)
|
3093
|
+
if isinstance(text_column, int) and not include_text_column:
|
3094
|
+
exclude.add(text_column)
|
3095
|
+
rows = []
|
3096
|
+
if exclude:
|
3097
|
+
for iid in self.PAR.tree_traverse():
|
3098
|
+
row = [index[self.rns[iid]]]
|
3099
|
+
row.extend(e for i, e in enumerate(data[data_rns[iid]]) if i not in exclude)
|
3100
|
+
rows.append(row)
|
3101
|
+
else:
|
3102
|
+
for iid in self.PAR.tree_traverse():
|
3103
|
+
row = [index[self.rns[iid]]]
|
3104
|
+
row.extend(data[data_rns[iid]])
|
3105
|
+
rows.append(row)
|
3106
|
+
self.MT._row_index = []
|
3107
|
+
self.rns = {}
|
3108
|
+
self.PAR.insert_rows(
|
3109
|
+
rows=rows,
|
3072
3110
|
idx=0,
|
3073
|
-
heights=
|
3111
|
+
heights=[] if row_heights is False else row_heights,
|
3074
3112
|
row_index=True,
|
3075
3113
|
create_selections=False,
|
3076
3114
|
fill=False,
|
3077
3115
|
undo=False,
|
3078
3116
|
push_ops=push_ops,
|
3079
3117
|
redraw=False,
|
3118
|
+
tree=False,
|
3080
3119
|
)
|
3120
|
+
self.MT.all_rows_displayed = False
|
3121
|
+
self.MT.displayed_rows = list(range(len(self.MT._row_index)))
|
3122
|
+
self.rns = {n.iid: i for i, n in enumerate(self.MT._row_index)}
|
3123
|
+
if open_ids:
|
3124
|
+
self.PAR.tree_set_open(open_ids=open_ids)
|
3125
|
+
else:
|
3126
|
+
index = self.MT._row_index
|
3127
|
+
self.PAR.hide_rows(
|
3128
|
+
{self.rns[iid] for iid in self.PAR.get_children() if index[self.rns[iid]].parent},
|
3129
|
+
deselect_all=False,
|
3130
|
+
data_indexes=True,
|
3131
|
+
row_heights=row_heights is not False,
|
3132
|
+
)
|
3133
|
+
|
3134
|
+
def safe_tree_build(
|
3135
|
+
self,
|
3136
|
+
data: list[list[Any]],
|
3137
|
+
iid_column: int,
|
3138
|
+
parent_column: int,
|
3139
|
+
text_column: None | int | list[str] = None,
|
3140
|
+
push_ops: bool = False,
|
3141
|
+
row_heights: Sequence[int] | None | False = None,
|
3142
|
+
open_ids: Iterator[str] | None = None,
|
3143
|
+
ncols: int | None = None,
|
3144
|
+
lower: bool = False,
|
3145
|
+
include_iid_column: bool = True,
|
3146
|
+
include_parent_column: bool = True,
|
3147
|
+
include_text_column: bool = True,
|
3148
|
+
) -> None:
|
3149
|
+
index = self.MT._row_index
|
3150
|
+
data_rns = {}
|
3151
|
+
iids_missing_rows = set()
|
3152
|
+
if text_column is None:
|
3153
|
+
text_column = iid_column
|
3154
|
+
tally_of_ids = defaultdict(lambda: -1)
|
3155
|
+
if not isinstance(ncols, int):
|
3156
|
+
ncols = max(map(len, data), default=0)
|
3157
|
+
for rn, row in enumerate(data):
|
3158
|
+
if ncols > (lnr := len(row)):
|
3159
|
+
row += self.MT.get_empty_row_seq(rn, end=ncols, start=lnr)
|
3160
|
+
if lower:
|
3161
|
+
iid = row[iid_column].lower()
|
3162
|
+
pid = row[parent_column].lower()
|
3163
|
+
else:
|
3164
|
+
iid = row[iid_column]
|
3165
|
+
pid = row[parent_column]
|
3166
|
+
if not iid:
|
3167
|
+
continue
|
3168
|
+
tally_of_ids[iid] += 1
|
3169
|
+
if tally_of_ids[iid]:
|
3170
|
+
x = 1
|
3171
|
+
while iid in tally_of_ids:
|
3172
|
+
new = f"{row[iid_column]}_DUPLICATED_{x}"
|
3173
|
+
iid = new.lower() if lower else new
|
3174
|
+
x += 1
|
3175
|
+
tally_of_ids[iid] += 1
|
3176
|
+
row[iid_column] = new
|
3177
|
+
if iid in self.rns:
|
3178
|
+
index[self.rns[iid]].text = row[text_column] if isinstance(text_column, int) else text_column[rn]
|
3179
|
+
else:
|
3180
|
+
index.append(
|
3181
|
+
Node(
|
3182
|
+
text=row[text_column] if isinstance(text_column, int) else text_column[rn],
|
3183
|
+
iid=iid,
|
3184
|
+
parent="",
|
3185
|
+
)
|
3186
|
+
)
|
3187
|
+
self.rns[iid] = len(index) - 1
|
3188
|
+
if iid in iids_missing_rows:
|
3189
|
+
iids_missing_rows.discard(iid)
|
3190
|
+
data_rns[iid] = rn
|
3191
|
+
if iid == pid or self.build_pid_causes_recursive_loop(iid, pid):
|
3192
|
+
row[parent_column] = ""
|
3193
|
+
pid = ""
|
3194
|
+
if pid:
|
3195
|
+
if pid in self.rns:
|
3196
|
+
index[self.rns[pid]].children.append(iid)
|
3197
|
+
else:
|
3198
|
+
index.append(
|
3199
|
+
Node(
|
3200
|
+
text=pid,
|
3201
|
+
iid=pid,
|
3202
|
+
children=[iid],
|
3203
|
+
)
|
3204
|
+
)
|
3205
|
+
iids_missing_rows.add(pid)
|
3206
|
+
self.rns[pid] = len(index) - 1
|
3207
|
+
index[self.rns[iid]].parent = pid
|
3208
|
+
else:
|
3209
|
+
index[self.rns[iid]].parent = ""
|
3210
|
+
empty_rows = {}
|
3211
|
+
for iid in iids_missing_rows:
|
3212
|
+
node = index[self.rns[iid]]
|
3213
|
+
node.parent = ""
|
3214
|
+
newrow = self.MT.get_empty_row_seq(len(data), ncols)
|
3215
|
+
newrow[iid_column] = node.iid
|
3216
|
+
empty_rows[node.iid] = newrow
|
3081
3217
|
exclude = set()
|
3082
3218
|
if not include_iid_column:
|
3083
3219
|
exclude.add(iid_column)
|
@@ -3085,27 +3221,46 @@ class RowIndex(tk.Canvas):
|
|
3085
3221
|
exclude.add(parent_column)
|
3086
3222
|
if isinstance(text_column, int) and not include_text_column:
|
3087
3223
|
exclude.add(text_column)
|
3224
|
+
rows = []
|
3088
3225
|
if exclude:
|
3089
|
-
|
3090
|
-
|
3091
|
-
|
3092
|
-
for
|
3093
|
-
|
3094
|
-
|
3095
|
-
|
3226
|
+
for iid in self.PAR.tree_traverse():
|
3227
|
+
row = [index[self.rns[iid]]]
|
3228
|
+
if iid in empty_rows:
|
3229
|
+
row.extend(e for i, e in enumerate(empty_rows[iid]) if i not in exclude)
|
3230
|
+
else:
|
3231
|
+
row.extend(e for i, e in enumerate(data[data_rns[iid]]) if i not in exclude)
|
3232
|
+
rows.append(row)
|
3096
3233
|
else:
|
3097
|
-
|
3098
|
-
|
3099
|
-
|
3100
|
-
|
3234
|
+
for iid in self.PAR.tree_traverse():
|
3235
|
+
row = [index[self.rns[iid]]]
|
3236
|
+
if iid in empty_rows:
|
3237
|
+
row.extend(empty_rows[iid])
|
3238
|
+
else:
|
3239
|
+
row.extend(data[data_rns[iid]])
|
3240
|
+
rows.append(row)
|
3241
|
+
self.MT._row_index = []
|
3242
|
+
self.rns = {}
|
3243
|
+
self.PAR.insert_rows(
|
3244
|
+
rows=rows,
|
3245
|
+
idx=0,
|
3246
|
+
heights=[] if row_heights is False else row_heights,
|
3247
|
+
row_index=True,
|
3248
|
+
create_selections=False,
|
3249
|
+
fill=False,
|
3250
|
+
undo=False,
|
3251
|
+
push_ops=push_ops,
|
3252
|
+
redraw=False,
|
3253
|
+
tree=False,
|
3254
|
+
)
|
3101
3255
|
self.MT.all_rows_displayed = False
|
3102
3256
|
self.MT.displayed_rows = list(range(len(self.MT._row_index)))
|
3103
|
-
self.
|
3257
|
+
self.rns = {n.iid: i for i, n in enumerate(self.MT._row_index)}
|
3104
3258
|
if open_ids:
|
3105
3259
|
self.PAR.tree_set_open(open_ids=open_ids)
|
3106
3260
|
else:
|
3261
|
+
index = self.MT._row_index
|
3107
3262
|
self.PAR.hide_rows(
|
3108
|
-
{self.
|
3263
|
+
{self.rns[iid] for iid in self.PAR.get_children() if index[self.rns[iid]].parent},
|
3109
3264
|
deselect_all=False,
|
3110
3265
|
data_indexes=True,
|
3111
3266
|
row_heights=row_heights is not False,
|