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/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 | None = None,
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 chain, cycle, islice, repeat
8
- from math import ceil, floor
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 = floor(self.MT.row_positions[self.rsz_h - 1] + self.ops.max_row_height)
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.endswith("w"):
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 := floor(self.PAR.winfo_width() * 0.7)) < new_w:
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 = floor(self.MT.min_row_height / 2)
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 = floor(self.MT.min_row_height / 2)
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 := self.get_cell_kwargs(datarn, key="dropdown"):
1703
- max_width = self.current_width - self.MT.index_txt_height - 2
1704
- if align.endswith("w"):
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.endswith("e"):
1680
+ elif align[-1] == "e":
1707
1681
  draw_x = self.current_width - 5 - self.MT.index_txt_height
1708
- elif align.endswith("n"):
1709
- draw_x = ceil((self.current_width - self.MT.index_txt_height) / 2)
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.endswith("w"):
1698
+ if align[-1] == "w":
1725
1699
  draw_x = 3
1726
- elif align.endswith("e"):
1700
+ elif align[-1] == "e":
1727
1701
  draw_x = self.current_width - 3
1728
- elif align.endswith("n"):
1729
- draw_x = floor(self.current_width / 2)
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.endswith("w"):
1710
+ if align[-1] == "w":
1737
1711
  draw_x += box_w + 3
1738
- elif align.endswith("n"):
1739
- draw_x += ceil(box_w / 2) + 1
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.endswith("w"):
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 (kwargs := kwargs.get("dropdown", {})) and kwargs["validate_input"] and kwargs["values"]:
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
- if new_loc_is_displayed:
2761
- if disp_insert_row is None:
2762
- if new_parent or insert_row > move_to_row:
2763
- disp_insert_row = self.MT.disprn(self.rns[move_to_iid]) + 1
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
- 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:
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 = dict(zip(data_new_idxs.values(), data_new_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 self.rns:
3062
- index[self.rns[iid]].text = row[text_column] if isinstance(text_column, int) else text_column[rn]
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
- index.append(
3065
- Node(
3066
- text=row[text_column] if isinstance(text_column, int) else text_column[rn],
3067
- iid=iid,
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 self.rns:
3075
- index[self.rns[pid]].children.append(iid)
3036
+ if pid in tree:
3037
+ tree[pid].children.append(iid)
3076
3038
  else:
3077
- index.append(
3078
- Node(
3079
- text=pid,
3080
- iid=pid,
3081
- children=[iid],
3082
- )
3039
+ tree[pid] = Node(
3040
+ text=pid,
3041
+ iid=pid,
3042
+ children=[iid],
3083
3043
  )
3084
- self.rns[pid] = len(index) - 1
3085
- index[self.rns[iid]].parent = pid
3044
+ tree[iid].parent = pid
3086
3045
  else:
3087
- index[self.rns[iid]].parent = ""
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 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)
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 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 = {}
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 self.rns:
3178
- index[self.rns[iid]].text = row[text_column] if isinstance(text_column, int) else text_column[rn]
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
- index.append(
3181
- Node(
3182
- text=row[text_column] if isinstance(text_column, int) else text_column[rn],
3183
- iid=iid,
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 self.rns:
3196
- index[self.rns[pid]].children.append(iid)
3167
+ if pid in tree:
3168
+ tree[pid].children.append(iid)
3197
3169
  else:
3198
- index.append(
3199
- Node(
3200
- text=pid,
3201
- iid=pid,
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
- self.rns[pid] = len(index) - 1
3207
- index[self.rns[iid]].parent = pid
3176
+ tree[iid].parent = pid
3208
3177
  else:
3209
- index[self.rns[iid]].parent = ""
3178
+ tree[iid].parent = ""
3210
3179
  empty_rows = {}
3211
3180
  for iid in iids_missing_rows:
3212
- node = index[self.rns[iid]]
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 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)
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 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 = {}
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