tksheet 7.2.17__py3-none-any.whl → 7.2.19__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 +2 -3
- tksheet/formatters.py +4 -3
- tksheet/functions.py +21 -10
- tksheet/main_table.py +125 -27
- tksheet/other_classes.py +41 -42
- tksheet/row_index.py +11 -6
- tksheet/sheet.py +293 -107
- tksheet/sheet_options.py +12 -0
- tksheet/themes.py +2 -2
- {tksheet-7.2.17.dist-info → tksheet-7.2.19.dist-info}/METADATA +1 -1
- tksheet-7.2.19.dist-info/RECORD +20 -0
- {tksheet-7.2.17.dist-info → tksheet-7.2.19.dist-info}/WHEEL +1 -1
- tksheet-7.2.17.dist-info/RECORD +0 -20
- {tksheet-7.2.17.dist-info → tksheet-7.2.19.dist-info}/LICENSE.txt +0 -0
- {tksheet-7.2.17.dist-info → tksheet-7.2.19.dist-info}/top_level.txt +0 -0
tksheet/sheet.py
CHANGED
@@ -19,6 +19,7 @@ from itertools import (
|
|
19
19
|
product,
|
20
20
|
repeat,
|
21
21
|
)
|
22
|
+
from operator import attrgetter
|
22
23
|
from timeit import default_timer
|
23
24
|
from tkinter import ttk
|
24
25
|
from typing import Literal
|
@@ -27,6 +28,7 @@ from .column_headers import ColumnHeaders
|
|
27
28
|
from .functions import (
|
28
29
|
add_highlight,
|
29
30
|
add_to_options,
|
31
|
+
alpha2idx,
|
30
32
|
consecutive_ranges,
|
31
33
|
convert_align,
|
32
34
|
data_to_displayed_idxs,
|
@@ -110,8 +112,8 @@ class Sheet(tk.Frame):
|
|
110
112
|
header: None | list[object] = None,
|
111
113
|
row_index: None | list[object] = None,
|
112
114
|
index: None | list[object] = None,
|
113
|
-
default_header: Literal["letters", "numbers", "both"] = "letters",
|
114
|
-
default_row_index: Literal["letters", "numbers", "both"] = "numbers",
|
115
|
+
default_header: Literal["letters", "numbers", "both"] | None = "letters",
|
116
|
+
default_row_index: Literal["letters", "numbers", "both"] | None = "numbers",
|
115
117
|
data_reference: None | Sequence[Sequence[object]] = None,
|
116
118
|
data: None | Sequence[Sequence[object]] = None,
|
117
119
|
# either (start row, end row, "rows"), (start column, end column, "rows") or
|
@@ -2906,10 +2908,16 @@ class Sheet(tk.Frame):
|
|
2906
2908
|
set_readonly(self.MT.cell_options, (r, c), readonly)
|
2907
2909
|
elif span.kind == "row":
|
2908
2910
|
for r in rows:
|
2909
|
-
|
2911
|
+
if index:
|
2912
|
+
set_readonly(self.RI.cell_options, r, readonly)
|
2913
|
+
if table:
|
2914
|
+
set_readonly(self.MT.row_options, r, readonly)
|
2910
2915
|
elif span.kind == "column":
|
2911
2916
|
for c in cols:
|
2912
|
-
|
2917
|
+
if header:
|
2918
|
+
set_readonly(self.CH.cell_options, c, readonly)
|
2919
|
+
if table:
|
2920
|
+
set_readonly(self.MT.col_options, c, readonly)
|
2913
2921
|
return span
|
2914
2922
|
|
2915
2923
|
# Text Font and Alignment
|
@@ -4151,6 +4159,7 @@ class Sheet(tk.Frame):
|
|
4151
4159
|
canvas: Literal[
|
4152
4160
|
"all",
|
4153
4161
|
"row_index",
|
4162
|
+
"index",
|
4154
4163
|
"header",
|
4155
4164
|
"top_left",
|
4156
4165
|
"x_scrollbar",
|
@@ -4173,7 +4182,7 @@ class Sheet(tk.Frame):
|
|
4173
4182
|
self.yscroll_showing = True
|
4174
4183
|
self.xscroll_disabled = False
|
4175
4184
|
self.yscroll_disabled = False
|
4176
|
-
elif canvas
|
4185
|
+
elif canvas in ("row_index", "index"):
|
4177
4186
|
self.RI.grid(row=1, column=0, sticky="nswe")
|
4178
4187
|
self.MT["yscrollcommand"] = self.yscroll.set
|
4179
4188
|
self.RI["yscrollcommand"] = self.yscroll.set
|
@@ -4422,14 +4431,107 @@ class Sheet(tk.Frame):
|
|
4422
4431
|
and event.widget == self.TL
|
4423
4432
|
)
|
4424
4433
|
|
4434
|
+
def props(
|
4435
|
+
self,
|
4436
|
+
row: int,
|
4437
|
+
column: int | str,
|
4438
|
+
key: None
|
4439
|
+
| Literal[
|
4440
|
+
"format",
|
4441
|
+
"highlight",
|
4442
|
+
"dropdown",
|
4443
|
+
"checkbox",
|
4444
|
+
"readonly",
|
4445
|
+
"align",
|
4446
|
+
] = None,
|
4447
|
+
cellops: bool = True,
|
4448
|
+
rowops: bool = True,
|
4449
|
+
columnops: bool = True,
|
4450
|
+
) -> dict:
|
4451
|
+
"""
|
4452
|
+
Retrieve options (properties - props)
|
4453
|
+
from a single cell in the main table
|
4454
|
+
|
4455
|
+
Also retrieves any row or column options
|
4456
|
+
impacting that cell
|
4457
|
+
"""
|
4458
|
+
if isinstance(column, str):
|
4459
|
+
column = alpha2idx(column)
|
4460
|
+
if key is not None:
|
4461
|
+
return self.MT.get_cell_kwargs(
|
4462
|
+
datarn=row,
|
4463
|
+
datacn=column,
|
4464
|
+
key=key,
|
4465
|
+
cell=cellops,
|
4466
|
+
row=rowops,
|
4467
|
+
column=columnops,
|
4468
|
+
)
|
4469
|
+
if cellops and (row, column) in self.MT.cell_options:
|
4470
|
+
return self.MT.cell_options[(row, column)]
|
4471
|
+
if rowops and row in self.MT.row_options:
|
4472
|
+
return self.MT.row_options[row]
|
4473
|
+
if columnops and column in self.MT.col_options:
|
4474
|
+
return self.MT.col_options[column]
|
4475
|
+
return {}
|
4476
|
+
|
4477
|
+
def index_props(
|
4478
|
+
self,
|
4479
|
+
row: int,
|
4480
|
+
key: None
|
4481
|
+
| Literal[
|
4482
|
+
"format",
|
4483
|
+
"highlight",
|
4484
|
+
"dropdown",
|
4485
|
+
"checkbox",
|
4486
|
+
"readonly",
|
4487
|
+
"align",
|
4488
|
+
] = None,
|
4489
|
+
) -> dict:
|
4490
|
+
"""
|
4491
|
+
Retrieve options (properties - props)
|
4492
|
+
from a cell in the index
|
4493
|
+
"""
|
4494
|
+
if key is not None:
|
4495
|
+
return self.RI.get_cell_kwargs(
|
4496
|
+
datarn=row,
|
4497
|
+
key=key,
|
4498
|
+
)
|
4499
|
+
return self.RI.cell_options[row] if row in self.RI.cell_options else {}
|
4500
|
+
|
4501
|
+
def header_props(
|
4502
|
+
self,
|
4503
|
+
column: int | str,
|
4504
|
+
key: None
|
4505
|
+
| Literal[
|
4506
|
+
"format",
|
4507
|
+
"highlight",
|
4508
|
+
"dropdown",
|
4509
|
+
"checkbox",
|
4510
|
+
"readonly",
|
4511
|
+
"align",
|
4512
|
+
] = None,
|
4513
|
+
) -> dict:
|
4514
|
+
"""
|
4515
|
+
Retrieve options (properties - props)
|
4516
|
+
from a cell in the header
|
4517
|
+
"""
|
4518
|
+
if isinstance(column, str):
|
4519
|
+
column = alpha2idx(column)
|
4520
|
+
if key is not None:
|
4521
|
+
return self.CH.get_cell_kwargs(
|
4522
|
+
datacn=column,
|
4523
|
+
key=key,
|
4524
|
+
)
|
4525
|
+
return self.CH.cell_options[column] if column in self.CH.cell_options else {}
|
4526
|
+
|
4425
4527
|
def get_cell_options(
|
4426
4528
|
self,
|
4427
4529
|
key: None | str = None,
|
4428
|
-
canvas: Literal["table", "row_index", "header"] = "table",
|
4530
|
+
canvas: Literal["table", "row_index", "index", "header"] = "table",
|
4429
4531
|
) -> dict:
|
4430
4532
|
if canvas == "table":
|
4431
4533
|
target = self.MT.cell_options
|
4432
|
-
elif canvas
|
4534
|
+
elif canvas in ("row_index", "index"):
|
4433
4535
|
target = self.RI.cell_options
|
4434
4536
|
elif canvas == "header":
|
4435
4537
|
target = self.CH.cell_options
|
@@ -4715,8 +4817,10 @@ class Sheet(tk.Frame):
|
|
4715
4817
|
open_ids: Iterator[str] | None = None,
|
4716
4818
|
safety: bool = True,
|
4717
4819
|
ncols: int | None = None,
|
4820
|
+
lower: bool = False,
|
4718
4821
|
include_iid_column: bool = True,
|
4719
4822
|
include_parent_column: bool = True,
|
4823
|
+
include_text_column: bool = True,
|
4720
4824
|
) -> Sheet:
|
4721
4825
|
self.reset(cell_options=False, column_widths=False, header=False, redraw=False)
|
4722
4826
|
if text_column is None:
|
@@ -4727,7 +4831,12 @@ class Sheet(tk.Frame):
|
|
4727
4831
|
for rn, row in enumerate(data):
|
4728
4832
|
if safety and ncols > (lnr := len(row)):
|
4729
4833
|
row += self.MT.get_empty_row_seq(rn, end=ncols, start=lnr)
|
4730
|
-
|
4834
|
+
if lower:
|
4835
|
+
iid = row[iid_column].lower()
|
4836
|
+
pid = row[parent_column].lower()
|
4837
|
+
else:
|
4838
|
+
iid = row[iid_column]
|
4839
|
+
pid = row[parent_column]
|
4731
4840
|
if safety:
|
4732
4841
|
if not iid:
|
4733
4842
|
continue
|
@@ -4736,7 +4845,7 @@ class Sheet(tk.Frame):
|
|
4736
4845
|
x = 1
|
4737
4846
|
while iid in tally_of_ids:
|
4738
4847
|
new = f"{row[iid_column]}_DUPLICATED_{x}"
|
4739
|
-
iid = new.lower()
|
4848
|
+
iid = new.lower() if lower else new
|
4740
4849
|
x += 1
|
4741
4850
|
tally_of_ids[iid] += 1
|
4742
4851
|
row[iid_column] = new
|
@@ -4755,14 +4864,14 @@ class Sheet(tk.Frame):
|
|
4755
4864
|
else:
|
4756
4865
|
self.RI.tree[iid].parent = ""
|
4757
4866
|
self.RI.tree_rns[iid] = rn
|
4758
|
-
|
4759
|
-
|
4760
|
-
n.parent
|
4761
|
-
|
4762
|
-
|
4763
|
-
|
4764
|
-
|
4765
|
-
|
4867
|
+
if safety:
|
4868
|
+
for n in self.RI.tree.values():
|
4869
|
+
if n.parent is None:
|
4870
|
+
n.parent = ""
|
4871
|
+
newrow = self.MT.get_empty_row_seq(len(data), ncols)
|
4872
|
+
newrow[iid_column] = n.iid
|
4873
|
+
self.RI.tree_rns[n.iid] = len(data)
|
4874
|
+
data.append(newrow)
|
4766
4875
|
insert_rows = partial(
|
4767
4876
|
self.insert_rows,
|
4768
4877
|
idx=0,
|
@@ -4773,37 +4882,22 @@ class Sheet(tk.Frame):
|
|
4773
4882
|
push_ops=push_ops,
|
4774
4883
|
redraw=False,
|
4775
4884
|
)
|
4776
|
-
|
4777
|
-
if include_iid_column
|
4778
|
-
|
4779
|
-
|
4780
|
-
|
4781
|
-
|
4782
|
-
|
4783
|
-
|
4784
|
-
[self.RI.tree[iid]] + [e for i, e in enumerate(data[self.RI.tree_rns[iid]]) if i not in exclude]
|
4785
|
-
for iid in self.get_children()
|
4786
|
-
]
|
4787
|
-
)
|
4788
|
-
|
4789
|
-
elif include_parent_column and not include_iid_column:
|
4790
|
-
exclude = {iid_column}
|
4885
|
+
exclude = set()
|
4886
|
+
if not include_iid_column:
|
4887
|
+
exclude.add(iid_column)
|
4888
|
+
if not include_parent_column:
|
4889
|
+
exclude.add(parent_column)
|
4890
|
+
if isinstance(text_column, int) and not include_text_column:
|
4891
|
+
exclude.add(text_column)
|
4892
|
+
if exclude:
|
4791
4893
|
insert_rows(
|
4792
4894
|
rows=[
|
4793
4895
|
[self.RI.tree[iid]] + [e for i, e in enumerate(data[self.RI.tree_rns[iid]]) if i not in exclude]
|
4794
|
-
for iid in self.
|
4896
|
+
for iid in self.get_nodes()
|
4795
4897
|
]
|
4796
4898
|
)
|
4797
|
-
|
4798
|
-
|
4799
|
-
exclude = {iid_column, parent_column}
|
4800
|
-
insert_rows(
|
4801
|
-
rows=[
|
4802
|
-
[self.RI.tree[iid]] + [e for i, e in enumerate(data[self.RI.tree_rns[iid]]) if i not in exclude]
|
4803
|
-
for iid in self.get_children()
|
4804
|
-
]
|
4805
|
-
)
|
4806
|
-
|
4899
|
+
else:
|
4900
|
+
insert_rows(rows=[[self.RI.tree[iid]] + data[self.RI.tree_rns[iid]] for iid in self.get_nodes()])
|
4807
4901
|
self.MT.all_rows_displayed = False
|
4808
4902
|
self.MT.displayed_rows = list(range(len(self.MT._row_index)))
|
4809
4903
|
self.RI.tree_rns = {n.iid: i for i, n in enumerate(self.MT._row_index)}
|
@@ -4840,7 +4934,7 @@ class Sheet(tk.Frame):
|
|
4840
4934
|
deselect_all=False,
|
4841
4935
|
data_indexes=True,
|
4842
4936
|
)
|
4843
|
-
open_ids = set(filter(self.exists,
|
4937
|
+
open_ids = set(filter(self.exists, open_ids))
|
4844
4938
|
self.RI.tree_open_ids = set()
|
4845
4939
|
if open_ids:
|
4846
4940
|
self.show_rows(
|
@@ -4924,58 +5018,129 @@ class Sheet(tk.Frame):
|
|
4924
5018
|
values: None | list[object] = None,
|
4925
5019
|
create_selections: bool = False,
|
4926
5020
|
) -> str:
|
4927
|
-
|
5021
|
+
"""
|
5022
|
+
Insert an item into the treeview
|
5023
|
+
"""
|
5024
|
+
if not iid:
|
4928
5025
|
i = 0
|
4929
5026
|
while (iid := f"{num2alpha(i)}") in self.RI.tree:
|
4930
5027
|
i += 1
|
4931
|
-
iid, pid = iid.lower(), parent.lower()
|
4932
|
-
if not iid:
|
4933
|
-
raise ValueError("iid cannot be empty string.")
|
4934
5028
|
if iid in self.RI.tree:
|
4935
5029
|
raise ValueError(f"iid '{iid}' already exists.")
|
4936
|
-
if iid ==
|
4937
|
-
raise ValueError(f"iid '{iid}' cannot be equal to parent '{
|
4938
|
-
if
|
5030
|
+
if iid == parent:
|
5031
|
+
raise ValueError(f"iid '{iid}' cannot be equal to parent '{parent}'.")
|
5032
|
+
if parent and parent not in self.RI.tree:
|
4939
5033
|
raise ValueError(f"parent '{parent}' does not exist.")
|
4940
5034
|
if text is None:
|
4941
5035
|
text = iid
|
4942
|
-
parent_node = self.RI.tree[
|
5036
|
+
parent_node = self.RI.tree[parent] if parent else ""
|
4943
5037
|
self.RI.tree[iid] = Node(text, iid, parent_node)
|
4944
5038
|
if parent_node:
|
4945
5039
|
if isinstance(index, int):
|
4946
|
-
|
4947
|
-
|
4948
|
-
|
4949
|
-
|
4950
|
-
|
4951
|
-
self.RI.tree[pid].children.insert(index, self.RI.tree[iid])
|
5040
|
+
datarn = self.RI.tree_rns[parent] + index + 1
|
5041
|
+
datarn += sum(
|
5042
|
+
sum(1 for _ in self.RI.get_iid_descendants(cid)) for cid in islice(self.get_children(parent), index)
|
5043
|
+
)
|
5044
|
+
self.RI.tree[parent].children.insert(index, self.RI.tree[iid])
|
4952
5045
|
else:
|
4953
|
-
|
4954
|
-
self.RI.tree[
|
5046
|
+
datarn = self.RI.tree_rns[parent] + sum(1 for _ in self.RI.get_iid_descendants(parent)) + 1
|
5047
|
+
self.RI.tree[parent].children.append(self.RI.tree[iid])
|
4955
5048
|
else:
|
4956
5049
|
if isinstance(index, int):
|
4957
|
-
|
4958
|
-
if index:
|
4959
|
-
|
4960
|
-
if count >= index:
|
4961
|
-
break
|
4962
|
-
idx += sum(1 for _ in self.RI.get_iid_descendants(cid)) + 1
|
5050
|
+
datarn = index
|
5051
|
+
if index and (datarn := self.top_index_row(datarn)) is None:
|
5052
|
+
datarn = len(self.MT._row_index)
|
4963
5053
|
else:
|
4964
|
-
|
5054
|
+
datarn = len(self.MT._row_index)
|
4965
5055
|
if values is None:
|
4966
5056
|
values = []
|
4967
5057
|
self.insert_rows(
|
4968
|
-
idx=idx,
|
4969
5058
|
rows=[[self.RI.tree[iid]] + values],
|
5059
|
+
idx=datarn,
|
4970
5060
|
row_index=True,
|
4971
5061
|
create_selections=create_selections,
|
4972
5062
|
fill=False,
|
4973
5063
|
)
|
4974
|
-
self.RI.tree_rns[iid] =
|
4975
|
-
if
|
4976
|
-
self.hide_rows(
|
5064
|
+
self.RI.tree_rns[iid] = datarn
|
5065
|
+
if parent and (parent not in self.RI.tree_open_ids or not self.item_displayed(parent)):
|
5066
|
+
self.hide_rows(datarn, deselect_all=False, data_indexes=True)
|
4977
5067
|
return iid
|
4978
5068
|
|
5069
|
+
def bulk_insert(
|
5070
|
+
self,
|
5071
|
+
data: list[list[object]],
|
5072
|
+
parent: str = "",
|
5073
|
+
index: None | int | Literal["end"] = None,
|
5074
|
+
iid_column: int | None = None,
|
5075
|
+
text_column: int | None | str = None,
|
5076
|
+
create_selections: bool = False,
|
5077
|
+
include_iid_column: bool = True,
|
5078
|
+
include_text_column: bool = True,
|
5079
|
+
) -> dict[str, int]:
|
5080
|
+
"""
|
5081
|
+
Insert multiple items into the treeview at once, under the same parent
|
5082
|
+
"""
|
5083
|
+
to_insert = []
|
5084
|
+
pid = parent
|
5085
|
+
if pid and pid not in self.RI.tree:
|
5086
|
+
raise ValueError(f"parent '{parent}' does not exist.")
|
5087
|
+
parent_node = self.RI.tree[pid] if parent else ""
|
5088
|
+
if parent_node:
|
5089
|
+
if isinstance(index, int):
|
5090
|
+
datarn = self.RI.tree_rns[pid] + index + 1
|
5091
|
+
datarn += sum(
|
5092
|
+
sum(1 for _ in self.RI.get_iid_descendants(cid)) for cid in islice(self.get_children(pid), index)
|
5093
|
+
)
|
5094
|
+
else:
|
5095
|
+
datarn = self.RI.tree_rns[pid] + sum(1 for _ in self.RI.get_iid_descendants(pid)) + 1
|
5096
|
+
else:
|
5097
|
+
if isinstance(index, int):
|
5098
|
+
datarn = index
|
5099
|
+
if index and (datarn := self.top_index_row(datarn)) is None:
|
5100
|
+
datarn = len(self.MT._row_index)
|
5101
|
+
else:
|
5102
|
+
datarn = len(self.MT._row_index)
|
5103
|
+
i = 0
|
5104
|
+
rns_to_add = {}
|
5105
|
+
for rn, r in enumerate(data, start=datarn):
|
5106
|
+
if iid_column is None:
|
5107
|
+
while (iid := f"{num2alpha(i)}") in self.RI.tree:
|
5108
|
+
i += 1
|
5109
|
+
else:
|
5110
|
+
iid = r[iid_column]
|
5111
|
+
self.RI.tree[iid] = Node(
|
5112
|
+
r[text_column] if isinstance(text_column, int) else text_column if isinstance(text_column, str) else "",
|
5113
|
+
iid,
|
5114
|
+
parent_node,
|
5115
|
+
)
|
5116
|
+
if parent_node:
|
5117
|
+
if isinstance(index, int):
|
5118
|
+
self.RI.tree[pid].children.insert(index, self.RI.tree[iid])
|
5119
|
+
else:
|
5120
|
+
self.RI.tree[pid].children.append(self.RI.tree[iid])
|
5121
|
+
exclude = set()
|
5122
|
+
if isinstance(iid_column, int) and not include_iid_column:
|
5123
|
+
exclude.add(iid_column)
|
5124
|
+
if isinstance(text_column, int) and not include_text_column:
|
5125
|
+
exclude.add(text_column)
|
5126
|
+
if exclude:
|
5127
|
+
to_insert.append([self.RI.tree[iid]] + [e for c, e in enumerate(r) if c not in exclude])
|
5128
|
+
else:
|
5129
|
+
to_insert.append([self.RI.tree[iid]] + r)
|
5130
|
+
rns_to_add[iid] = rn
|
5131
|
+
self.insert_rows(
|
5132
|
+
rows=to_insert,
|
5133
|
+
idx=datarn,
|
5134
|
+
row_index=True,
|
5135
|
+
create_selections=create_selections,
|
5136
|
+
fill=False,
|
5137
|
+
)
|
5138
|
+
for iid, rn in rns_to_add.items():
|
5139
|
+
self.RI.tree_rns[iid] = rn
|
5140
|
+
if pid and (pid not in self.RI.tree_open_ids or not self.item_displayed(pid)):
|
5141
|
+
self.hide_rows(range(datarn, datarn + len(to_insert)), deselect_all=False, data_indexes=True)
|
5142
|
+
return rns_to_add
|
5143
|
+
|
4979
5144
|
def item(
|
4980
5145
|
self,
|
4981
5146
|
item: str,
|
@@ -4990,12 +5155,11 @@ class Sheet(tk.Frame):
|
|
4990
5155
|
If no options are set then returns DotDict of options for item
|
4991
5156
|
Else returns Sheet
|
4992
5157
|
"""
|
4993
|
-
if
|
5158
|
+
if item not in self.RI.tree:
|
4994
5159
|
raise ValueError(f"Item '{item}' does not exist.")
|
4995
5160
|
if isinstance(iid, str):
|
4996
5161
|
if iid in self.RI.tree:
|
4997
5162
|
raise ValueError(f"Cannot rename '{iid}', it already exists.")
|
4998
|
-
iid = iid.lower()
|
4999
5163
|
self.RI.tree[item].iid = iid
|
5000
5164
|
self.RI.tree[iid] = self.RI.tree.pop(item)
|
5001
5165
|
self.RI.tree_rns[iid] = self.RI.tree_rns.pop(item)
|
@@ -5040,9 +5204,9 @@ class Sheet(tk.Frame):
|
|
5040
5204
|
|
5041
5205
|
def itemrow(self, item: str) -> int:
|
5042
5206
|
try:
|
5043
|
-
return self.RI.tree_rns[item
|
5207
|
+
return self.RI.tree_rns[item]
|
5044
5208
|
except Exception:
|
5045
|
-
raise ValueError(f"item '{item
|
5209
|
+
raise ValueError(f"item '{item}' does not exist.")
|
5046
5210
|
|
5047
5211
|
def rowitem(self, row: int, data_index: bool = False) -> str | None:
|
5048
5212
|
try:
|
@@ -5053,12 +5217,21 @@ class Sheet(tk.Frame):
|
|
5053
5217
|
return None
|
5054
5218
|
|
5055
5219
|
def get_children(self, item: None | str = None) -> Generator[str]:
|
5220
|
+
if item is None:
|
5221
|
+
for iid in self.get_children(""):
|
5222
|
+
yield iid
|
5223
|
+
yield from self.RI.get_iid_descendants(iid)
|
5224
|
+
elif item == "":
|
5225
|
+
yield from map(attrgetter("iid"), self.RI.gen_top_nodes())
|
5226
|
+
else:
|
5227
|
+
yield from (n.iid for n in self.RI.tree[item].children)
|
5228
|
+
|
5229
|
+
def get_nodes(self, item: None | str = None) -> Generator[str]:
|
5056
5230
|
if item is None:
|
5057
5231
|
for n in self.RI.tree.values():
|
5058
5232
|
if not n.parent:
|
5059
5233
|
yield n.iid
|
5060
|
-
|
5061
|
-
yield iid
|
5234
|
+
yield from self.RI.get_iid_descendants(n.iid)
|
5062
5235
|
elif item == "":
|
5063
5236
|
yield from (n.iid for n in self.RI.tree.values() if not n.parent)
|
5064
5237
|
else:
|
@@ -5071,7 +5244,6 @@ class Sheet(tk.Frame):
|
|
5071
5244
|
rows_to_del = []
|
5072
5245
|
iids_to_del = []
|
5073
5246
|
for item in unpack(items):
|
5074
|
-
item = item.lower()
|
5075
5247
|
if item not in self.RI.tree:
|
5076
5248
|
continue
|
5077
5249
|
rows_to_del.append(self.RI.tree_rns[item])
|
@@ -5109,9 +5281,9 @@ class Sheet(tk.Frame):
|
|
5109
5281
|
'parent' can be an empty str which will put the item at top level
|
5110
5282
|
Performance is not great
|
5111
5283
|
"""
|
5112
|
-
if
|
5284
|
+
if item not in self.RI.tree:
|
5113
5285
|
raise ValueError(f"Item '{item}' does not exist.")
|
5114
|
-
if
|
5286
|
+
if parent and parent not in self.RI.tree:
|
5115
5287
|
raise ValueError(f"Parent '{parent}' does not exist.")
|
5116
5288
|
mapping = {}
|
5117
5289
|
to_show = []
|
@@ -5188,11 +5360,8 @@ class Sheet(tk.Frame):
|
|
5188
5360
|
item_node.parent = parent_node
|
5189
5361
|
parent_node.children.insert(index, item_node)
|
5190
5362
|
else:
|
5191
|
-
if index is None:
|
5192
|
-
new_r = self.top_index_row(
|
5193
|
-
else:
|
5194
|
-
if (new_r := self.top_index_row(index)) is None:
|
5195
|
-
new_r = self.top_index_row((sum(1 for _ in self.RI.gen_top_nodes()) - 1))
|
5363
|
+
if index is None or (new_r := self.top_index_row(index)) is None:
|
5364
|
+
new_r = self.top_index_row(sum(1 for _ in self.RI.gen_top_nodes()) - 1)
|
5196
5365
|
if item_r < new_r:
|
5197
5366
|
r_ctr = (
|
5198
5367
|
new_r
|
@@ -5225,15 +5394,15 @@ class Sheet(tk.Frame):
|
|
5225
5394
|
reattach = move
|
5226
5395
|
|
5227
5396
|
def exists(self, item: str) -> bool:
|
5228
|
-
return item
|
5397
|
+
return item in self.RI.tree
|
5229
5398
|
|
5230
5399
|
def parent(self, item: str) -> str:
|
5231
|
-
if
|
5400
|
+
if item not in self.RI.tree:
|
5232
5401
|
raise ValueError(f"Item '{item}' does not exist.")
|
5233
5402
|
return self.RI.tree[item].parent.iid if self.RI.tree[item].parent else self.RI.tree[item].parent
|
5234
5403
|
|
5235
5404
|
def index(self, item: str) -> int:
|
5236
|
-
if
|
5405
|
+
if item not in self.RI.tree:
|
5237
5406
|
raise ValueError(f"Item '{item}' does not exist.")
|
5238
5407
|
if not self.RI.tree[item].parent:
|
5239
5408
|
find_node = self.RI.tree[item]
|
@@ -5245,7 +5414,7 @@ class Sheet(tk.Frame):
|
|
5245
5414
|
Check if an item (row) is currently displayed on the sheet
|
5246
5415
|
- Does not check if the item is visible to the user
|
5247
5416
|
"""
|
5248
|
-
if
|
5417
|
+
if item not in self.RI.tree:
|
5249
5418
|
raise ValueError(f"Item '{item}' does not exist.")
|
5250
5419
|
return self.RI.tree_rns[item] in self.MT.displayed_rows
|
5251
5420
|
|
@@ -5256,7 +5425,7 @@ class Sheet(tk.Frame):
|
|
5256
5425
|
- Unlike the ttk treeview 'see' function
|
5257
5426
|
this function does **NOT** scroll to the item
|
5258
5427
|
"""
|
5259
|
-
if
|
5428
|
+
if item not in self.RI.tree:
|
5260
5429
|
raise ValueError(f"Item '{item}' does not exist.")
|
5261
5430
|
if self.RI.tree[item].parent:
|
5262
5431
|
self.show_rows(
|
@@ -5270,7 +5439,7 @@ class Sheet(tk.Frame):
|
|
5270
5439
|
"""
|
5271
5440
|
Scrolls to an item and ensures that it is displayed
|
5272
5441
|
"""
|
5273
|
-
if
|
5442
|
+
if item not in self.RI.tree:
|
5274
5443
|
raise ValueError(f"Item '{item}' does not exist.")
|
5275
5444
|
self.display_item(item, redraw=False)
|
5276
5445
|
self.see(
|
@@ -5288,19 +5457,29 @@ class Sheet(tk.Frame):
|
|
5288
5457
|
self.MT._row_index[self.MT.displayed_rows[rn]].iid for rn in self.get_selected_rows(get_cells_as_rows=cells)
|
5289
5458
|
]
|
5290
5459
|
|
5291
|
-
|
5292
|
-
|
5293
|
-
|
5294
|
-
|
5295
|
-
|
5296
|
-
|
5460
|
+
@property
|
5461
|
+
def tree_selected(self) -> str | None:
|
5462
|
+
"""
|
5463
|
+
Get the iid at the currently selected box
|
5464
|
+
"""
|
5465
|
+
if selected := self.selected:
|
5466
|
+
return self.rowitem(selected.row)
|
5467
|
+
return None
|
5468
|
+
|
5469
|
+
def selection_set(self, *items, run_binding: bool = True, redraw: bool = True) -> Sheet:
|
5470
|
+
boxes_to_hide = tuple(self.MT.selection_boxes)
|
5471
|
+
self.selection_add(*items, run_binding=False, redraw=False)
|
5472
|
+
for iid in boxes_to_hide:
|
5473
|
+
self.MT.hide_selection_box(iid)
|
5474
|
+
if run_binding:
|
5475
|
+
self.MT.run_selection_binding("rows")
|
5297
5476
|
return self.set_refresh_timer(redraw)
|
5298
5477
|
|
5299
|
-
def selection_add(self, *items, redraw: bool = True) -> Sheet:
|
5478
|
+
def selection_add(self, *items, run_binding: bool = True, redraw: bool = True) -> Sheet:
|
5300
5479
|
to_open = []
|
5301
5480
|
quick_displayed_check = set(self.MT.displayed_rows)
|
5302
5481
|
for item in unpack(items):
|
5303
|
-
if self.RI.tree_rns[
|
5482
|
+
if self.RI.tree_rns[item] not in quick_displayed_check and self.RI.tree[item].parent:
|
5304
5483
|
to_open.extend(list(self.RI.get_iid_ancestors(item)))
|
5305
5484
|
if to_open:
|
5306
5485
|
self.show_rows(
|
@@ -5312,7 +5491,7 @@ class Sheet(tk.Frame):
|
|
5312
5491
|
sorted(
|
5313
5492
|
bisect_left(
|
5314
5493
|
self.MT.displayed_rows,
|
5315
|
-
self.RI.tree_rns[item
|
5494
|
+
self.RI.tree_rns[item],
|
5316
5495
|
)
|
5317
5496
|
for item in unpack(items)
|
5318
5497
|
)
|
@@ -5326,12 +5505,13 @@ class Sheet(tk.Frame):
|
|
5326
5505
|
set_current=True,
|
5327
5506
|
ext=True,
|
5328
5507
|
)
|
5329
|
-
|
5508
|
+
if run_binding:
|
5509
|
+
self.MT.run_selection_binding("rows")
|
5330
5510
|
return self.set_refresh_timer(redraw)
|
5331
5511
|
|
5332
5512
|
def selection_remove(self, *items, redraw: bool = True) -> Sheet:
|
5333
5513
|
for item in unpack(items):
|
5334
|
-
if
|
5514
|
+
if item not in self.RI.tree:
|
5335
5515
|
continue
|
5336
5516
|
try:
|
5337
5517
|
self.deselect(bisect_left(self.MT.displayed_rows, self.RI.tree_rns[item]), redraw=False)
|
@@ -5344,7 +5524,7 @@ class Sheet(tk.Frame):
|
|
5344
5524
|
add = []
|
5345
5525
|
remove = []
|
5346
5526
|
for item in unpack(items):
|
5347
|
-
if
|
5527
|
+
if item in self.RI.tree:
|
5348
5528
|
if item in selected:
|
5349
5529
|
remove.append(item)
|
5350
5530
|
else:
|
@@ -5353,6 +5533,9 @@ class Sheet(tk.Frame):
|
|
5353
5533
|
self.selection_add(*add, redraw=False)
|
5354
5534
|
return self.set_refresh_timer(redraw)
|
5355
5535
|
|
5536
|
+
def descendants(self, item: str, check_open: bool = False) -> Generator[str]:
|
5537
|
+
return self.RI.get_iid_descendants(item, check_open=check_open)
|
5538
|
+
|
5356
5539
|
# Functions not in docs
|
5357
5540
|
|
5358
5541
|
def event_generate(self, *args, **kwargs) -> None:
|
@@ -5942,7 +6125,7 @@ class Sheet(tk.Frame):
|
|
5942
6125
|
row: int | Literal["all"] = 0,
|
5943
6126
|
column: int = 0,
|
5944
6127
|
cells: list[tuple[int, int]] = [],
|
5945
|
-
canvas: Literal["table", "row_index", "header"] = "table",
|
6128
|
+
canvas: Literal["table", "row_index", "index", "header"] = "table",
|
5946
6129
|
all_: bool = False,
|
5947
6130
|
redraw: bool = True,
|
5948
6131
|
) -> Sheet:
|
@@ -5975,7 +6158,7 @@ class Sheet(tk.Frame):
|
|
5975
6158
|
for k in self.MT.cell_options:
|
5976
6159
|
if "highlight" in self.MT.cell_options[k]:
|
5977
6160
|
del self.MT.cell_options[k]["highlight"]
|
5978
|
-
elif canvas
|
6161
|
+
elif canvas in ("row_index", "index"):
|
5979
6162
|
if cells and not all_:
|
5980
6163
|
for r in cells:
|
5981
6164
|
try:
|
@@ -6005,10 +6188,13 @@ class Sheet(tk.Frame):
|
|
6005
6188
|
del self.CH.cell_options[c]["highlight"]
|
6006
6189
|
return self.set_refresh_timer(redraw)
|
6007
6190
|
|
6008
|
-
def get_highlighted_cells(
|
6191
|
+
def get_highlighted_cells(
|
6192
|
+
self,
|
6193
|
+
canvas: Literal["table", "row_index", "index", "header"] = "table",
|
6194
|
+
) -> dict | None:
|
6009
6195
|
if canvas == "table":
|
6010
6196
|
return {k: v["highlight"] for k, v in self.MT.cell_options.items() if "highlight" in v}
|
6011
|
-
elif canvas
|
6197
|
+
elif canvas in ("row_index", "index"):
|
6012
6198
|
return {k: v["highlight"] for k, v in self.RI.cell_options.items() if "highlight" in v}
|
6013
6199
|
elif canvas == "header":
|
6014
6200
|
return {k: v["highlight"] for k, v in self.CH.cell_options.items() if "highlight" in v}
|