tksheet 7.3.3__py3-none-any.whl → 7.4.0__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 +11 -11
- tksheet/colors.py +1 -1
- tksheet/column_headers.py +397 -366
- tksheet/constants.py +13 -0
- tksheet/find_window.py +4 -13
- tksheet/functions.py +198 -37
- tksheet/main_table.py +1109 -848
- tksheet/other_classes.py +13 -9
- tksheet/row_index.py +939 -437
- tksheet/sheet.py +470 -619
- tksheet/sheet_options.py +47 -12
- tksheet/sorting.py +369 -0
- tksheet/text_editor.py +4 -15
- tksheet/{types.py → tksheet_types.py} +12 -8
- {tksheet-7.3.3.dist-info → tksheet-7.4.0.dist-info}/METADATA +14 -14
- tksheet-7.4.0.dist-info/RECORD +22 -0
- tksheet-7.3.3.dist-info/RECORD +0 -21
- {tksheet-7.3.3.dist-info → tksheet-7.4.0.dist-info}/LICENSE.txt +0 -0
- {tksheet-7.3.3.dist-info → tksheet-7.4.0.dist-info}/WHEEL +0 -0
- {tksheet-7.3.3.dist-info → tksheet-7.4.0.dist-info}/top_level.txt +0 -0
tksheet/sheet.py
CHANGED
@@ -2,36 +2,31 @@ from __future__ import annotations
|
|
2
2
|
|
3
3
|
import tkinter as tk
|
4
4
|
from bisect import bisect_left
|
5
|
-
from collections import
|
6
|
-
from collections.abc import
|
7
|
-
|
8
|
-
Generator,
|
9
|
-
Hashable,
|
10
|
-
Iterator,
|
11
|
-
Sequence,
|
12
|
-
)
|
13
|
-
from functools import partial
|
14
|
-
from itertools import (
|
15
|
-
accumulate,
|
16
|
-
chain,
|
17
|
-
filterfalse,
|
18
|
-
islice,
|
19
|
-
product,
|
20
|
-
repeat,
|
21
|
-
)
|
5
|
+
from collections import deque
|
6
|
+
from collections.abc import Callable, Generator, Hashable, Iterator, Sequence
|
7
|
+
from itertools import accumulate, chain, filterfalse, islice, product, repeat
|
22
8
|
from operator import attrgetter
|
23
9
|
from timeit import default_timer
|
24
10
|
from tkinter import ttk
|
25
11
|
from typing import Literal
|
26
12
|
|
27
13
|
from .column_headers import ColumnHeaders
|
14
|
+
from .constants import (
|
15
|
+
USER_OS,
|
16
|
+
align_value_error,
|
17
|
+
backwards_compatibility_keys,
|
18
|
+
emitted_events,
|
19
|
+
named_span_types,
|
20
|
+
rc_binding,
|
21
|
+
scrollbar_options_keys,
|
22
|
+
)
|
28
23
|
from .functions import (
|
29
24
|
add_highlight,
|
30
25
|
add_to_options,
|
31
26
|
alpha2idx,
|
27
|
+
bisect_in,
|
32
28
|
consecutive_ranges,
|
33
29
|
convert_align,
|
34
|
-
data_to_displayed_idxs,
|
35
30
|
del_from_options,
|
36
31
|
del_named_span_options,
|
37
32
|
del_named_span_options_nested,
|
@@ -48,12 +43,12 @@ from .functions import (
|
|
48
43
|
key_to_span,
|
49
44
|
new_tk_event,
|
50
45
|
num2alpha,
|
51
|
-
stored_event_dict,
|
52
46
|
pop_positions,
|
53
47
|
set_align,
|
54
48
|
set_readonly,
|
55
49
|
span_froms,
|
56
50
|
span_ranges,
|
51
|
+
stored_event_dict,
|
57
52
|
tksheet_type_error,
|
58
53
|
unpack,
|
59
54
|
)
|
@@ -70,9 +65,7 @@ from .other_classes import (
|
|
70
65
|
Span,
|
71
66
|
)
|
72
67
|
from .row_index import RowIndex
|
73
|
-
from .sheet_options import
|
74
|
-
new_sheet_options,
|
75
|
-
)
|
68
|
+
from .sheet_options import new_sheet_options
|
76
69
|
from .themes import (
|
77
70
|
theme_black,
|
78
71
|
theme_dark,
|
@@ -81,19 +74,8 @@ from .themes import (
|
|
81
74
|
theme_light_blue,
|
82
75
|
theme_light_green,
|
83
76
|
)
|
77
|
+
from .tksheet_types import AnyIter, CellPropertyKey, CreateSpanTypes
|
84
78
|
from .top_left_rectangle import TopLeftRectangle
|
85
|
-
from .types import (
|
86
|
-
AnyIter,
|
87
|
-
CreateSpanTypes,
|
88
|
-
)
|
89
|
-
from .constants import (
|
90
|
-
USER_OS,
|
91
|
-
backwards_compatibility_keys,
|
92
|
-
emitted_events,
|
93
|
-
named_span_types,
|
94
|
-
rc_binding,
|
95
|
-
scrollbar_options_keys,
|
96
|
-
)
|
97
79
|
|
98
80
|
|
99
81
|
class Sheet(tk.Frame):
|
@@ -102,7 +84,7 @@ class Sheet(tk.Frame):
|
|
102
84
|
parent: tk.Misc,
|
103
85
|
name: str = "!sheet",
|
104
86
|
show_table: bool = True,
|
105
|
-
show_top_left: bool =
|
87
|
+
show_top_left: bool = False,
|
106
88
|
show_row_index: bool = True,
|
107
89
|
show_header: bool = True,
|
108
90
|
show_x_scrollbar: bool = True,
|
@@ -135,10 +117,10 @@ class Sheet(tk.Frame):
|
|
135
117
|
after_redraw_time_ms: int = 20,
|
136
118
|
set_all_heights_and_widths: bool = False,
|
137
119
|
zoom: int = 100,
|
138
|
-
align: str = "
|
139
|
-
header_align: str = "
|
120
|
+
align: str = "nw",
|
121
|
+
header_align: str = "n",
|
140
122
|
row_index_align: str | None = None,
|
141
|
-
index_align: str = "
|
123
|
+
index_align: str = "n",
|
142
124
|
displayed_columns: list[int] = [],
|
143
125
|
all_columns_displayed: bool = True,
|
144
126
|
displayed_rows: list[int] = [],
|
@@ -197,9 +179,14 @@ class Sheet(tk.Frame):
|
|
197
179
|
edit_cell_return: Literal["right", "down", ""] = "down",
|
198
180
|
editor_del_key: Literal["forward", "backward", ""] = "forward",
|
199
181
|
treeview: bool = False,
|
200
|
-
treeview_indent: str | int = "
|
182
|
+
treeview_indent: str | int = "2",
|
201
183
|
rounded_boxes: bool = True,
|
202
184
|
alternate_color: str = "",
|
185
|
+
allow_cell_overflow: bool = False,
|
186
|
+
# "" no wrap, "w" word wrap, "c" char wrap
|
187
|
+
table_wrap: Literal["", "w", "c"] = "c",
|
188
|
+
index_wrap: Literal["", "w", "c"] = "c",
|
189
|
+
header_wrap: Literal["", "w", "c"] = "c",
|
203
190
|
# colors
|
204
191
|
outline_thickness: int = 0,
|
205
192
|
theme: str = "light blue",
|
@@ -338,7 +325,7 @@ class Sheet(tk.Frame):
|
|
338
325
|
self.name = name
|
339
326
|
self.last_event_data = EventDataDict()
|
340
327
|
self.bound_events = DotDict({k: [] for k in emitted_events})
|
341
|
-
self.
|
328
|
+
self._dropdown_cls = Dropdown
|
342
329
|
self.after_redraw_id = None
|
343
330
|
self.after_redraw_time_ms = after_redraw_time_ms
|
344
331
|
self.named_span_id = 0
|
@@ -354,22 +341,22 @@ class Sheet(tk.Frame):
|
|
354
341
|
self.config(width=350)
|
355
342
|
self.grid_columnconfigure(1, weight=1)
|
356
343
|
self.grid_rowconfigure(1, weight=1)
|
357
|
-
self.RI = RowIndex(
|
344
|
+
self.RI: RowIndex = RowIndex(
|
358
345
|
parent=self,
|
359
346
|
row_index_align=(
|
360
347
|
convert_align(row_index_align) if row_index_align is not None else convert_align(index_align)
|
361
348
|
),
|
362
349
|
)
|
363
|
-
self.CH = ColumnHeaders(
|
350
|
+
self.CH: ColumnHeaders = ColumnHeaders(
|
364
351
|
parent=self,
|
365
352
|
header_align=convert_align(header_align),
|
366
353
|
)
|
367
|
-
self.MT = MainTable(
|
354
|
+
self.MT: MainTable = MainTable(
|
368
355
|
parent=self,
|
369
|
-
show_index=show_row_index,
|
370
|
-
show_header=show_header,
|
371
356
|
column_headers_canvas=self.CH,
|
372
357
|
row_index_canvas=self.RI,
|
358
|
+
show_index=show_row_index,
|
359
|
+
show_header=show_header,
|
373
360
|
headers=headers,
|
374
361
|
header=header,
|
375
362
|
data_reference=data if data_reference is None else data_reference,
|
@@ -384,7 +371,7 @@ class Sheet(tk.Frame):
|
|
384
371
|
displayed_rows=displayed_rows,
|
385
372
|
all_rows_displayed=all_rows_displayed,
|
386
373
|
)
|
387
|
-
self.TL = TopLeftRectangle(
|
374
|
+
self.TL: TopLeftRectangle = TopLeftRectangle(
|
388
375
|
parent=self,
|
389
376
|
main_canvas=self.MT,
|
390
377
|
row_index_canvas=self.RI,
|
@@ -448,32 +435,19 @@ class Sheet(tk.Frame):
|
|
448
435
|
orient="horizontal",
|
449
436
|
style=f"Sheet{self.unique_id}.Horizontal.TScrollbar",
|
450
437
|
)
|
451
|
-
|
452
|
-
|
453
|
-
|
454
|
-
|
455
|
-
self.
|
456
|
-
|
457
|
-
|
458
|
-
|
459
|
-
self.
|
460
|
-
if
|
461
|
-
self.
|
462
|
-
|
463
|
-
|
464
|
-
self.xscroll.grid(row=2, column=0, columnspan=2, sticky="nswe")
|
465
|
-
self.xscroll_showing = True
|
466
|
-
self.xscroll_disabled = False
|
467
|
-
else:
|
468
|
-
self.xscroll_showing = False
|
469
|
-
self.xscroll_disabled = True
|
470
|
-
if show_y_scrollbar:
|
471
|
-
self.yscroll.grid(row=0, column=2, rowspan=3, sticky="nswe")
|
472
|
-
self.yscroll_showing = True
|
473
|
-
self.yscroll_disabled = False
|
474
|
-
else:
|
475
|
-
self.yscroll_showing = False
|
476
|
-
self.yscroll_disabled = True
|
438
|
+
self.show()
|
439
|
+
if not show_top_left and not (show_row_index and show_header):
|
440
|
+
self.hide("top_left")
|
441
|
+
if not show_row_index:
|
442
|
+
self.hide("row_index")
|
443
|
+
if not show_header:
|
444
|
+
self.hide("header")
|
445
|
+
if not show_table:
|
446
|
+
self.hide("table")
|
447
|
+
if not show_x_scrollbar:
|
448
|
+
self.hide("x_scrollbar")
|
449
|
+
if not show_y_scrollbar:
|
450
|
+
self.hide("y_scrollbar")
|
477
451
|
self.update_idletasks()
|
478
452
|
self.MT.update_idletasks()
|
479
453
|
self.RI.update_idletasks()
|
@@ -652,6 +626,11 @@ class Sheet(tk.Frame):
|
|
652
626
|
- "rc_delete_column"
|
653
627
|
- "rc_insert_row"
|
654
628
|
- "rc_delete_row"
|
629
|
+
- "sort_cells"
|
630
|
+
- "sort_row"
|
631
|
+
- "sort_column" / "sort_col"
|
632
|
+
- "sort_rows"
|
633
|
+
- "sort_columns" / "sort_cols"
|
655
634
|
- "ctrl_click_select" / "ctrl_select"
|
656
635
|
- "copy"
|
657
636
|
- "cut"
|
@@ -718,6 +697,12 @@ class Sheet(tk.Frame):
|
|
718
697
|
) -> Sheet:
|
719
698
|
"""
|
720
699
|
List of available bindings:
|
700
|
+
- "begin_sort_cells"
|
701
|
+
- "sort_cells", "end_sort_cells"
|
702
|
+
- "begin_sort_rows"
|
703
|
+
- "sort_rows", "end_sort_rows"
|
704
|
+
- "begin_sort_columns"
|
705
|
+
- "sort_columns", "end_sort_columns"
|
721
706
|
- "begin_copy", "begin_ctrl_c"
|
722
707
|
- "ctrl_c", "end_copy", "end_ctrl_c", "copy"
|
723
708
|
- "begin_cut", "begin_ctrl_x"
|
@@ -793,6 +778,9 @@ class Sheet(tk.Frame):
|
|
793
778
|
"bind_all",
|
794
779
|
"unbind_all",
|
795
780
|
):
|
781
|
+
self.MT.extra_begin_sort_cells_func = f
|
782
|
+
self.CH.ch_extra_begin_sort_rows_func = f
|
783
|
+
self.RI.ri_extra_begin_sort_cols_func = f
|
796
784
|
self.MT.extra_begin_ctrl_c_func = f
|
797
785
|
self.MT.extra_begin_ctrl_x_func = f
|
798
786
|
self.MT.extra_begin_ctrl_v_func = f
|
@@ -844,6 +832,9 @@ class Sheet(tk.Frame):
|
|
844
832
|
"modified_events",
|
845
833
|
"modified",
|
846
834
|
):
|
835
|
+
self.MT.extra_end_sort_cells_func = f
|
836
|
+
self.CH.ch_extra_end_sort_rows_func = f
|
837
|
+
self.RI.ri_extra_end_sort_cols_func = f
|
847
838
|
self.MT.extra_end_ctrl_c_func = f
|
848
839
|
self.MT.extra_end_ctrl_x_func = f
|
849
840
|
self.MT.extra_end_ctrl_v_func = f
|
@@ -859,6 +850,24 @@ class Sheet(tk.Frame):
|
|
859
850
|
self.CH.extra_end_edit_cell_func = f
|
860
851
|
self.RI.extra_end_edit_cell_func = f
|
861
852
|
|
853
|
+
if b in ("begin_sort_cells",):
|
854
|
+
self.MT.extra_begin_sort_cells_func = f
|
855
|
+
|
856
|
+
if b in ("sort_cells", "end_sort_cells"):
|
857
|
+
self.MT.extra_end_sort_cells_func = f
|
858
|
+
|
859
|
+
if b in ("begin_sort_rows",):
|
860
|
+
self.CH.ch_extra_begin_sort_rows_func = f
|
861
|
+
|
862
|
+
if b in ("sort_rows", "end_sort_rows"):
|
863
|
+
self.CH.ch_extra_end_sort_rows_func = f
|
864
|
+
|
865
|
+
if b in ("begin_sort_columns",):
|
866
|
+
self.RI.ri_extra_begin_sort_cols_func = f
|
867
|
+
|
868
|
+
if b in ("sort_columns", "end_sort_columns"):
|
869
|
+
self.RI.ri_extra_end_sort_cols_func = f
|
870
|
+
|
862
871
|
if b in (
|
863
872
|
"begin_copy",
|
864
873
|
"begin_ctrl_c",
|
@@ -1318,7 +1327,7 @@ class Sheet(tk.Frame):
|
|
1318
1327
|
transposed: bool = False,
|
1319
1328
|
ndim: int = 0,
|
1320
1329
|
convert: object = None,
|
1321
|
-
undo: bool =
|
1330
|
+
undo: bool = True,
|
1322
1331
|
emit_event: bool = False,
|
1323
1332
|
widget: object = None,
|
1324
1333
|
expand: None | str = None,
|
@@ -1790,8 +1799,6 @@ class Sheet(tk.Frame):
|
|
1790
1799
|
|
1791
1800
|
"""
|
1792
1801
|
span = self.span_from_key(*key)
|
1793
|
-
if data is None:
|
1794
|
-
data = []
|
1795
1802
|
startr, startc = span_froms(span)
|
1796
1803
|
table, index, header = span.table, span.index, span.header
|
1797
1804
|
fmt_kw = span.kwargs if span.type_ == "format" and span.kwargs else None
|
@@ -2097,7 +2104,7 @@ class Sheet(tk.Frame):
|
|
2097
2104
|
height: int | None = None,
|
2098
2105
|
row_index: bool = False,
|
2099
2106
|
fill: bool = True,
|
2100
|
-
undo: bool =
|
2107
|
+
undo: bool = True,
|
2101
2108
|
emit_event: bool = False,
|
2102
2109
|
redraw: bool = True,
|
2103
2110
|
) -> EventDataDict:
|
@@ -2119,7 +2126,7 @@ class Sheet(tk.Frame):
|
|
2119
2126
|
width: int | None = None,
|
2120
2127
|
header: bool = False,
|
2121
2128
|
fill: bool = True,
|
2122
|
-
undo: bool =
|
2129
|
+
undo: bool = True,
|
2123
2130
|
emit_event: bool = False,
|
2124
2131
|
redraw: bool = True,
|
2125
2132
|
) -> EventDataDict:
|
@@ -2141,11 +2148,12 @@ class Sheet(tk.Frame):
|
|
2141
2148
|
heights: list[int] | tuple[int] | None = None,
|
2142
2149
|
row_index: bool = False,
|
2143
2150
|
fill: bool = True,
|
2144
|
-
undo: bool =
|
2151
|
+
undo: bool = True,
|
2145
2152
|
emit_event: bool = False,
|
2146
2153
|
create_selections: bool = True,
|
2147
2154
|
add_column_widths: bool = True,
|
2148
2155
|
push_ops: bool = True,
|
2156
|
+
tree: bool = True,
|
2149
2157
|
redraw: bool = True,
|
2150
2158
|
) -> EventDataDict:
|
2151
2159
|
total_cols = None
|
@@ -2205,14 +2213,10 @@ class Sheet(tk.Frame):
|
|
2205
2213
|
row_index=row_index,
|
2206
2214
|
),
|
2207
2215
|
add_col_positions=add_column_widths,
|
2208
|
-
event_data=
|
2209
|
-
name="add_rows",
|
2210
|
-
sheet=self.name,
|
2211
|
-
boxes=self.MT.get_boxes(),
|
2212
|
-
selected=self.MT.selected,
|
2213
|
-
),
|
2216
|
+
event_data=self.MT.new_event_dict("add_rows", state=True),
|
2214
2217
|
create_selections=create_selections,
|
2215
2218
|
push_ops=push_ops,
|
2219
|
+
tree=tree,
|
2216
2220
|
)
|
2217
2221
|
if undo:
|
2218
2222
|
self.MT.undo_stack.append(stored_event_dict(event_data))
|
@@ -2228,7 +2232,7 @@ class Sheet(tk.Frame):
|
|
2228
2232
|
widths: list[int] | tuple[int] | None = None,
|
2229
2233
|
headers: bool = False,
|
2230
2234
|
fill: bool = True,
|
2231
|
-
undo: bool =
|
2235
|
+
undo: bool = True,
|
2232
2236
|
emit_event: bool = False,
|
2233
2237
|
create_selections: bool = True,
|
2234
2238
|
add_row_heights: bool = True,
|
@@ -2300,12 +2304,7 @@ class Sheet(tk.Frame):
|
|
2300
2304
|
headers=headers,
|
2301
2305
|
),
|
2302
2306
|
add_row_positions=add_row_heights,
|
2303
|
-
event_data=
|
2304
|
-
name="add_columns",
|
2305
|
-
sheet=self.name,
|
2306
|
-
boxes=self.MT.get_boxes(),
|
2307
|
-
selected=self.MT.selected,
|
2308
|
-
),
|
2307
|
+
event_data=self.MT.new_event_dict("add_columns", state=True),
|
2309
2308
|
create_selections=create_selections,
|
2310
2309
|
push_ops=push_ops,
|
2311
2310
|
)
|
@@ -2316,124 +2315,48 @@ class Sheet(tk.Frame):
|
|
2316
2315
|
self.set_refresh_timer(redraw)
|
2317
2316
|
return event_data
|
2318
2317
|
|
2319
|
-
def
|
2320
|
-
self,
|
2321
|
-
idx: int = 0,
|
2322
|
-
data_indexes: bool = True,
|
2323
|
-
undo: bool = False,
|
2324
|
-
emit_event: bool = False,
|
2325
|
-
redraw: bool = True,
|
2326
|
-
) -> EventDataDict:
|
2327
|
-
return self.del_rows(
|
2328
|
-
rows=idx,
|
2329
|
-
data_indexes=data_indexes,
|
2330
|
-
undo=undo,
|
2331
|
-
emit_event=emit_event,
|
2332
|
-
redraw=redraw,
|
2333
|
-
)
|
2334
|
-
|
2335
|
-
delete_row = del_row
|
2336
|
-
|
2337
|
-
def del_column(
|
2318
|
+
def del_rows(
|
2338
2319
|
self,
|
2339
|
-
|
2320
|
+
rows: int | AnyIter[int],
|
2340
2321
|
data_indexes: bool = True,
|
2341
|
-
undo: bool =
|
2322
|
+
undo: bool = True,
|
2342
2323
|
emit_event: bool = False,
|
2343
2324
|
redraw: bool = True,
|
2344
2325
|
) -> EventDataDict:
|
2345
|
-
|
2346
|
-
|
2326
|
+
event_data = self.MT.delete_rows(
|
2327
|
+
rows=[rows] if isinstance(rows, int) else sorted(set(rows)),
|
2347
2328
|
data_indexes=data_indexes,
|
2348
2329
|
undo=undo,
|
2349
2330
|
emit_event=emit_event,
|
2350
|
-
|
2351
|
-
)
|
2352
|
-
|
2353
|
-
delete_column = del_column
|
2354
|
-
|
2355
|
-
def del_rows(
|
2356
|
-
self,
|
2357
|
-
rows: int | AnyIter[int],
|
2358
|
-
data_indexes: bool = True,
|
2359
|
-
undo: bool = False,
|
2360
|
-
emit_event: bool = False,
|
2361
|
-
redraw: bool = True,
|
2362
|
-
) -> EventDataDict:
|
2363
|
-
self.MT.deselect("all", redraw=False)
|
2364
|
-
rows = [rows] if isinstance(rows, int) else sorted(rows)
|
2365
|
-
event_data = event_dict(
|
2366
|
-
name="delete_rows",
|
2367
|
-
sheet=self.name,
|
2368
|
-
widget=self,
|
2369
|
-
boxes=self.MT.get_boxes(),
|
2370
|
-
selected=self.MT.selected,
|
2331
|
+
ext=True,
|
2371
2332
|
)
|
2372
|
-
if not data_indexes:
|
2373
|
-
event_data = self.MT.delete_rows_displayed(rows, event_data)
|
2374
|
-
event_data = self.MT.delete_rows_data(
|
2375
|
-
rows if self.MT.all_rows_displayed else [self.MT.displayed_rows[r] for r in rows],
|
2376
|
-
event_data,
|
2377
|
-
)
|
2378
|
-
else:
|
2379
|
-
if self.MT.all_rows_displayed:
|
2380
|
-
rows = rows
|
2381
|
-
else:
|
2382
|
-
rows = data_to_displayed_idxs(rows, self.MT.displayed_rows)
|
2383
|
-
event_data = self.MT.delete_rows_data(rows, event_data)
|
2384
|
-
event_data = self.MT.delete_rows_displayed(
|
2385
|
-
rows,
|
2386
|
-
event_data,
|
2387
|
-
)
|
2388
|
-
if undo:
|
2389
|
-
self.MT.undo_stack.append(stored_event_dict(event_data))
|
2390
|
-
if emit_event:
|
2391
|
-
self.emit_event("<<SheetModified>>", event_data)
|
2392
2333
|
self.set_refresh_timer(redraw)
|
2393
2334
|
return event_data
|
2394
2335
|
|
2336
|
+
del_row = del_rows
|
2337
|
+
delete_row = del_rows
|
2395
2338
|
delete_rows = del_rows
|
2396
2339
|
|
2397
2340
|
def del_columns(
|
2398
2341
|
self,
|
2399
2342
|
columns: int | AnyIter[int],
|
2400
2343
|
data_indexes: bool = True,
|
2401
|
-
undo: bool =
|
2344
|
+
undo: bool = True,
|
2402
2345
|
emit_event: bool = False,
|
2403
2346
|
redraw: bool = True,
|
2404
2347
|
) -> EventDataDict:
|
2405
|
-
self.MT.
|
2406
|
-
|
2407
|
-
|
2408
|
-
|
2409
|
-
|
2410
|
-
|
2411
|
-
boxes=self.MT.get_boxes(),
|
2412
|
-
selected=self.MT.selected,
|
2348
|
+
event_data = self.MT.delete_columns(
|
2349
|
+
columns=[columns] if isinstance(columns, int) else sorted(set(columns)),
|
2350
|
+
data_indexes=data_indexes,
|
2351
|
+
undo=undo,
|
2352
|
+
emit_event=emit_event,
|
2353
|
+
ext=True,
|
2413
2354
|
)
|
2414
|
-
if not data_indexes:
|
2415
|
-
event_data = self.MT.delete_columns_displayed(columns, event_data)
|
2416
|
-
event_data = self.MT.delete_columns_data(
|
2417
|
-
columns if self.MT.all_columns_displayed else [self.MT.displayed_columns[c] for c in columns],
|
2418
|
-
event_data,
|
2419
|
-
)
|
2420
|
-
else:
|
2421
|
-
if self.MT.all_columns_displayed:
|
2422
|
-
columns = columns
|
2423
|
-
else:
|
2424
|
-
columns = data_to_displayed_idxs(columns, self.MT.displayed_columns)
|
2425
|
-
event_data = self.MT.delete_columns_data(columns, event_data)
|
2426
|
-
event_data = self.MT.delete_columns_displayed(
|
2427
|
-
columns,
|
2428
|
-
event_data,
|
2429
|
-
)
|
2430
|
-
if undo:
|
2431
|
-
self.MT.undo_stack.append(stored_event_dict(event_data))
|
2432
|
-
if emit_event:
|
2433
|
-
self.emit_event("<<SheetModified>>", event_data)
|
2434
2355
|
self.set_refresh_timer(redraw)
|
2435
2356
|
return event_data
|
2436
2357
|
|
2358
|
+
del_column = del_columns
|
2359
|
+
delete_column = del_columns
|
2437
2360
|
delete_columns = del_columns
|
2438
2361
|
|
2439
2362
|
def sheet_data_dimensions(
|
@@ -2495,11 +2418,11 @@ class Sheet(tk.Frame):
|
|
2495
2418
|
self.MT.data_dimensions(total_columns=number)
|
2496
2419
|
return self
|
2497
2420
|
|
2498
|
-
def move_row(self, row: int, moveto: int) -> tuple[dict, dict,
|
2499
|
-
return self.move_rows(moveto, row)
|
2421
|
+
def move_row(self, row: int, moveto: int) -> tuple[dict[int, int], dict[int, int], EventDataDict]:
|
2422
|
+
return self.move_rows(moveto, [row])
|
2500
2423
|
|
2501
|
-
def move_column(self, column: int, moveto: int) -> tuple[dict, dict,
|
2502
|
-
return self.move_columns(moveto, column)
|
2424
|
+
def move_column(self, column: int, moveto: int) -> tuple[dict[int, int], dict[int, int], EventDataDict]:
|
2425
|
+
return self.move_columns(moveto, [column])
|
2503
2426
|
|
2504
2427
|
def move_rows(
|
2505
2428
|
self,
|
@@ -2508,11 +2431,16 @@ class Sheet(tk.Frame):
|
|
2508
2431
|
move_data: bool = True,
|
2509
2432
|
data_indexes: bool = False,
|
2510
2433
|
create_selections: bool = True,
|
2511
|
-
undo: bool =
|
2434
|
+
undo: bool = True,
|
2512
2435
|
emit_event: bool = False,
|
2513
2436
|
move_heights: bool = True,
|
2437
|
+
event_data: EventDataDict | None = None,
|
2514
2438
|
redraw: bool = True,
|
2515
|
-
) -> tuple[dict, dict,
|
2439
|
+
) -> tuple[dict[int, int], dict[int, int], EventDataDict]:
|
2440
|
+
if not event_data:
|
2441
|
+
event_data = self.MT.new_event_dict("move_rows", state=True)
|
2442
|
+
if not data_indexes:
|
2443
|
+
event_data.value = move_to
|
2516
2444
|
data_idxs, disp_idxs, event_data = self.MT.move_rows_adjust_options_dict(
|
2517
2445
|
*self.MT.get_args_for_move_rows(
|
2518
2446
|
move_to=move_to,
|
@@ -2522,7 +2450,7 @@ class Sheet(tk.Frame):
|
|
2522
2450
|
move_data=move_data,
|
2523
2451
|
move_heights=move_heights,
|
2524
2452
|
create_selections=create_selections,
|
2525
|
-
|
2453
|
+
event_data=event_data,
|
2526
2454
|
)
|
2527
2455
|
if undo:
|
2528
2456
|
self.MT.undo_stack.append(stored_event_dict(event_data))
|
@@ -2538,11 +2466,16 @@ class Sheet(tk.Frame):
|
|
2538
2466
|
move_data: bool = True,
|
2539
2467
|
data_indexes: bool = False,
|
2540
2468
|
create_selections: bool = True,
|
2541
|
-
undo: bool =
|
2469
|
+
undo: bool = True,
|
2542
2470
|
emit_event: bool = False,
|
2543
2471
|
move_widths: bool = True,
|
2472
|
+
event_data: EventDataDict | None = None,
|
2544
2473
|
redraw: bool = True,
|
2545
|
-
) -> tuple[dict, dict,
|
2474
|
+
) -> tuple[dict[int, int], dict[int, int], EventDataDict]:
|
2475
|
+
if not event_data:
|
2476
|
+
event_data = self.MT.new_event_dict("move_columns", state=True)
|
2477
|
+
if not data_indexes:
|
2478
|
+
event_data.value = move_to
|
2546
2479
|
data_idxs, disp_idxs, event_data = self.MT.move_columns_adjust_options_dict(
|
2547
2480
|
*self.MT.get_args_for_move_columns(
|
2548
2481
|
move_to=move_to,
|
@@ -2552,7 +2485,7 @@ class Sheet(tk.Frame):
|
|
2552
2485
|
move_data=move_data,
|
2553
2486
|
move_widths=move_widths,
|
2554
2487
|
create_selections=create_selections,
|
2555
|
-
|
2488
|
+
event_data=event_data,
|
2556
2489
|
)
|
2557
2490
|
if undo:
|
2558
2491
|
self.MT.undo_stack.append(stored_event_dict(event_data))
|
@@ -2566,9 +2499,8 @@ class Sheet(tk.Frame):
|
|
2566
2499
|
data_new_idxs: dict[int, int],
|
2567
2500
|
disp_new_idxs: None | dict[int, int] = None,
|
2568
2501
|
move_data: bool = True,
|
2569
|
-
data_indexes: bool = False,
|
2570
2502
|
create_selections: bool = True,
|
2571
|
-
undo: bool =
|
2503
|
+
undo: bool = True,
|
2572
2504
|
emit_event: bool = False,
|
2573
2505
|
redraw: bool = True,
|
2574
2506
|
) -> tuple[dict[int, int], dict[int, int], EventDataDict]:
|
@@ -2579,7 +2511,6 @@ class Sheet(tk.Frame):
|
|
2579
2511
|
disp_new_idxs=disp_new_idxs,
|
2580
2512
|
move_data=move_data,
|
2581
2513
|
create_selections=create_selections,
|
2582
|
-
data_indexes=data_indexes,
|
2583
2514
|
)
|
2584
2515
|
if undo:
|
2585
2516
|
self.MT.undo_stack.append(stored_event_dict(event_data))
|
@@ -2593,10 +2524,10 @@ class Sheet(tk.Frame):
|
|
2593
2524
|
data_new_idxs: dict[int, int],
|
2594
2525
|
disp_new_idxs: None | dict[int, int] = None,
|
2595
2526
|
move_data: bool = True,
|
2596
|
-
data_indexes: bool = False,
|
2597
2527
|
create_selections: bool = True,
|
2598
|
-
undo: bool =
|
2528
|
+
undo: bool = True,
|
2599
2529
|
emit_event: bool = False,
|
2530
|
+
event_data: EventDataDict | None = None,
|
2600
2531
|
redraw: bool = True,
|
2601
2532
|
) -> tuple[dict[int, int], dict[int, int], EventDataDict]:
|
2602
2533
|
data_idxs, disp_idxs, event_data = self.MT.move_rows_adjust_options_dict(
|
@@ -2606,7 +2537,7 @@ class Sheet(tk.Frame):
|
|
2606
2537
|
disp_new_idxs=disp_new_idxs,
|
2607
2538
|
move_data=move_data,
|
2608
2539
|
create_selections=create_selections,
|
2609
|
-
|
2540
|
+
event_data=event_data,
|
2610
2541
|
)
|
2611
2542
|
if undo:
|
2612
2543
|
self.MT.undo_stack.append(stored_event_dict(event_data))
|
@@ -2647,6 +2578,102 @@ class Sheet(tk.Frame):
|
|
2647
2578
|
data_idxs,
|
2648
2579
|
)
|
2649
2580
|
|
2581
|
+
# Sorting
|
2582
|
+
|
2583
|
+
def sort(
|
2584
|
+
self,
|
2585
|
+
boxes: AnyIter[Sequence[int, int, int, int]] | Span | None = None,
|
2586
|
+
reverse: bool = False,
|
2587
|
+
row_wise: bool = False,
|
2588
|
+
validation: bool = True,
|
2589
|
+
key: Callable | None = None,
|
2590
|
+
undo: bool = True,
|
2591
|
+
) -> EventDataDict:
|
2592
|
+
"""
|
2593
|
+
Sort the data within specified box regions in the table.
|
2594
|
+
|
2595
|
+
This method sorts the data within one or multiple box regions defined by their coordinates. Each box's columns are sorted independently.
|
2596
|
+
|
2597
|
+
Args:
|
2598
|
+
boxes (AnyIter[Sequence[int, int, int, int]] | Span | None): An iterable of box coordinates. Each box is defined by:
|
2599
|
+
- From Row (inclusive)
|
2600
|
+
- From Column (inclusive)
|
2601
|
+
- Up To Row (exclusive)
|
2602
|
+
- Up To Column (exclusive)
|
2603
|
+
If None, it will sort the currently selected boxes or the entire table.
|
2604
|
+
If Span, it will use the span coordinates.
|
2605
|
+
|
2606
|
+
reverse (bool): If True, sorts in descending order. Default is False (ascending).
|
2607
|
+
|
2608
|
+
row_wise (bool): if True sorts cells row-wise. Default is column-wise
|
2609
|
+
|
2610
|
+
validation (bool): If True, checks if the new cell values are valid according to any restrictions
|
2611
|
+
(e.g., dropdown validations) before applying the sort. Default is True.
|
2612
|
+
|
2613
|
+
key (Callable | None): A function to extract a comparison key from each element in the columns.
|
2614
|
+
If None, a natural sorting key will be used, which can handle most Python objects, including:
|
2615
|
+
- None, booleans, numbers (int, float), datetime objects, strings, and unknown types.
|
2616
|
+
Note: Performance might be slow with the natural sort for very large datasets.
|
2617
|
+
|
2618
|
+
Returns:
|
2619
|
+
EventDataDict: A dictionary containing information about the sorting event, including changes made to the table.
|
2620
|
+
|
2621
|
+
Raises:
|
2622
|
+
ValueError: If the input boxes are not in the expected format or if the data cannot be sorted.
|
2623
|
+
|
2624
|
+
Note:
|
2625
|
+
- Sorting is performed column-wise within each box.
|
2626
|
+
- If validation is enabled, any cell content that fails validation will not be updated.
|
2627
|
+
- Any cell options attached to cells will not be moved. Event data can be used to re-locate them.
|
2628
|
+
"""
|
2629
|
+
if isinstance(boxes, Span):
|
2630
|
+
boxes = [boxes.coords]
|
2631
|
+
return self.MT.sort_boxes(
|
2632
|
+
boxes=boxes, reverse=reverse, row_wise=row_wise, validation=validation, key=key, undo=undo
|
2633
|
+
)
|
2634
|
+
|
2635
|
+
def sort_rows(
|
2636
|
+
self,
|
2637
|
+
rows: AnyIter[int] | Span | None = None,
|
2638
|
+
reverse: bool = False,
|
2639
|
+
validation: bool = True,
|
2640
|
+
key: Callable | None = None,
|
2641
|
+
undo: bool = True,
|
2642
|
+
) -> EventDataDict:
|
2643
|
+
if isinstance(rows, Span):
|
2644
|
+
rows = rows.rows
|
2645
|
+
return self.RI._sort_rows(rows=rows, reverse=reverse, validation=validation, key=key, undo=undo)
|
2646
|
+
|
2647
|
+
def sort_columns(
|
2648
|
+
self,
|
2649
|
+
columns: AnyIter[int] | Span | None = None,
|
2650
|
+
reverse: bool = False,
|
2651
|
+
validation: bool = True,
|
2652
|
+
key: Callable | None = None,
|
2653
|
+
undo: bool = True,
|
2654
|
+
) -> EventDataDict:
|
2655
|
+
if isinstance(columns, Span):
|
2656
|
+
columns = columns.columns
|
2657
|
+
return self.CH._sort_columns(columns=columns, reverse=reverse, validation=validation, key=key, undo=undo)
|
2658
|
+
|
2659
|
+
def sort_rows_by_column(
|
2660
|
+
self,
|
2661
|
+
column: int | None = None,
|
2662
|
+
reverse: bool = False,
|
2663
|
+
key: Callable | None = None,
|
2664
|
+
undo: bool = True,
|
2665
|
+
) -> EventDataDict:
|
2666
|
+
return self.CH._sort_rows_by_column(column=column, reverse=reverse, key=key, undo=undo)
|
2667
|
+
|
2668
|
+
def sort_columns_by_row(
|
2669
|
+
self,
|
2670
|
+
row: int | None = None,
|
2671
|
+
reverse: bool = False,
|
2672
|
+
key: Callable | None = None,
|
2673
|
+
undo: bool = True,
|
2674
|
+
) -> EventDataDict:
|
2675
|
+
return self.RI._sort_columns_by_row(row=row, reverse=reverse, key=key, undo=undo)
|
2676
|
+
|
2650
2677
|
# Highlighting Cells
|
2651
2678
|
|
2652
2679
|
def highlight(
|
@@ -3085,16 +3112,17 @@ class Sheet(tk.Frame):
|
|
3085
3112
|
|
3086
3113
|
# Text Font and Alignment
|
3087
3114
|
|
3088
|
-
def font(
|
3089
|
-
self
|
3090
|
-
|
3091
|
-
|
3092
|
-
) -> tuple[str, int, str]:
|
3093
|
-
return self.MT.set_table_font(newfont, reset_row_positions=reset_row_positions)
|
3115
|
+
def font(self, newfont: tuple[str, int, str] | None = None, **_) -> tuple[str, int, str]:
|
3116
|
+
return self.MT.set_table_font(newfont)
|
3117
|
+
|
3118
|
+
table_font = font
|
3094
3119
|
|
3095
3120
|
def header_font(self, newfont: tuple[str, int, str] | None = None) -> tuple[str, int, str]:
|
3096
3121
|
return self.MT.set_header_font(newfont)
|
3097
3122
|
|
3123
|
+
def index_font(self, newfont: tuple[str, int, str] | None = None) -> tuple[str, int, str]:
|
3124
|
+
return self.MT.set_index_font(newfont)
|
3125
|
+
|
3098
3126
|
def table_align(
|
3099
3127
|
self,
|
3100
3128
|
align: str | None = None,
|
@@ -3105,7 +3133,7 @@ class Sheet(tk.Frame):
|
|
3105
3133
|
elif convert_align(align):
|
3106
3134
|
self.MT.align = convert_align(align)
|
3107
3135
|
else:
|
3108
|
-
raise ValueError(
|
3136
|
+
raise ValueError()
|
3109
3137
|
return self.set_refresh_timer(redraw)
|
3110
3138
|
|
3111
3139
|
def header_align(
|
@@ -3118,7 +3146,7 @@ class Sheet(tk.Frame):
|
|
3118
3146
|
elif convert_align(align):
|
3119
3147
|
self.CH.align = convert_align(align)
|
3120
3148
|
else:
|
3121
|
-
raise ValueError(
|
3149
|
+
raise ValueError(align_value_error)
|
3122
3150
|
return self.set_refresh_timer(redraw)
|
3123
3151
|
|
3124
3152
|
def row_index_align(
|
@@ -3131,7 +3159,7 @@ class Sheet(tk.Frame):
|
|
3131
3159
|
elif convert_align(align):
|
3132
3160
|
self.RI.align = convert_align(align)
|
3133
3161
|
else:
|
3134
|
-
raise ValueError(
|
3162
|
+
raise ValueError(align_value_error)
|
3135
3163
|
return self.set_refresh_timer(redraw)
|
3136
3164
|
|
3137
3165
|
index_align = row_index_align
|
@@ -3594,18 +3622,41 @@ class Sheet(tk.Frame):
|
|
3594
3622
|
only_set_if_too_small: bool = False,
|
3595
3623
|
redraw: bool = True,
|
3596
3624
|
) -> Sheet | int:
|
3597
|
-
if column == "all"
|
3598
|
-
|
3599
|
-
|
3600
|
-
|
3601
|
-
self.
|
3602
|
-
|
3603
|
-
|
3604
|
-
|
3605
|
-
|
3625
|
+
if column == "all":
|
3626
|
+
if width == "default":
|
3627
|
+
self.MT.reset_col_positions()
|
3628
|
+
elif width == "text":
|
3629
|
+
self.set_all_column_widths(only_set_if_too_small=only_set_if_too_small)
|
3630
|
+
elif isinstance(width, int):
|
3631
|
+
self.MT.reset_col_positions(width=width)
|
3632
|
+
|
3633
|
+
elif column == "displayed":
|
3634
|
+
if width == "default":
|
3635
|
+
for c in range(*self.MT.visible_text_columns):
|
3636
|
+
self.CH.set_col_width(
|
3637
|
+
c, width=self.ops.default_column_width, only_if_too_small=only_set_if_too_small
|
3638
|
+
)
|
3639
|
+
elif width == "text":
|
3640
|
+
for c in range(*self.MT.visible_text_columns):
|
3641
|
+
self.CH.set_col_width(c, only_if_too_small=only_set_if_too_small)
|
3642
|
+
elif isinstance(width, int):
|
3643
|
+
for c in range(*self.MT.visible_text_columns):
|
3644
|
+
self.CH.set_col_width(c, width=width, only_if_too_small=only_set_if_too_small)
|
3645
|
+
|
3606
3646
|
elif isinstance(column, int):
|
3607
|
-
|
3608
|
-
|
3647
|
+
if width == "default":
|
3648
|
+
self.CH.set_col_width(
|
3649
|
+
col=column, width=self.ops.default_column_width, only_if_too_small=only_set_if_too_small
|
3650
|
+
)
|
3651
|
+
elif width == "text":
|
3652
|
+
self.CH.set_col_width(col=column, only_if_too_small=only_set_if_too_small)
|
3653
|
+
elif isinstance(width, int):
|
3654
|
+
self.CH.set_col_width(col=column, width=width, only_if_too_small=only_set_if_too_small)
|
3655
|
+
elif width is None:
|
3656
|
+
return int(self.MT.col_positions[column + 1] - self.MT.col_positions[column])
|
3657
|
+
|
3658
|
+
else:
|
3659
|
+
return self.set_refresh_timer(redraw)
|
3609
3660
|
|
3610
3661
|
def row_height(
|
3611
3662
|
self,
|
@@ -3614,18 +3665,39 @@ class Sheet(tk.Frame):
|
|
3614
3665
|
only_set_if_too_small: bool = False,
|
3615
3666
|
redraw: bool = True,
|
3616
3667
|
) -> Sheet | int:
|
3617
|
-
if row == "all"
|
3618
|
-
|
3619
|
-
|
3620
|
-
|
3621
|
-
self.
|
3622
|
-
|
3623
|
-
|
3624
|
-
|
3625
|
-
|
3668
|
+
if row == "all":
|
3669
|
+
if height == "default":
|
3670
|
+
self.MT.reset_row_positions()
|
3671
|
+
elif height == "text":
|
3672
|
+
self.set_all_row_heights()
|
3673
|
+
elif isinstance(height, int):
|
3674
|
+
self.MT.reset_row_positions(height=height)
|
3675
|
+
|
3676
|
+
elif row == "displayed":
|
3677
|
+
if height == "default":
|
3678
|
+
height = self.MT.get_default_row_height()
|
3679
|
+
for r in range(*self.MT.visible_text_rows):
|
3680
|
+
self.RI.set_row_height(r, height=height, only_if_too_small=only_set_if_too_small)
|
3681
|
+
elif height == "text":
|
3682
|
+
for r in range(*self.MT.visible_text_rows):
|
3683
|
+
self.RI.set_row_height(r, only_if_too_small=only_set_if_too_small)
|
3684
|
+
elif isinstance(height, int):
|
3685
|
+
for r in range(*self.MT.visible_text_rows):
|
3686
|
+
self.RI.set_row_height(r, height=height, only_if_too_small=only_set_if_too_small)
|
3687
|
+
|
3626
3688
|
elif isinstance(row, int):
|
3627
|
-
|
3628
|
-
|
3689
|
+
if height == "default":
|
3690
|
+
height = self.MT.get_default_row_height()
|
3691
|
+
self.RI.set_row_height(row=row, height=height, only_if_too_small=only_set_if_too_small)
|
3692
|
+
elif height == "text":
|
3693
|
+
self.RI.set_row_height(row=row, only_if_too_small=only_set_if_too_small)
|
3694
|
+
elif isinstance(height, int):
|
3695
|
+
self.RI.set_row_height(row=row, height=height, only_if_too_small=only_set_if_too_small)
|
3696
|
+
elif height is None:
|
3697
|
+
return int(self.MT.row_positions[row + 1] - self.MT.row_positions[row])
|
3698
|
+
|
3699
|
+
else:
|
3700
|
+
return self.set_refresh_timer(redraw)
|
3629
3701
|
|
3630
3702
|
def get_column_widths(self, canvas_positions: bool = False) -> list[float]:
|
3631
3703
|
if canvas_positions:
|
@@ -3759,7 +3831,7 @@ class Sheet(tk.Frame):
|
|
3759
3831
|
deselect_all: bool = False,
|
3760
3832
|
redraw: bool = False,
|
3761
3833
|
) -> Sheet:
|
3762
|
-
self.MT.
|
3834
|
+
self.MT.insert_col_positions(idx=idx, widths=width, deselect_all=deselect_all)
|
3763
3835
|
return self.set_refresh_timer(redraw)
|
3764
3836
|
|
3765
3837
|
def insert_row_position(
|
@@ -3769,7 +3841,7 @@ class Sheet(tk.Frame):
|
|
3769
3841
|
deselect_all: bool = False,
|
3770
3842
|
redraw: bool = False,
|
3771
3843
|
) -> Sheet:
|
3772
|
-
self.MT.
|
3844
|
+
self.MT.insert_row_positions(idx=idx, heights=height, deselect_all=deselect_all)
|
3773
3845
|
return self.set_refresh_timer(redraw)
|
3774
3846
|
|
3775
3847
|
def insert_column_positions(
|
@@ -4101,11 +4173,12 @@ class Sheet(tk.Frame):
|
|
4101
4173
|
if isinstance(columns, int):
|
4102
4174
|
columns = [columns]
|
4103
4175
|
cws = self.MT.get_column_widths()
|
4176
|
+
default_col_w = self.ops.default_column_width
|
4104
4177
|
for column in columns:
|
4105
4178
|
idx = bisect_left(self.MT.displayed_columns, column)
|
4106
4179
|
if len(self.MT.displayed_columns) == idx or self.MT.displayed_columns[idx] != column:
|
4107
4180
|
self.MT.displayed_columns.insert(idx, column)
|
4108
|
-
cws.insert(idx, self.MT.saved_column_widths.pop(column,
|
4181
|
+
cws.insert(idx, self.MT.saved_column_widths.pop(column, default_col_w))
|
4109
4182
|
self.MT.set_col_positions(cws)
|
4110
4183
|
if deselect_all:
|
4111
4184
|
self.MT.deselect(redraw=False)
|
@@ -4234,12 +4307,13 @@ class Sheet(tk.Frame):
|
|
4234
4307
|
return
|
4235
4308
|
if isinstance(rows, int):
|
4236
4309
|
rows = [rows]
|
4310
|
+
default_row_h = self.MT.get_default_row_height()
|
4237
4311
|
rhs = self.MT.get_row_heights()
|
4238
4312
|
for row in rows:
|
4239
4313
|
idx = bisect_left(self.MT.displayed_rows, row)
|
4240
4314
|
if len(self.MT.displayed_rows) == idx or self.MT.displayed_rows[idx] != row:
|
4241
4315
|
self.MT.displayed_rows.insert(idx, row)
|
4242
|
-
rhs.insert(idx, self.MT.saved_row_heights.pop(row,
|
4316
|
+
rhs.insert(idx, self.MT.saved_row_heights.pop(row, default_row_h))
|
4243
4317
|
self.MT.set_row_positions(rhs)
|
4244
4318
|
if deselect_all:
|
4245
4319
|
self.MT.deselect(redraw=False)
|
@@ -4274,52 +4348,6 @@ class Sheet(tk.Frame):
|
|
4274
4348
|
|
4275
4349
|
# Hiding Sheet Elements
|
4276
4350
|
|
4277
|
-
def hide(
|
4278
|
-
self,
|
4279
|
-
canvas: Literal[
|
4280
|
-
"all",
|
4281
|
-
"row_index",
|
4282
|
-
"header",
|
4283
|
-
"top_left",
|
4284
|
-
"x_scrollbar",
|
4285
|
-
"y_scrollbar",
|
4286
|
-
] = "all",
|
4287
|
-
) -> Sheet:
|
4288
|
-
if canvas.lower() == "all":
|
4289
|
-
self.TL.grid_forget()
|
4290
|
-
self.RI.grid_forget()
|
4291
|
-
self.RI["yscrollcommand"] = 0
|
4292
|
-
self.MT.show_index = False
|
4293
|
-
self.CH.grid_forget()
|
4294
|
-
self.CH["xscrollcommand"] = 0
|
4295
|
-
self.MT.show_header = False
|
4296
|
-
self.MT.grid_forget()
|
4297
|
-
self.yscroll.grid_forget()
|
4298
|
-
self.xscroll.grid_forget()
|
4299
|
-
self.xscroll_showing = False
|
4300
|
-
self.yscroll_showing = False
|
4301
|
-
self.xscroll_disabled = True
|
4302
|
-
self.yscroll_disabled = True
|
4303
|
-
elif canvas.lower() == "row_index":
|
4304
|
-
self.RI.grid_forget()
|
4305
|
-
self.RI["yscrollcommand"] = 0
|
4306
|
-
self.MT.show_index = False
|
4307
|
-
elif canvas.lower() == "header":
|
4308
|
-
self.CH.grid_forget()
|
4309
|
-
self.CH["xscrollcommand"] = 0
|
4310
|
-
self.MT.show_header = False
|
4311
|
-
elif canvas.lower() == "top_left":
|
4312
|
-
self.TL.grid_forget()
|
4313
|
-
elif canvas.lower() == "x_scrollbar":
|
4314
|
-
self.xscroll.grid_forget()
|
4315
|
-
self.xscroll_showing = False
|
4316
|
-
self.xscroll_disabled = True
|
4317
|
-
elif canvas.lower() == "y_scrollbar":
|
4318
|
-
self.yscroll.grid_forget()
|
4319
|
-
self.yscroll_showing = False
|
4320
|
-
self.yscroll_disabled = True
|
4321
|
-
return self
|
4322
|
-
|
4323
4351
|
def show(
|
4324
4352
|
self,
|
4325
4353
|
canvas: Literal[
|
@@ -4330,45 +4358,75 @@ class Sheet(tk.Frame):
|
|
4330
4358
|
"top_left",
|
4331
4359
|
"x_scrollbar",
|
4332
4360
|
"y_scrollbar",
|
4361
|
+
"table",
|
4333
4362
|
] = "all",
|
4334
4363
|
) -> Sheet:
|
4335
|
-
if canvas
|
4336
|
-
self.hide()
|
4337
|
-
self.TL.grid(row=0, column=0)
|
4338
|
-
self.RI.grid(row=1, column=0, sticky="nswe")
|
4339
|
-
self.CH.grid(row=0, column=1, sticky="nswe")
|
4364
|
+
if canvas in ("all", "table"):
|
4340
4365
|
self.MT.grid(row=1, column=1, sticky="nswe")
|
4341
|
-
|
4342
|
-
self.xscroll.grid(row=2, column=0, columnspan=2, sticky="nswe")
|
4343
|
-
self.MT["xscrollcommand"] = self.xscroll.set
|
4344
|
-
self.CH["xscrollcommand"] = self.xscroll.set
|
4345
|
-
self.MT["yscrollcommand"] = self.yscroll.set
|
4346
|
-
self.RI["yscrollcommand"] = self.yscroll.set
|
4347
|
-
self.xscroll_showing = True
|
4348
|
-
self.yscroll_showing = True
|
4349
|
-
self.xscroll_disabled = False
|
4350
|
-
self.yscroll_disabled = False
|
4351
|
-
elif canvas in ("row_index", "index"):
|
4366
|
+
if canvas in ("all", "row_index", "index"):
|
4352
4367
|
self.RI.grid(row=1, column=0, sticky="nswe")
|
4353
4368
|
self.MT["yscrollcommand"] = self.yscroll.set
|
4354
4369
|
self.RI["yscrollcommand"] = self.yscroll.set
|
4355
4370
|
self.MT.show_index = True
|
4356
|
-
|
4371
|
+
if self.MT.show_header:
|
4372
|
+
self.show("top_left")
|
4373
|
+
if canvas in ("all", "header"):
|
4357
4374
|
self.CH.grid(row=0, column=1, sticky="nswe")
|
4358
4375
|
self.MT["xscrollcommand"] = self.xscroll.set
|
4359
4376
|
self.CH["xscrollcommand"] = self.xscroll.set
|
4360
4377
|
self.MT.show_header = True
|
4361
|
-
|
4378
|
+
if self.MT.show_index:
|
4379
|
+
self.show("top_left")
|
4380
|
+
if canvas in ("all", "top_left"):
|
4362
4381
|
self.TL.grid(row=0, column=0)
|
4363
|
-
|
4382
|
+
if canvas in ("all", "x_scrollbar"):
|
4364
4383
|
self.xscroll.grid(row=2, column=0, columnspan=2, sticky="nswe")
|
4365
4384
|
self.xscroll_showing = True
|
4366
4385
|
self.xscroll_disabled = False
|
4367
|
-
|
4386
|
+
if canvas in ("all", "y_scrollbar"):
|
4368
4387
|
self.yscroll.grid(row=0, column=2, rowspan=3, sticky="nswe")
|
4369
4388
|
self.yscroll_showing = True
|
4370
4389
|
self.yscroll_disabled = False
|
4371
|
-
self.
|
4390
|
+
if self._startup_complete:
|
4391
|
+
self.MT.update_idletasks()
|
4392
|
+
return self
|
4393
|
+
|
4394
|
+
def hide(
|
4395
|
+
self,
|
4396
|
+
canvas: Literal[
|
4397
|
+
"all",
|
4398
|
+
"row_index",
|
4399
|
+
"header",
|
4400
|
+
"top_left",
|
4401
|
+
"x_scrollbar",
|
4402
|
+
"y_scrollbar",
|
4403
|
+
"table",
|
4404
|
+
] = "all",
|
4405
|
+
) -> Sheet:
|
4406
|
+
if canvas in ("all", "row_index"):
|
4407
|
+
self.RI.grid_remove()
|
4408
|
+
self.RI["yscrollcommand"] = 0
|
4409
|
+
self.MT.show_index = False
|
4410
|
+
if not self.ops.show_top_left:
|
4411
|
+
self.hide("top_left")
|
4412
|
+
if canvas in ("all", "header"):
|
4413
|
+
self.CH.grid_remove()
|
4414
|
+
self.CH["xscrollcommand"] = 0
|
4415
|
+
self.MT.show_header = False
|
4416
|
+
if not self.ops.show_top_left:
|
4417
|
+
self.hide("top_left")
|
4418
|
+
if canvas in ("all", "top_left"):
|
4419
|
+
self.TL.grid_remove()
|
4420
|
+
if canvas in ("all", "x_scrollbar"):
|
4421
|
+
self.xscroll.grid_remove()
|
4422
|
+
self.xscroll_showing = False
|
4423
|
+
self.xscroll_disabled = True
|
4424
|
+
if canvas in ("all", "y_scrollbar"):
|
4425
|
+
self.yscroll.grid_remove()
|
4426
|
+
self.yscroll_showing = False
|
4427
|
+
self.yscroll_disabled = True
|
4428
|
+
if canvas in ("all", "table"):
|
4429
|
+
self.MT.grid_remove()
|
4372
4430
|
return self
|
4373
4431
|
|
4374
4432
|
# Sheet Height and Width
|
@@ -4504,6 +4562,8 @@ class Sheet(tk.Frame):
|
|
4504
4562
|
if "expand_sheet_if_paste_too_big" in kwargs:
|
4505
4563
|
self.ops.paste_can_expand_x = kwargs["expand_sheet_if_paste_too_big"]
|
4506
4564
|
self.ops.paste_can_expand_y = kwargs["expand_sheet_if_paste_too_big"]
|
4565
|
+
if "show_top_left" in kwargs:
|
4566
|
+
self.show("top_left")
|
4507
4567
|
if "font" in kwargs:
|
4508
4568
|
self.MT.set_table_font(kwargs["font"])
|
4509
4569
|
elif "table_font" in kwargs:
|
@@ -4539,7 +4599,7 @@ class Sheet(tk.Frame):
|
|
4539
4599
|
self.set_scrollbar_options()
|
4540
4600
|
self.MT.create_rc_menus()
|
4541
4601
|
if "treeview" in kwargs:
|
4542
|
-
self.index_align("
|
4602
|
+
self.index_align("nw", redraw=False)
|
4543
4603
|
return self.set_refresh_timer(redraw)
|
4544
4604
|
|
4545
4605
|
def set_scrollbar_options(self) -> Sheet:
|
@@ -4596,15 +4656,7 @@ class Sheet(tk.Frame):
|
|
4596
4656
|
self,
|
4597
4657
|
row: int,
|
4598
4658
|
column: int | str,
|
4599
|
-
key: None
|
4600
|
-
| Literal[
|
4601
|
-
"format",
|
4602
|
-
"highlight",
|
4603
|
-
"dropdown",
|
4604
|
-
"checkbox",
|
4605
|
-
"readonly",
|
4606
|
-
"align",
|
4607
|
-
] = None,
|
4659
|
+
key: None | CellPropertyKey = None,
|
4608
4660
|
cellops: bool = True,
|
4609
4661
|
rowops: bool = True,
|
4610
4662
|
columnops: bool = True,
|
@@ -4638,15 +4690,7 @@ class Sheet(tk.Frame):
|
|
4638
4690
|
def index_props(
|
4639
4691
|
self,
|
4640
4692
|
row: int,
|
4641
|
-
key: None
|
4642
|
-
| Literal[
|
4643
|
-
"format",
|
4644
|
-
"highlight",
|
4645
|
-
"dropdown",
|
4646
|
-
"checkbox",
|
4647
|
-
"readonly",
|
4648
|
-
"align",
|
4649
|
-
] = None,
|
4693
|
+
key: None | CellPropertyKey = None,
|
4650
4694
|
) -> dict:
|
4651
4695
|
"""
|
4652
4696
|
Retrieve options (properties - props)
|
@@ -4662,15 +4706,7 @@ class Sheet(tk.Frame):
|
|
4662
4706
|
def header_props(
|
4663
4707
|
self,
|
4664
4708
|
column: int | str,
|
4665
|
-
key: None
|
4666
|
-
| Literal[
|
4667
|
-
"format",
|
4668
|
-
"highlight",
|
4669
|
-
"dropdown",
|
4670
|
-
"checkbox",
|
4671
|
-
"readonly",
|
4672
|
-
"align",
|
4673
|
-
] = None,
|
4709
|
+
key: None | CellPropertyKey = None,
|
4674
4710
|
) -> dict:
|
4675
4711
|
"""
|
4676
4712
|
Retrieve options (properties - props)
|
@@ -4687,7 +4723,7 @@ class Sheet(tk.Frame):
|
|
4687
4723
|
|
4688
4724
|
def get_cell_options(
|
4689
4725
|
self,
|
4690
|
-
key: None |
|
4726
|
+
key: None | CellPropertyKey = None,
|
4691
4727
|
canvas: Literal["table", "row_index", "index", "header"] = "table",
|
4692
4728
|
) -> dict:
|
4693
4729
|
if canvas == "table":
|
@@ -4700,22 +4736,22 @@ class Sheet(tk.Frame):
|
|
4700
4736
|
return target
|
4701
4737
|
return {k: v[key] for k, v in target.items() if key in v}
|
4702
4738
|
|
4703
|
-
def get_row_options(self, key: None |
|
4739
|
+
def get_row_options(self, key: None | CellPropertyKey = None) -> dict:
|
4704
4740
|
if key is None:
|
4705
4741
|
return self.MT.row_options
|
4706
4742
|
return {k: v[key] for k, v in self.MT.row_options.items() if key in v}
|
4707
4743
|
|
4708
|
-
def get_column_options(self, key: None |
|
4744
|
+
def get_column_options(self, key: None | CellPropertyKey = None) -> dict:
|
4709
4745
|
if key is None:
|
4710
4746
|
return self.MT.col_options
|
4711
4747
|
return {k: v[key] for k, v in self.MT.col_options.items() if key in v}
|
4712
4748
|
|
4713
|
-
def get_index_options(self, key: None |
|
4749
|
+
def get_index_options(self, key: None | CellPropertyKey = None) -> dict:
|
4714
4750
|
if key is None:
|
4715
4751
|
return self.RI.cell_options
|
4716
4752
|
return {k: v[key] for k, v in self.RI.cell_options.items() if key in v}
|
4717
4753
|
|
4718
|
-
def get_header_options(self, key: None |
|
4754
|
+
def get_header_options(self, key: None | CellPropertyKey = None) -> dict:
|
4719
4755
|
if key is None:
|
4720
4756
|
return self.CH.cell_options
|
4721
4757
|
return {k: v[key] for k, v in self.CH.cell_options.items() if key in v}
|
@@ -4983,94 +5019,21 @@ class Sheet(tk.Frame):
|
|
4983
5019
|
include_parent_column: bool = True,
|
4984
5020
|
include_text_column: bool = True,
|
4985
5021
|
) -> Sheet:
|
4986
|
-
self.
|
4987
|
-
|
4988
|
-
|
4989
|
-
|
4990
|
-
|
4991
|
-
ncols = max(map(len, data), default=0)
|
4992
|
-
for rn, row in enumerate(data):
|
4993
|
-
if safety and ncols > (lnr := len(row)):
|
4994
|
-
row += self.MT.get_empty_row_seq(rn, end=ncols, start=lnr)
|
4995
|
-
if lower:
|
4996
|
-
iid = row[iid_column].lower()
|
4997
|
-
pid = row[parent_column].lower()
|
4998
|
-
else:
|
4999
|
-
iid = row[iid_column]
|
5000
|
-
pid = row[parent_column]
|
5001
|
-
if safety:
|
5002
|
-
if not iid:
|
5003
|
-
continue
|
5004
|
-
tally_of_ids[iid] += 1
|
5005
|
-
if tally_of_ids[iid]:
|
5006
|
-
x = 1
|
5007
|
-
while iid in tally_of_ids:
|
5008
|
-
new = f"{row[iid_column]}_DUPLICATED_{x}"
|
5009
|
-
iid = new.lower() if lower else new
|
5010
|
-
x += 1
|
5011
|
-
tally_of_ids[iid] += 1
|
5012
|
-
row[iid_column] = new
|
5013
|
-
if iid in self.RI.tree:
|
5014
|
-
self.RI.tree[iid].text = row[text_column] if isinstance(text_column, int) else text_column[rn]
|
5015
|
-
else:
|
5016
|
-
self.RI.tree[iid] = Node(row[text_column] if isinstance(text_column, int) else text_column[rn], iid, "")
|
5017
|
-
if safety and (iid == pid or self.RI.build_pid_causes_recursive_loop(iid, pid)):
|
5018
|
-
row[parent_column] = ""
|
5019
|
-
pid = ""
|
5020
|
-
if pid:
|
5021
|
-
if pid not in self.RI.tree:
|
5022
|
-
self.RI.tree[pid] = Node(row[text_column] if isinstance(text_column, int) else text_column[rn], pid)
|
5023
|
-
self.RI.tree[iid].parent = self.RI.tree[pid]
|
5024
|
-
self.RI.tree[pid].children.append(self.RI.tree[iid])
|
5025
|
-
else:
|
5026
|
-
self.RI.tree[iid].parent = ""
|
5027
|
-
self.RI.tree_rns[iid] = rn
|
5028
|
-
if safety:
|
5029
|
-
for n in self.RI.tree.values():
|
5030
|
-
if n.parent is None:
|
5031
|
-
n.parent = ""
|
5032
|
-
newrow = self.MT.get_empty_row_seq(len(data), ncols)
|
5033
|
-
newrow[iid_column] = n.iid
|
5034
|
-
self.RI.tree_rns[n.iid] = len(data)
|
5035
|
-
data.append(newrow)
|
5036
|
-
insert_rows = partial(
|
5037
|
-
self.insert_rows,
|
5038
|
-
idx=0,
|
5039
|
-
heights={} if row_heights is False else row_heights,
|
5040
|
-
row_index=True,
|
5041
|
-
create_selections=False,
|
5042
|
-
fill=False,
|
5022
|
+
self.RI.tree_build(
|
5023
|
+
data=data,
|
5024
|
+
iid_column=iid_column,
|
5025
|
+
parent_column=parent_column,
|
5026
|
+
text_column=text_column,
|
5043
5027
|
push_ops=push_ops,
|
5044
|
-
|
5028
|
+
row_heights=row_heights,
|
5029
|
+
open_ids=open_ids,
|
5030
|
+
safety=safety,
|
5031
|
+
ncols=ncols,
|
5032
|
+
lower=lower,
|
5033
|
+
include_iid_column=include_iid_column,
|
5034
|
+
include_parent_column=include_parent_column,
|
5035
|
+
include_text_column=include_text_column,
|
5045
5036
|
)
|
5046
|
-
exclude = set()
|
5047
|
-
if not include_iid_column:
|
5048
|
-
exclude.add(iid_column)
|
5049
|
-
if not include_parent_column:
|
5050
|
-
exclude.add(parent_column)
|
5051
|
-
if isinstance(text_column, int) and not include_text_column:
|
5052
|
-
exclude.add(text_column)
|
5053
|
-
if exclude:
|
5054
|
-
insert_rows(
|
5055
|
-
rows=[
|
5056
|
-
[self.RI.tree[iid]] + [e for i, e in enumerate(data[self.RI.tree_rns[iid]]) if i not in exclude]
|
5057
|
-
for iid in self.get_nodes()
|
5058
|
-
]
|
5059
|
-
)
|
5060
|
-
else:
|
5061
|
-
insert_rows(rows=[[self.RI.tree[iid]] + data[self.RI.tree_rns[iid]] for iid in self.get_nodes()])
|
5062
|
-
self.MT.all_rows_displayed = False
|
5063
|
-
self.MT.displayed_rows = list(range(len(self.MT._row_index)))
|
5064
|
-
self.RI.tree_rns = {n.iid: i for i, n in enumerate(self.MT._row_index)}
|
5065
|
-
if open_ids:
|
5066
|
-
self.tree_set_open(open_ids=open_ids)
|
5067
|
-
else:
|
5068
|
-
self.hide_rows(
|
5069
|
-
{self.RI.tree_rns[iid] for iid in self.get_children() if self.RI.tree[iid].parent},
|
5070
|
-
deselect_all=False,
|
5071
|
-
data_indexes=True,
|
5072
|
-
row_heights=False if row_heights is False else True,
|
5073
|
-
)
|
5074
5037
|
return self
|
5075
5038
|
|
5076
5039
|
def tree_reset(self) -> Sheet:
|
@@ -5178,6 +5141,7 @@ class Sheet(tk.Frame):
|
|
5178
5141
|
text: None | str = None,
|
5179
5142
|
values: None | list[object] = None,
|
5180
5143
|
create_selections: bool = False,
|
5144
|
+
undo: bool = True,
|
5181
5145
|
) -> str:
|
5182
5146
|
"""
|
5183
5147
|
Insert an item into the treeview
|
@@ -5186,9 +5150,7 @@ class Sheet(tk.Frame):
|
|
5186
5150
|
str: new item iid
|
5187
5151
|
"""
|
5188
5152
|
if not iid:
|
5189
|
-
|
5190
|
-
while (iid := f"{num2alpha(i)}") in self.RI.tree:
|
5191
|
-
i += 1
|
5153
|
+
iid = self.RI.new_iid()
|
5192
5154
|
if iid in self.RI.tree:
|
5193
5155
|
raise ValueError(f"iid '{iid}' already exists.")
|
5194
5156
|
if iid == parent:
|
@@ -5197,18 +5159,37 @@ class Sheet(tk.Frame):
|
|
5197
5159
|
raise ValueError(f"parent '{parent}' does not exist.")
|
5198
5160
|
if text is None:
|
5199
5161
|
text = iid
|
5200
|
-
|
5201
|
-
|
5202
|
-
|
5162
|
+
new_node = Node(text, iid, parent)
|
5163
|
+
datarn = self._get_id_insert_row(index=index, parent=parent)
|
5164
|
+
self.insert_rows(
|
5165
|
+
rows=[[new_node] + ([] if values is None else values)],
|
5166
|
+
idx=datarn,
|
5167
|
+
row_index=True,
|
5168
|
+
create_selections=create_selections,
|
5169
|
+
fill=False,
|
5170
|
+
undo=undo,
|
5171
|
+
tree=True,
|
5172
|
+
)
|
5173
|
+
# only relevant here because in rc add rows they are visible and undo sets old open_ids
|
5174
|
+
if parent and (parent not in self.RI.tree_open_ids or not self.item_displayed(parent)):
|
5175
|
+
self.hide_rows(datarn, deselect_all=False, data_indexes=True)
|
5176
|
+
return iid
|
5177
|
+
|
5178
|
+
def _get_id_insert_row(self, index: int, parent: str) -> int:
|
5179
|
+
if parent:
|
5203
5180
|
if isinstance(index, int):
|
5204
|
-
|
5205
|
-
datarn
|
5206
|
-
|
5181
|
+
index = min(index, len(self.RI.tree[parent].children))
|
5182
|
+
datarn = (
|
5183
|
+
self.RI.tree_rns[parent]
|
5184
|
+
+ index
|
5185
|
+
+ 1
|
5186
|
+
+ sum(
|
5187
|
+
sum(1 for _ in self.RI.get_iid_descendants(cid))
|
5188
|
+
for cid in islice(self.get_children(parent), index)
|
5189
|
+
)
|
5207
5190
|
)
|
5208
|
-
self.RI.tree[parent].children.insert(index, self.RI.tree[iid])
|
5209
5191
|
else:
|
5210
5192
|
datarn = self.RI.tree_rns[parent] + sum(1 for _ in self.RI.get_iid_descendants(parent)) + 1
|
5211
|
-
self.RI.tree[parent].children.append(self.RI.tree[iid])
|
5212
5193
|
else:
|
5213
5194
|
if isinstance(index, int):
|
5214
5195
|
datarn = index
|
@@ -5216,19 +5197,7 @@ class Sheet(tk.Frame):
|
|
5216
5197
|
datarn = len(self.MT._row_index)
|
5217
5198
|
else:
|
5218
5199
|
datarn = len(self.MT._row_index)
|
5219
|
-
|
5220
|
-
values = []
|
5221
|
-
self.insert_rows(
|
5222
|
-
rows=[[self.RI.tree[iid]] + values],
|
5223
|
-
idx=datarn,
|
5224
|
-
row_index=True,
|
5225
|
-
create_selections=create_selections,
|
5226
|
-
fill=False,
|
5227
|
-
)
|
5228
|
-
self.RI.tree_rns[iid] = datarn
|
5229
|
-
if parent and (parent not in self.RI.tree_open_ids or not self.item_displayed(parent)):
|
5230
|
-
self.hide_rows(datarn, deselect_all=False, data_indexes=True)
|
5231
|
-
return iid
|
5200
|
+
return datarn
|
5232
5201
|
|
5233
5202
|
def bulk_insert(
|
5234
5203
|
self,
|
@@ -5240,6 +5209,7 @@ class Sheet(tk.Frame):
|
|
5240
5209
|
create_selections: bool = False,
|
5241
5210
|
include_iid_column: bool = True,
|
5242
5211
|
include_text_column: bool = True,
|
5212
|
+
undo: bool = True,
|
5243
5213
|
) -> dict[str, int]:
|
5244
5214
|
"""
|
5245
5215
|
Insert multiple items into the treeview at once, under the same parent.
|
@@ -5250,52 +5220,29 @@ class Sheet(tk.Frame):
|
|
5250
5220
|
- Values (int): row numbers
|
5251
5221
|
"""
|
5252
5222
|
to_insert = []
|
5253
|
-
|
5254
|
-
if pid and pid not in self.RI.tree:
|
5223
|
+
if parent and parent not in self.RI.tree:
|
5255
5224
|
raise ValueError(f"parent '{parent}' does not exist.")
|
5256
|
-
|
5257
|
-
if parent_node:
|
5258
|
-
if isinstance(index, int):
|
5259
|
-
datarn = self.RI.tree_rns[pid] + index + 1
|
5260
|
-
datarn += sum(
|
5261
|
-
sum(1 for _ in self.RI.get_iid_descendants(cid)) for cid in islice(self.get_children(pid), index)
|
5262
|
-
)
|
5263
|
-
else:
|
5264
|
-
datarn = self.RI.tree_rns[pid] + sum(1 for _ in self.RI.get_iid_descendants(pid)) + 1
|
5265
|
-
else:
|
5266
|
-
if isinstance(index, int):
|
5267
|
-
datarn = index
|
5268
|
-
if index and (datarn := self.top_index_row(datarn)) is None:
|
5269
|
-
datarn = len(self.MT._row_index)
|
5270
|
-
else:
|
5271
|
-
datarn = len(self.MT._row_index)
|
5272
|
-
i = 0
|
5225
|
+
datarn = self._get_id_insert_row(index=index, parent=parent)
|
5273
5226
|
rns_to_add = {}
|
5274
5227
|
for rn, r in enumerate(data, start=datarn):
|
5275
5228
|
if iid_column is None:
|
5276
|
-
|
5277
|
-
i += 1
|
5229
|
+
iid = self.RI.new_iid()
|
5278
5230
|
else:
|
5279
5231
|
iid = r[iid_column]
|
5280
|
-
|
5232
|
+
new_node = Node(
|
5281
5233
|
r[text_column] if isinstance(text_column, int) else text_column if isinstance(text_column, str) else "",
|
5282
5234
|
iid,
|
5283
|
-
|
5235
|
+
parent,
|
5284
5236
|
)
|
5285
|
-
if parent_node:
|
5286
|
-
if isinstance(index, int):
|
5287
|
-
self.RI.tree[pid].children.insert(index, self.RI.tree[iid])
|
5288
|
-
else:
|
5289
|
-
self.RI.tree[pid].children.append(self.RI.tree[iid])
|
5290
5237
|
exclude = set()
|
5291
5238
|
if isinstance(iid_column, int) and not include_iid_column:
|
5292
5239
|
exclude.add(iid_column)
|
5293
5240
|
if isinstance(text_column, int) and not include_text_column:
|
5294
5241
|
exclude.add(text_column)
|
5295
5242
|
if exclude:
|
5296
|
-
to_insert.append([
|
5243
|
+
to_insert.append([new_node] + [e for c, e in enumerate(r) if c not in exclude])
|
5297
5244
|
else:
|
5298
|
-
to_insert.append([
|
5245
|
+
to_insert.append([new_node] + r)
|
5299
5246
|
rns_to_add[iid] = rn
|
5300
5247
|
self.insert_rows(
|
5301
5248
|
rows=to_insert,
|
@@ -5303,10 +5250,10 @@ class Sheet(tk.Frame):
|
|
5303
5250
|
row_index=True,
|
5304
5251
|
create_selections=create_selections,
|
5305
5252
|
fill=False,
|
5253
|
+
undo=undo,
|
5254
|
+
tree=True,
|
5306
5255
|
)
|
5307
|
-
|
5308
|
-
self.RI.tree_rns[iid] = rn
|
5309
|
-
if pid and (pid not in self.RI.tree_open_ids or not self.item_displayed(pid)):
|
5256
|
+
if parent and (parent not in self.RI.tree_open_ids or not self.item_displayed(parent)):
|
5310
5257
|
self.hide_rows(range(datarn, datarn + len(to_insert)), deselect_all=False, data_indexes=True)
|
5311
5258
|
return rns_to_add
|
5312
5259
|
|
@@ -5393,9 +5340,9 @@ class Sheet(tk.Frame):
|
|
5393
5340
|
elif item == "":
|
5394
5341
|
yield from map(attrgetter("iid"), self.RI.gen_top_nodes())
|
5395
5342
|
else:
|
5396
|
-
yield from
|
5343
|
+
yield from self.RI.tree[item].children
|
5397
5344
|
|
5398
|
-
def
|
5345
|
+
def get_iids(self, item: None | str = None) -> Generator[str]:
|
5399
5346
|
if item is None:
|
5400
5347
|
for n in self.RI.tree.values():
|
5401
5348
|
if not n.parent:
|
@@ -5404,31 +5351,16 @@ class Sheet(tk.Frame):
|
|
5404
5351
|
elif item == "":
|
5405
5352
|
yield from (n.iid for n in self.RI.tree.values() if not n.parent)
|
5406
5353
|
else:
|
5407
|
-
yield from
|
5354
|
+
yield from self.RI.tree[item].children
|
5408
5355
|
|
5409
|
-
def del_items(self, *items) -> Sheet:
|
5356
|
+
def del_items(self, *items, undo: bool = True) -> Sheet:
|
5410
5357
|
"""
|
5411
5358
|
Also deletes all descendants of items
|
5412
5359
|
"""
|
5413
|
-
|
5414
|
-
|
5415
|
-
|
5416
|
-
|
5417
|
-
continue
|
5418
|
-
rows_to_del.append(self.RI.tree_rns[item])
|
5419
|
-
iids_to_del.append(item)
|
5420
|
-
for did in self.RI.get_iid_descendants(item):
|
5421
|
-
rows_to_del.append(self.RI.tree_rns[did])
|
5422
|
-
iids_to_del.append(did)
|
5423
|
-
for item in unpack(items):
|
5424
|
-
self.RI.remove_node_from_parents_children(self.RI.tree[item])
|
5425
|
-
self.del_rows(rows_to_del)
|
5426
|
-
for iid in iids_to_del:
|
5427
|
-
self.RI.tree_open_ids.discard(iid)
|
5428
|
-
if self.RI.tree[iid].parent and len(self.RI.tree[iid].parent.children) == 1:
|
5429
|
-
self.RI.tree_open_ids.discard(self.RI.tree[iid].parent.iid)
|
5430
|
-
del self.RI.tree[iid]
|
5431
|
-
return self.set_refresh_timer()
|
5360
|
+
rows = list(map(self.RI.tree_rns.get, filter(self.exists, unpack(items))))
|
5361
|
+
if rows:
|
5362
|
+
self.del_rows(rows, data_indexes=True, undo=undo)
|
5363
|
+
return self.set_refresh_timer(rows)
|
5432
5364
|
|
5433
5365
|
def set_children(self, parent: str, *newchildren) -> Sheet:
|
5434
5366
|
"""
|
@@ -5444,123 +5376,42 @@ class Sheet(tk.Frame):
|
|
5444
5376
|
except Exception:
|
5445
5377
|
return None
|
5446
5378
|
|
5447
|
-
def move(
|
5379
|
+
def move(
|
5380
|
+
self,
|
5381
|
+
item: str,
|
5382
|
+
parent: str,
|
5383
|
+
index: int | None = None,
|
5384
|
+
select: bool = True,
|
5385
|
+
undo: bool = True,
|
5386
|
+
emit_event: bool = False,
|
5387
|
+
) -> tuple[dict[int, int], dict[int, int], EventDataDict]:
|
5448
5388
|
"""
|
5449
5389
|
Moves item to be under parent as child at index
|
5450
5390
|
'parent' can be an empty str which will put the item at top level
|
5451
|
-
Performance is not great
|
5452
5391
|
"""
|
5453
5392
|
if item not in self.RI.tree:
|
5454
5393
|
raise ValueError(f"Item '{item}' does not exist.")
|
5455
5394
|
if parent and parent not in self.RI.tree:
|
5456
5395
|
raise ValueError(f"Parent '{parent}' does not exist.")
|
5457
|
-
|
5458
|
-
|
5459
|
-
|
5460
|
-
|
5461
|
-
|
5462
|
-
|
5463
|
-
|
5464
|
-
|
5465
|
-
|
5466
|
-
|
5467
|
-
|
5468
|
-
|
5469
|
-
index = len(parent_node.children)
|
5470
|
-
new_r = self.RI.tree_rns[parent] + sum(1 for _ in self.RI.get_iid_descendants(parent))
|
5471
|
-
# new parent has children
|
5472
|
-
# index is on end
|
5473
|
-
# item row is less than move to row
|
5474
|
-
if item_r < new_r:
|
5475
|
-
r_ctr = new_r - num_item_descendants
|
5476
|
-
|
5477
|
-
# new parent has children
|
5478
|
-
# index is on end
|
5479
|
-
# item row is greater than move to row
|
5480
|
-
else:
|
5481
|
-
r_ctr = new_r + 1
|
5482
|
-
else:
|
5483
|
-
new_r = self.RI.tree_rns[parent_node.children[index].iid]
|
5484
|
-
# new parent has children
|
5485
|
-
# index is not end
|
5486
|
-
# item row is less than move to row
|
5487
|
-
if item_r < new_r:
|
5488
|
-
if self.RI.items_parent(item) == parent:
|
5489
|
-
r_ctr = (
|
5490
|
-
new_r
|
5491
|
-
+ sum(1 for _ in self.RI.get_iid_descendants(parent_node.children[index].iid))
|
5492
|
-
- num_item_descendants
|
5493
|
-
)
|
5494
|
-
else:
|
5495
|
-
r_ctr = new_r - num_item_descendants - 1
|
5496
|
-
|
5497
|
-
# new parent has children
|
5498
|
-
# index is not end
|
5499
|
-
# item row is greater than move to row
|
5500
|
-
else:
|
5501
|
-
r_ctr = new_r
|
5502
|
-
else:
|
5503
|
-
index = 0
|
5504
|
-
new_r = self.RI.tree_rns[parent_node.iid]
|
5505
|
-
|
5506
|
-
# new parent doesn't have children
|
5507
|
-
# index always start
|
5508
|
-
# item row is less than move to row
|
5509
|
-
if item_r < new_r:
|
5510
|
-
r_ctr = new_r - num_item_descendants
|
5511
|
-
|
5512
|
-
# new parent doesn't have children
|
5513
|
-
# index always start
|
5514
|
-
# item row is greater than move to row
|
5515
|
-
else:
|
5516
|
-
r_ctr = new_r + 1
|
5517
|
-
mapping[item_r] = r_ctr
|
5518
|
-
if parent in self.RI.tree_open_ids and self.item_displayed(parent):
|
5519
|
-
to_show.append(r_ctr)
|
5520
|
-
r_ctr += 1
|
5521
|
-
for did in item_descendants:
|
5522
|
-
mapping[self.RI.tree_rns[did]] = r_ctr
|
5523
|
-
if to_show and self.RI.ancestors_all_open(did, item_node.parent):
|
5524
|
-
to_show.append(r_ctr)
|
5525
|
-
r_ctr += 1
|
5526
|
-
if parent == self.RI.items_parent(item):
|
5527
|
-
pop_index = parent_node.children.index(item_node)
|
5528
|
-
parent_node.children.insert(index, parent_node.children.pop(pop_index))
|
5529
|
-
else:
|
5530
|
-
self.RI.remove_node_from_parents_children(item_node)
|
5531
|
-
item_node.parent = parent_node
|
5532
|
-
parent_node.children.insert(index, item_node)
|
5533
|
-
else:
|
5534
|
-
if index is None or (new_r := self.top_index_row(index)) is None:
|
5535
|
-
new_r = self.top_index_row(sum(1 for _ in self.RI.gen_top_nodes()) - 1)
|
5536
|
-
if item_r < new_r:
|
5537
|
-
r_ctr = (
|
5538
|
-
new_r
|
5539
|
-
+ sum(1 for _ in self.RI.get_iid_descendants(self.rowitem(new_r, data_index=True)))
|
5540
|
-
- num_item_descendants
|
5541
|
-
)
|
5542
|
-
else:
|
5543
|
-
r_ctr = new_r
|
5544
|
-
mapping[item_r] = r_ctr
|
5545
|
-
to_show.append(r_ctr)
|
5546
|
-
r_ctr += 1
|
5547
|
-
for did in item_descendants:
|
5548
|
-
mapping[self.RI.tree_rns[did]] = r_ctr
|
5549
|
-
if to_show and self.RI.ancestors_all_open(did, item_node.parent):
|
5550
|
-
to_show.append(r_ctr)
|
5551
|
-
r_ctr += 1
|
5552
|
-
self.RI.remove_node_from_parents_children(item_node)
|
5553
|
-
self.RI.tree[item].parent = ""
|
5554
|
-
self.mapping_move_rows(
|
5555
|
-
data_new_idxs=mapping,
|
5556
|
-
data_indexes=True,
|
5557
|
-
create_selections=False,
|
5558
|
-
redraw=False,
|
5396
|
+
if self.RI.move_pid_causes_recursive_loop(item, parent):
|
5397
|
+
raise ValueError(f"Item '{item}' causes recursive loop with parent '{parent}.")
|
5398
|
+
data_new_idxs, disp_new_idxs, event_data = self.MT.move_rows_adjust_options_dict(
|
5399
|
+
data_new_idxs={},
|
5400
|
+
data_old_idxs={},
|
5401
|
+
totalrows=None,
|
5402
|
+
disp_new_idxs={},
|
5403
|
+
move_data=True,
|
5404
|
+
move_heights=True,
|
5405
|
+
create_selections=select,
|
5406
|
+
event_data=None,
|
5407
|
+
node_change=(item, parent, index),
|
5559
5408
|
)
|
5560
|
-
if
|
5561
|
-
self.
|
5562
|
-
|
5563
|
-
|
5409
|
+
if undo:
|
5410
|
+
self.MT.undo_stack.append(stored_event_dict(event_data))
|
5411
|
+
if emit_event:
|
5412
|
+
self.emit_event("<<SheetModified>>", event_data)
|
5413
|
+
self.set_refresh_timer()
|
5414
|
+
return data_new_idxs, disp_new_idxs, event_data
|
5564
5415
|
|
5565
5416
|
reattach = move
|
5566
5417
|
|
@@ -5570,15 +5421,16 @@ class Sheet(tk.Frame):
|
|
5570
5421
|
def parent(self, item: str) -> str:
|
5571
5422
|
if item not in self.RI.tree:
|
5572
5423
|
raise ValueError(f"Item '{item}' does not exist.")
|
5573
|
-
return self.RI.tree[item].parent
|
5424
|
+
return self.RI.tree[item].parent
|
5574
5425
|
|
5575
5426
|
def index(self, item: str) -> int:
|
5576
5427
|
if item not in self.RI.tree:
|
5577
5428
|
raise ValueError(f"Item '{item}' does not exist.")
|
5578
|
-
|
5429
|
+
elif self.RI.tree[item].parent:
|
5430
|
+
return self.RI.parent_node(item).children.index(item)
|
5431
|
+
else:
|
5579
5432
|
find_node = self.RI.tree[item]
|
5580
5433
|
return next(index for index, node in enumerate(self.RI.gen_top_nodes()) if node == find_node)
|
5581
|
-
return self.RI.tree[item].parent.children.index(self.RI.tree[item])
|
5582
5434
|
|
5583
5435
|
def item_displayed(self, item: str) -> bool:
|
5584
5436
|
"""
|
@@ -5587,7 +5439,7 @@ class Sheet(tk.Frame):
|
|
5587
5439
|
"""
|
5588
5440
|
if item not in self.RI.tree:
|
5589
5441
|
raise ValueError(f"Item '{item}' does not exist.")
|
5590
|
-
return self.RI.tree_rns[item]
|
5442
|
+
return bisect_in(self.MT.displayed_rows, self.RI.tree_rns[item])
|
5591
5443
|
|
5592
5444
|
def display_item(self, item: str, redraw: bool = False) -> Sheet:
|
5593
5445
|
"""
|
@@ -5996,7 +5848,7 @@ class Sheet(tk.Frame):
|
|
5996
5848
|
def set_row_data(
|
5997
5849
|
self,
|
5998
5850
|
r: int,
|
5999
|
-
values=
|
5851
|
+
values: Sequence[object] = [],
|
6000
5852
|
add_columns: bool = True,
|
6001
5853
|
redraw: bool = True,
|
6002
5854
|
keep_formatting: bool = True,
|
@@ -6014,7 +5866,7 @@ class Sheet(tk.Frame):
|
|
6014
5866
|
if c > maxidx:
|
6015
5867
|
self.MT.data[r].append(v)
|
6016
5868
|
if self.MT.all_columns_displayed:
|
6017
|
-
self.MT.
|
5869
|
+
self.MT.insert_col_positions()
|
6018
5870
|
else:
|
6019
5871
|
self.set_cell_data(r=r, c=c, value=v, redraw=False, keep_formatting=keep_formatting)
|
6020
5872
|
else:
|
@@ -6028,7 +5880,7 @@ class Sheet(tk.Frame):
|
|
6028
5880
|
def set_column_data(
|
6029
5881
|
self,
|
6030
5882
|
c: int,
|
6031
|
-
values=
|
5883
|
+
values: Sequence[object] = [],
|
6032
5884
|
add_rows: bool = True,
|
6033
5885
|
redraw: bool = True,
|
6034
5886
|
keep_formatting: bool = True,
|
@@ -6045,7 +5897,7 @@ class Sheet(tk.Frame):
|
|
6045
5897
|
total_cols = self.MT.total_data_cols()
|
6046
5898
|
self.MT.fix_data_len(rn, total_cols - 1)
|
6047
5899
|
if self.MT.all_rows_displayed:
|
6048
|
-
self.MT.
|
5900
|
+
self.MT.insert_row_positions(heights=height)
|
6049
5901
|
maxidx += 1
|
6050
5902
|
if c >= len(self.MT.data[rn]):
|
6051
5903
|
self.MT.fix_row_len(rn, c)
|
@@ -7043,7 +6895,6 @@ class Sheet(tk.Frame):
|
|
7043
6895
|
self.RI.dropdown.window.values(values)
|
7044
6896
|
if set_value is not None:
|
7045
6897
|
self.MT.row_index(newindex=set_value, index=r_)
|
7046
|
-
# here
|
7047
6898
|
return self
|
7048
6899
|
|
7049
6900
|
def get_dropdown_values(self, r: int = 0, c: int = 0) -> None | list:
|
@@ -7273,7 +7124,7 @@ class Dropdown(Sheet):
|
|
7273
7124
|
modified_function: None | Callable = None,
|
7274
7125
|
arrowkey_RIGHT: Callable | None = None,
|
7275
7126
|
arrowkey_LEFT: Callable | None = None,
|
7276
|
-
align: str = "
|
7127
|
+
align: str = "nw",
|
7277
7128
|
# False for using r, c
|
7278
7129
|
# "r" for r
|
7279
7130
|
# "c" for c
|