tksheet 7.4.11__py3-none-any.whl → 7.4.13__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 +44 -65
- tksheet/functions.py +109 -38
- tksheet/main_table.py +325 -316
- tksheet/other_classes.py +4 -2
- tksheet/row_index.py +177 -167
- tksheet/sheet.py +16 -10
- {tksheet-7.4.11.dist-info → tksheet-7.4.13.dist-info}/METADATA +7 -7
- tksheet-7.4.13.dist-info/RECORD +22 -0
- {tksheet-7.4.11.dist-info → tksheet-7.4.13.dist-info}/WHEEL +1 -1
- tksheet-7.4.11.dist-info/RECORD +0 -22
- {tksheet-7.4.11.dist-info → tksheet-7.4.13.dist-info}/LICENSE.txt +0 -0
- {tksheet-7.4.11.dist-info → tksheet-7.4.13.dist-info}/top_level.txt +0 -0
tksheet/other_classes.py
CHANGED
@@ -40,7 +40,7 @@ DraggedRowColumn = namedtuple("DraggedRowColumn", "dragged to_move")
|
|
40
40
|
|
41
41
|
|
42
42
|
class SelectionBox:
|
43
|
-
__slots__ = ("fill_iid", "bd_iid", "index", "header", "coords", "type_")
|
43
|
+
__slots__ = ("fill_iid", "bd_iid", "index", "header", "coords", "type_", "state")
|
44
44
|
|
45
45
|
def __init__(
|
46
46
|
self,
|
@@ -50,6 +50,7 @@ class SelectionBox:
|
|
50
50
|
header: int | None = None,
|
51
51
|
coords: tuple[int, int, int, int] = None,
|
52
52
|
type_: Literal["cells", "rows", "columns"] = "cells",
|
53
|
+
state: Literal["normal", "hidden"] = "normal",
|
53
54
|
) -> None:
|
54
55
|
self.fill_iid = fill_iid
|
55
56
|
self.bd_iid = bd_iid
|
@@ -57,6 +58,7 @@ class SelectionBox:
|
|
57
58
|
self.header = header
|
58
59
|
self.coords = coords
|
59
60
|
self.type_ = type_
|
61
|
+
self.state = state
|
60
62
|
|
61
63
|
|
62
64
|
Selected = namedtuple(
|
@@ -446,7 +448,7 @@ class Node:
|
|
446
448
|
self,
|
447
449
|
text: str,
|
448
450
|
iid: str,
|
449
|
-
parent: str
|
451
|
+
parent: str = "",
|
450
452
|
children: list[str] | None = None,
|
451
453
|
) -> None:
|
452
454
|
self.text = text
|
tksheet/row_index.py
CHANGED
@@ -3,9 +3,10 @@ from __future__ import annotations
|
|
3
3
|
import tkinter as tk
|
4
4
|
from collections import defaultdict
|
5
5
|
from collections.abc import Callable, Generator, Hashable, Iterator, Sequence
|
6
|
+
from contextlib import suppress
|
6
7
|
from functools import partial
|
7
|
-
from itertools import
|
8
|
-
from math import ceil
|
8
|
+
from itertools import cycle, islice, repeat
|
9
|
+
from math import ceil
|
9
10
|
from operator import itemgetter
|
10
11
|
from typing import Any, Literal
|
11
12
|
|
@@ -758,7 +759,7 @@ class RowIndex(tk.Canvas):
|
|
758
759
|
if size < self.MT.min_row_height:
|
759
760
|
new_row_pos = ceil(self.MT.row_positions[self.rsz_h - 1] + self.MT.min_row_height)
|
760
761
|
elif size > self.ops.max_row_height:
|
761
|
-
new_row_pos =
|
762
|
+
new_row_pos = int(self.MT.row_positions[self.rsz_h - 1] + self.ops.max_row_height)
|
762
763
|
increment = new_row_pos - self.MT.row_positions[self.rsz_h]
|
763
764
|
self.MT.row_positions[self.rsz_h + 1 :] = [
|
764
765
|
e + increment for e in islice(self.MT.row_positions, self.rsz_h + 1, None)
|
@@ -1054,51 +1055,6 @@ class RowIndex(tk.Canvas):
|
|
1054
1055
|
self.MT.run_selection_binding("rows")
|
1055
1056
|
return fill_iid
|
1056
1057
|
|
1057
|
-
def display_box(
|
1058
|
-
self,
|
1059
|
-
x1: int,
|
1060
|
-
y1: int,
|
1061
|
-
x2: int,
|
1062
|
-
y2: int,
|
1063
|
-
fill: str,
|
1064
|
-
outline: str,
|
1065
|
-
state: str,
|
1066
|
-
tags: str | tuple[str],
|
1067
|
-
iid: None | int = None,
|
1068
|
-
) -> int:
|
1069
|
-
coords = rounded_box_coords(
|
1070
|
-
x1,
|
1071
|
-
y1,
|
1072
|
-
x2,
|
1073
|
-
y2,
|
1074
|
-
radius=5 if self.ops.rounded_boxes else 0,
|
1075
|
-
)
|
1076
|
-
if isinstance(iid, int):
|
1077
|
-
self.coords(iid, coords)
|
1078
|
-
self.itemconfig(iid, fill=fill, outline=outline, state=state, tags=tags)
|
1079
|
-
else:
|
1080
|
-
if self.hidd_boxes:
|
1081
|
-
iid = self.hidd_boxes.pop()
|
1082
|
-
self.coords(iid, coords)
|
1083
|
-
self.itemconfig(iid, fill=fill, outline=outline, state=state, tags=tags)
|
1084
|
-
else:
|
1085
|
-
iid = self.create_polygon(
|
1086
|
-
coords,
|
1087
|
-
fill=fill,
|
1088
|
-
outline=outline,
|
1089
|
-
state=state,
|
1090
|
-
tags=tags,
|
1091
|
-
smooth=True,
|
1092
|
-
)
|
1093
|
-
self.disp_boxes.add(iid)
|
1094
|
-
return iid
|
1095
|
-
|
1096
|
-
def hide_box(self, item: int | None) -> None:
|
1097
|
-
if isinstance(item, int):
|
1098
|
-
self.disp_boxes.discard(item)
|
1099
|
-
self.hidd_boxes.add(item)
|
1100
|
-
self.itemconfig(item, state="hidden")
|
1101
|
-
|
1102
1058
|
def get_cell_dimensions(self, datarn: int) -> tuple[int, int]:
|
1103
1059
|
txt = self.cell_str(datarn, fix=False)
|
1104
1060
|
if txt:
|
@@ -1116,7 +1072,7 @@ class RowIndex(tk.Canvas):
|
|
1116
1072
|
align = self.cell_options[datarn]["align"]
|
1117
1073
|
else:
|
1118
1074
|
align = self.align
|
1119
|
-
if align
|
1075
|
+
if align[-1] == "w":
|
1120
1076
|
w += self.MT.index_txt_height
|
1121
1077
|
w += self.get_iid_indent(self.MT._row_index[datarn].iid) + 10
|
1122
1078
|
return w, h
|
@@ -1290,7 +1246,7 @@ class RowIndex(tk.Canvas):
|
|
1290
1246
|
new_w = self.get_index_text_width(only_rows=only_rows)
|
1291
1247
|
else:
|
1292
1248
|
new_w = None
|
1293
|
-
if new_w is not None and (sheet_w_x :=
|
1249
|
+
if new_w is not None and (sheet_w_x := int(self.PAR.winfo_width() * 0.7)) < new_w:
|
1294
1250
|
new_w = sheet_w_x
|
1295
1251
|
if new_w and (self.current_width - new_w > 20 or new_w - self.current_width > 3):
|
1296
1252
|
if self.MT.find_window.open:
|
@@ -1308,6 +1264,7 @@ class RowIndex(tk.Canvas):
|
|
1308
1264
|
sel_rows_bg: str,
|
1309
1265
|
selections: dict,
|
1310
1266
|
datarn: int,
|
1267
|
+
has_dd: bool,
|
1311
1268
|
) -> tuple[str, str, bool]:
|
1312
1269
|
redrawn = False
|
1313
1270
|
kwargs = self.get_cell_kwargs(datarn, key="highlight")
|
@@ -1348,11 +1305,7 @@ class RowIndex(tk.Canvas):
|
|
1348
1305
|
self.current_width - 1,
|
1349
1306
|
sr,
|
1350
1307
|
fill=fill,
|
1351
|
-
outline=
|
1352
|
-
self.ops.index_fg
|
1353
|
-
if self.get_cell_kwargs(datarn, key="dropdown") and self.ops.show_dropdown_borders
|
1354
|
-
else ""
|
1355
|
-
),
|
1308
|
+
outline=self.ops.index_fg if has_dd and self.ops.show_dropdown_borders else "",
|
1356
1309
|
tag="s",
|
1357
1310
|
)
|
1358
1311
|
tree_arrow_fg = txtfg
|
@@ -1360,9 +1313,27 @@ class RowIndex(tk.Canvas):
|
|
1360
1313
|
if "rows" in selections and r in selections["rows"]:
|
1361
1314
|
txtfg = self.ops.index_selected_rows_fg
|
1362
1315
|
tree_arrow_fg = self.ops.selected_rows_tree_arrow_fg
|
1316
|
+
redrawn = self.redraw_highlight(
|
1317
|
+
0,
|
1318
|
+
fr + 1,
|
1319
|
+
self.current_width - 1,
|
1320
|
+
sr,
|
1321
|
+
fill=self.ops.index_selected_rows_bg,
|
1322
|
+
outline=self.ops.index_fg if has_dd and self.ops.show_dropdown_borders else "",
|
1323
|
+
tag="s",
|
1324
|
+
)
|
1363
1325
|
elif "cells" in selections and r in selections["cells"]:
|
1364
1326
|
txtfg = self.ops.index_selected_cells_fg
|
1365
1327
|
tree_arrow_fg = self.ops.selected_cells_tree_arrow_fg
|
1328
|
+
redrawn = self.redraw_highlight(
|
1329
|
+
0,
|
1330
|
+
fr + 1,
|
1331
|
+
self.current_width - 1,
|
1332
|
+
sr,
|
1333
|
+
fill=self.ops.index_selected_cells_bg,
|
1334
|
+
outline=self.ops.index_fg if has_dd and self.ops.show_dropdown_borders else "",
|
1335
|
+
tag="s",
|
1336
|
+
)
|
1366
1337
|
else:
|
1367
1338
|
txtfg = self.ops.index_fg
|
1368
1339
|
tree_arrow_fg = self.ops.tree_arrow_fg
|
@@ -1424,7 +1395,7 @@ class RowIndex(tk.Canvas):
|
|
1424
1395
|
) -> None:
|
1425
1396
|
mod = (self.MT.index_txt_height - 1) if self.MT.index_txt_height % 2 else self.MT.index_txt_height
|
1426
1397
|
small_mod = int(mod / 5)
|
1427
|
-
mid_y =
|
1398
|
+
mid_y = int(self.MT.min_row_height / 2)
|
1428
1399
|
if has_children:
|
1429
1400
|
# up arrow
|
1430
1401
|
if open_:
|
@@ -1520,7 +1491,7 @@ class RowIndex(tk.Canvas):
|
|
1520
1491
|
if draw_arrow:
|
1521
1492
|
mod = (self.MT.index_txt_height - 1) if self.MT.index_txt_height % 2 else self.MT.index_txt_height
|
1522
1493
|
small_mod = int(mod / 5)
|
1523
|
-
mid_y =
|
1494
|
+
mid_y = int(self.MT.min_row_height / 2)
|
1524
1495
|
if open_:
|
1525
1496
|
# up arrow
|
1526
1497
|
points = (
|
@@ -1686,6 +1657,7 @@ class RowIndex(tk.Canvas):
|
|
1686
1657
|
continue
|
1687
1658
|
checkbox_kwargs = {}
|
1688
1659
|
datarn = r if self.MT.all_rows_displayed else self.MT.displayed_rows[r]
|
1660
|
+
dropdown_kwargs = self.get_cell_kwargs(datarn, key="dropdown")
|
1689
1661
|
fill, tree_arrow_fg, dd_drawn = self.redraw_highlight_get_text_fg(
|
1690
1662
|
fr=rtopgridln,
|
1691
1663
|
sr=rbotgridln,
|
@@ -1694,19 +1666,21 @@ class RowIndex(tk.Canvas):
|
|
1694
1666
|
sel_rows_bg=sel_rows_bg,
|
1695
1667
|
selections=selections,
|
1696
1668
|
datarn=datarn,
|
1669
|
+
has_dd=bool(dropdown_kwargs),
|
1697
1670
|
)
|
1671
|
+
|
1698
1672
|
if datarn in self.cell_options and "align" in self.cell_options[datarn]:
|
1699
1673
|
align = self.cell_options[datarn]["align"]
|
1700
1674
|
else:
|
1701
1675
|
align = self.align
|
1702
|
-
if dropdown_kwargs
|
1703
|
-
max_width = self.current_width - self.MT.index_txt_height -
|
1704
|
-
if align
|
1676
|
+
if dropdown_kwargs:
|
1677
|
+
max_width = self.current_width - self.MT.index_txt_height - 5
|
1678
|
+
if align[-1] == "w":
|
1705
1679
|
draw_x = 3
|
1706
|
-
elif align
|
1680
|
+
elif align[-1] == "e":
|
1707
1681
|
draw_x = self.current_width - 5 - self.MT.index_txt_height
|
1708
|
-
elif align
|
1709
|
-
draw_x =
|
1682
|
+
elif align[-1] == "n":
|
1683
|
+
draw_x = (self.current_width - self.MT.index_txt_height) / 2
|
1710
1684
|
self.redraw_dropdown(
|
1711
1685
|
0,
|
1712
1686
|
rtopgridln,
|
@@ -1721,22 +1695,22 @@ class RowIndex(tk.Canvas):
|
|
1721
1695
|
)
|
1722
1696
|
else:
|
1723
1697
|
max_width = self.current_width - 2
|
1724
|
-
if align
|
1698
|
+
if align[-1] == "w":
|
1725
1699
|
draw_x = 3
|
1726
|
-
elif align
|
1700
|
+
elif align[-1] == "e":
|
1727
1701
|
draw_x = self.current_width - 3
|
1728
|
-
elif align
|
1729
|
-
draw_x =
|
1702
|
+
elif align[-1] == "n":
|
1703
|
+
draw_x = self.current_width / 2
|
1730
1704
|
if (
|
1731
1705
|
(checkbox_kwargs := self.get_cell_kwargs(datarn, key="checkbox"))
|
1732
1706
|
and not dropdown_kwargs
|
1733
1707
|
and max_width > self.MT.index_txt_height + 1
|
1734
1708
|
):
|
1735
1709
|
box_w = self.MT.index_txt_height + 1
|
1736
|
-
if align
|
1710
|
+
if align[-1] == "w":
|
1737
1711
|
draw_x += box_w + 3
|
1738
|
-
elif align
|
1739
|
-
draw_x +=
|
1712
|
+
elif align[-1] == "n":
|
1713
|
+
draw_x += box_w / 2 + 1
|
1740
1714
|
max_width -= box_w + 4
|
1741
1715
|
try:
|
1742
1716
|
draw_check = (
|
@@ -1759,7 +1733,7 @@ class RowIndex(tk.Canvas):
|
|
1759
1733
|
if treeview and isinstance(self.MT._row_index, list) and len(self.MT._row_index) > datarn:
|
1760
1734
|
iid = self.MT._row_index[datarn].iid
|
1761
1735
|
max_width -= self.MT.index_txt_height
|
1762
|
-
if align
|
1736
|
+
if align[-1] == "w":
|
1763
1737
|
draw_x += self.MT.index_txt_height + 3
|
1764
1738
|
level, indent = self.get_iid_level_indent(iid)
|
1765
1739
|
draw_x += indent + 5
|
@@ -1811,7 +1785,6 @@ class RowIndex(tk.Canvas):
|
|
1811
1785
|
anchor=align,
|
1812
1786
|
state="normal",
|
1813
1787
|
)
|
1814
|
-
self.tag_raise(iid)
|
1815
1788
|
else:
|
1816
1789
|
iid = self.create_text(
|
1817
1790
|
draw_x,
|
@@ -1845,7 +1818,6 @@ class RowIndex(tk.Canvas):
|
|
1845
1818
|
anchor=align,
|
1846
1819
|
state="normal",
|
1847
1820
|
)
|
1848
|
-
self.tag_raise(iid)
|
1849
1821
|
else:
|
1850
1822
|
iid = self.create_text(
|
1851
1823
|
draw_x,
|
@@ -1898,6 +1870,7 @@ class RowIndex(tk.Canvas):
|
|
1898
1870
|
if showing:
|
1899
1871
|
self.itemconfig(iid, state="hidden")
|
1900
1872
|
dct[iid] = False
|
1873
|
+
self.tag_raise("t")
|
1901
1874
|
if self.disp_resize_lines:
|
1902
1875
|
self.tag_raise("rh")
|
1903
1876
|
return True
|
@@ -2505,8 +2478,8 @@ class RowIndex(tk.Canvas):
|
|
2505
2478
|
kwargs = self.get_cell_kwargs(datarn, key=None, cell=r_ops)
|
2506
2479
|
if "checkbox" in kwargs:
|
2507
2480
|
return False
|
2508
|
-
elif
|
2509
|
-
return kwargs["values"][0]
|
2481
|
+
elif "dropdown" in kwargs and kwargs["dropdown"]["validate_input"] and kwargs["dropdown"]["values"]:
|
2482
|
+
return kwargs["dropdown"]["values"][0]
|
2510
2483
|
else:
|
2511
2484
|
return ""
|
2512
2485
|
|
@@ -2757,16 +2730,17 @@ class RowIndex(tk.Canvas):
|
|
2757
2730
|
)
|
2758
2731
|
# deal with displayed mapping
|
2759
2732
|
event_data["moved"]["rows"]["displayed"] = {}
|
2760
|
-
|
2761
|
-
if
|
2762
|
-
if
|
2763
|
-
|
2733
|
+
with suppress(Exception):
|
2734
|
+
if new_loc_is_displayed:
|
2735
|
+
if disp_insert_row is None:
|
2736
|
+
if new_parent or insert_row > move_to_row:
|
2737
|
+
disp_insert_row = self.MT.disprn(self.rns[move_to_iid]) + 1
|
2738
|
+
else:
|
2739
|
+
disp_insert_row = self.MT.disprn(self.rns[move_to_iid])
|
2740
|
+
if (disp_from_row := self.MT.try_disprn(self.rns[item])) is not None:
|
2741
|
+
event_data["moved"]["rows"]["displayed"] = {disp_from_row: disp_insert_row}
|
2764
2742
|
else:
|
2765
|
-
|
2766
|
-
if (disp_from_row := self.MT.try_disprn(self.rns[item])) is not None:
|
2767
|
-
event_data["moved"]["rows"]["displayed"] = {disp_from_row: disp_insert_row}
|
2768
|
-
else:
|
2769
|
-
event_data["moved"]["rows"]["displayed"] = {(): disp_insert_row}
|
2743
|
+
event_data["moved"]["rows"]["displayed"] = {(): disp_insert_row}
|
2770
2744
|
|
2771
2745
|
if any(self.move_pid_causes_recursive_loop(self.MT._row_index[r].iid, new_parent) for r in moved_rows):
|
2772
2746
|
event_data["moved"]["rows"] = {}
|
@@ -2787,7 +2761,7 @@ class RowIndex(tk.Canvas):
|
|
2787
2761
|
event_data["moved"]["rows"]["data"],
|
2788
2762
|
)
|
2789
2763
|
data_new_idxs = event_data["moved"]["rows"]["data"]
|
2790
|
-
data_old_idxs =
|
2764
|
+
data_old_idxs = {v: k for k, v in data_new_idxs.items()}
|
2791
2765
|
|
2792
2766
|
if () in event_data["moved"]["rows"]["displayed"]:
|
2793
2767
|
del event_data["moved"]["rows"]["displayed"][()]
|
@@ -3016,15 +2990,6 @@ class RowIndex(tk.Canvas):
|
|
3016
2990
|
if not parent_node.children:
|
3017
2991
|
self.tree_open_ids.discard(parent_node.iid)
|
3018
2992
|
|
3019
|
-
def build_pid_causes_recursive_loop(self, iid: str, pid: str) -> bool:
|
3020
|
-
return any(
|
3021
|
-
i == pid
|
3022
|
-
for i in chain(
|
3023
|
-
self.get_iid_descendants(iid),
|
3024
|
-
islice(self.get_iid_ancestors(iid), 1, None),
|
3025
|
-
)
|
3026
|
-
)
|
3027
|
-
|
3028
2993
|
def move_pid_causes_recursive_loop(self, to_move_iid: str, move_to_parent: str) -> bool:
|
3029
2994
|
# if the parent the item is being moved under is one of the item's descendants
|
3030
2995
|
# then it is a recursive loop
|
@@ -3045,8 +3010,8 @@ class RowIndex(tk.Canvas):
|
|
3045
3010
|
include_parent_column: bool = True,
|
3046
3011
|
include_text_column: bool = True,
|
3047
3012
|
) -> None:
|
3048
|
-
index = self.MT._row_index
|
3049
3013
|
data_rns = {}
|
3014
|
+
tree = {}
|
3050
3015
|
if text_column is None:
|
3051
3016
|
text_column = iid_column
|
3052
3017
|
if not isinstance(ncols, int):
|
@@ -3058,33 +3023,27 @@ class RowIndex(tk.Canvas):
|
|
3058
3023
|
else:
|
3059
3024
|
iid = row[iid_column]
|
3060
3025
|
pid = row[parent_column]
|
3061
|
-
if iid in
|
3062
|
-
|
3026
|
+
if iid in tree:
|
3027
|
+
tree[iid].text = row[text_column] if isinstance(text_column, int) else text_column[rn]
|
3063
3028
|
else:
|
3064
|
-
|
3065
|
-
|
3066
|
-
|
3067
|
-
|
3068
|
-
parent="",
|
3069
|
-
)
|
3029
|
+
tree[iid] = Node(
|
3030
|
+
text=row[text_column] if isinstance(text_column, int) else text_column[rn],
|
3031
|
+
iid=iid,
|
3032
|
+
parent="",
|
3070
3033
|
)
|
3071
|
-
self.rns[iid] = len(index) - 1
|
3072
3034
|
data_rns[iid] = rn
|
3073
3035
|
if pid:
|
3074
|
-
if pid in
|
3075
|
-
|
3036
|
+
if pid in tree:
|
3037
|
+
tree[pid].children.append(iid)
|
3076
3038
|
else:
|
3077
|
-
|
3078
|
-
|
3079
|
-
|
3080
|
-
|
3081
|
-
children=[iid],
|
3082
|
-
)
|
3039
|
+
tree[pid] = Node(
|
3040
|
+
text=pid,
|
3041
|
+
iid=pid,
|
3042
|
+
children=[iid],
|
3083
3043
|
)
|
3084
|
-
|
3085
|
-
index[self.rns[iid]].parent = pid
|
3044
|
+
tree[iid].parent = pid
|
3086
3045
|
else:
|
3087
|
-
|
3046
|
+
tree[iid].parent = ""
|
3088
3047
|
exclude = set()
|
3089
3048
|
if not include_iid_column:
|
3090
3049
|
exclude.add(iid_column)
|
@@ -3093,18 +3052,35 @@ class RowIndex(tk.Canvas):
|
|
3093
3052
|
if isinstance(text_column, int) and not include_text_column:
|
3094
3053
|
exclude.add(text_column)
|
3095
3054
|
rows = []
|
3055
|
+
ctr = 0
|
3096
3056
|
if exclude:
|
3097
|
-
for iid in
|
3098
|
-
|
3099
|
-
|
3100
|
-
|
3057
|
+
for iid, node in tree.items():
|
3058
|
+
if node.parent == "":
|
3059
|
+
row = [tree[iid]]
|
3060
|
+
row.extend(e for i, e in enumerate(data[data_rns[iid]]) if i not in exclude)
|
3061
|
+
rows.append(row)
|
3062
|
+
self.rns[iid] = ctr
|
3063
|
+
ctr += 1
|
3064
|
+
for diid in self._build_get_descendants(iid, tree):
|
3065
|
+
row = [tree[diid]]
|
3066
|
+
row.extend(e for i, e in enumerate(data[data_rns[diid]]) if i not in exclude)
|
3067
|
+
rows.append(row)
|
3068
|
+
self.rns[diid] = ctr
|
3069
|
+
ctr += 1
|
3101
3070
|
else:
|
3102
|
-
for iid in
|
3103
|
-
|
3104
|
-
|
3105
|
-
|
3106
|
-
|
3107
|
-
|
3071
|
+
for iid, node in tree.items():
|
3072
|
+
if node.parent == "":
|
3073
|
+
row = [tree[iid]]
|
3074
|
+
row.extend(data[data_rns[iid]])
|
3075
|
+
rows.append(row)
|
3076
|
+
self.rns[iid] = ctr
|
3077
|
+
ctr += 1
|
3078
|
+
for diid in self._build_get_descendants(iid, tree):
|
3079
|
+
row = [tree[diid]]
|
3080
|
+
row.extend(data[data_rns[diid]])
|
3081
|
+
rows.append(row)
|
3082
|
+
self.rns[diid] = ctr
|
3083
|
+
ctr += 1
|
3108
3084
|
self.PAR.insert_rows(
|
3109
3085
|
rows=rows,
|
3110
3086
|
idx=0,
|
@@ -3119,7 +3095,6 @@ class RowIndex(tk.Canvas):
|
|
3119
3095
|
)
|
3120
3096
|
self.MT.all_rows_displayed = False
|
3121
3097
|
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
3098
|
if open_ids:
|
3124
3099
|
self.PAR.tree_set_open(open_ids=open_ids)
|
3125
3100
|
else:
|
@@ -3146,8 +3121,8 @@ class RowIndex(tk.Canvas):
|
|
3146
3121
|
include_parent_column: bool = True,
|
3147
3122
|
include_text_column: bool = True,
|
3148
3123
|
) -> None:
|
3149
|
-
index = self.MT._row_index
|
3150
3124
|
data_rns = {}
|
3125
|
+
tree = {}
|
3151
3126
|
iids_missing_rows = set()
|
3152
3127
|
if text_column is None:
|
3153
3128
|
text_column = iid_column
|
@@ -3174,43 +3149,36 @@ class RowIndex(tk.Canvas):
|
|
3174
3149
|
x += 1
|
3175
3150
|
tally_of_ids[iid] += 1
|
3176
3151
|
row[iid_column] = new
|
3177
|
-
if iid in
|
3178
|
-
|
3152
|
+
if iid in tree:
|
3153
|
+
tree[iid].text = row[text_column] if isinstance(text_column, int) else text_column[rn]
|
3179
3154
|
else:
|
3180
|
-
|
3181
|
-
|
3182
|
-
|
3183
|
-
|
3184
|
-
parent="",
|
3185
|
-
)
|
3155
|
+
tree[iid] = Node(
|
3156
|
+
text=row[text_column] if isinstance(text_column, int) else text_column[rn],
|
3157
|
+
iid=iid,
|
3158
|
+
parent="",
|
3186
3159
|
)
|
3187
|
-
self.rns[iid] = len(index) - 1
|
3188
3160
|
if iid in iids_missing_rows:
|
3189
3161
|
iids_missing_rows.discard(iid)
|
3190
3162
|
data_rns[iid] = rn
|
3191
|
-
if iid == pid or self.build_pid_causes_recursive_loop(iid, pid):
|
3163
|
+
if iid == pid or self.build_pid_causes_recursive_loop(iid, pid, tree):
|
3192
3164
|
row[parent_column] = ""
|
3193
3165
|
pid = ""
|
3194
3166
|
if pid:
|
3195
|
-
if pid in
|
3196
|
-
|
3167
|
+
if pid in tree:
|
3168
|
+
tree[pid].children.append(iid)
|
3197
3169
|
else:
|
3198
|
-
|
3199
|
-
|
3200
|
-
|
3201
|
-
|
3202
|
-
children=[iid],
|
3203
|
-
)
|
3170
|
+
tree[pid] = Node(
|
3171
|
+
text=pid,
|
3172
|
+
iid=pid,
|
3173
|
+
children=[iid],
|
3204
3174
|
)
|
3205
3175
|
iids_missing_rows.add(pid)
|
3206
|
-
|
3207
|
-
index[self.rns[iid]].parent = pid
|
3176
|
+
tree[iid].parent = pid
|
3208
3177
|
else:
|
3209
|
-
|
3178
|
+
tree[iid].parent = ""
|
3210
3179
|
empty_rows = {}
|
3211
3180
|
for iid in iids_missing_rows:
|
3212
|
-
node =
|
3213
|
-
node.parent = ""
|
3181
|
+
node = tree[iid]
|
3214
3182
|
newrow = self.MT.get_empty_row_seq(len(data), ncols)
|
3215
3183
|
newrow[iid_column] = node.iid
|
3216
3184
|
empty_rows[node.iid] = newrow
|
@@ -3222,24 +3190,41 @@ class RowIndex(tk.Canvas):
|
|
3222
3190
|
if isinstance(text_column, int) and not include_text_column:
|
3223
3191
|
exclude.add(text_column)
|
3224
3192
|
rows = []
|
3193
|
+
ctr = 0
|
3225
3194
|
if exclude:
|
3226
|
-
for iid in
|
3227
|
-
|
3228
|
-
|
3229
|
-
|
3230
|
-
|
3231
|
-
|
3232
|
-
|
3195
|
+
for iid, node in tree.items():
|
3196
|
+
if node.parent == "":
|
3197
|
+
row = [tree[iid]]
|
3198
|
+
if iid in empty_rows:
|
3199
|
+
row.extend(e for i, e in enumerate(empty_rows[iid]) if i not in exclude)
|
3200
|
+
else:
|
3201
|
+
row.extend(e for i, e in enumerate(data[data_rns[iid]]) if i not in exclude)
|
3202
|
+
rows.append(row)
|
3203
|
+
self.rns[iid] = ctr
|
3204
|
+
ctr += 1
|
3205
|
+
for diid in self._build_get_descendants(iid, tree):
|
3206
|
+
row = [tree[diid]]
|
3207
|
+
row.extend(e for i, e in enumerate(data[data_rns[diid]]) if i not in exclude)
|
3208
|
+
rows.append(row)
|
3209
|
+
self.rns[diid] = ctr
|
3210
|
+
ctr += 1
|
3233
3211
|
else:
|
3234
|
-
for iid in
|
3235
|
-
|
3236
|
-
|
3237
|
-
|
3238
|
-
|
3239
|
-
|
3240
|
-
|
3241
|
-
|
3242
|
-
|
3212
|
+
for iid, node in tree.items():
|
3213
|
+
if node.parent == "":
|
3214
|
+
row = [tree[iid]]
|
3215
|
+
if iid in empty_rows:
|
3216
|
+
row.extend(empty_rows[iid])
|
3217
|
+
else:
|
3218
|
+
row.extend(data[data_rns[iid]])
|
3219
|
+
rows.append(row)
|
3220
|
+
self.rns[iid] = ctr
|
3221
|
+
ctr += 1
|
3222
|
+
for diid in self._build_get_descendants(iid, tree):
|
3223
|
+
row = [tree[diid]]
|
3224
|
+
row.extend(data[data_rns[diid]])
|
3225
|
+
rows.append(row)
|
3226
|
+
self.rns[diid] = ctr
|
3227
|
+
ctr += 1
|
3243
3228
|
self.PAR.insert_rows(
|
3244
3229
|
rows=rows,
|
3245
3230
|
idx=0,
|
@@ -3254,7 +3239,6 @@ class RowIndex(tk.Canvas):
|
|
3254
3239
|
)
|
3255
3240
|
self.MT.all_rows_displayed = False
|
3256
3241
|
self.MT.displayed_rows = list(range(len(self.MT._row_index)))
|
3257
|
-
self.rns = {n.iid: i for i, n in enumerate(self.MT._row_index)}
|
3258
3242
|
if open_ids:
|
3259
3243
|
self.PAR.tree_set_open(open_ids=open_ids)
|
3260
3244
|
else:
|
@@ -3265,3 +3249,29 @@ class RowIndex(tk.Canvas):
|
|
3265
3249
|
data_indexes=True,
|
3266
3250
|
row_heights=row_heights is not False,
|
3267
3251
|
)
|
3252
|
+
|
3253
|
+
def _build_get_descendants(self, iid: str, tree: dict[str, Node]) -> Generator[str]:
|
3254
|
+
stack = [iter(tree[iid].children)]
|
3255
|
+
while stack:
|
3256
|
+
top_iterator = stack[-1]
|
3257
|
+
try:
|
3258
|
+
ciid = next(top_iterator)
|
3259
|
+
yield ciid
|
3260
|
+
if tree[ciid].children:
|
3261
|
+
stack.append(iter(tree[ciid].children))
|
3262
|
+
except StopIteration:
|
3263
|
+
stack.pop()
|
3264
|
+
|
3265
|
+
def build_pid_causes_recursive_loop(self, iid: str, pid: str, tree: dict[str, Node]) -> bool:
|
3266
|
+
# check descendants
|
3267
|
+
for diid in self._build_get_descendants(iid, tree):
|
3268
|
+
if diid == pid:
|
3269
|
+
return True
|
3270
|
+
# check ancestors
|
3271
|
+
current_iid = iid
|
3272
|
+
while tree[current_iid].parent:
|
3273
|
+
parent_iid = tree[current_iid].parent
|
3274
|
+
if parent_iid == pid:
|
3275
|
+
return True
|
3276
|
+
current_iid = parent_iid
|
3277
|
+
return False
|