psiutils 0.2.19__tar.gz → 0.2.20__tar.gz
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.
- {psiutils-0.2.19 → psiutils-0.2.20}/PKG-INFO +1 -1
- {psiutils-0.2.19 → psiutils-0.2.20}/pyproject.toml +1 -1
- psiutils-0.2.20/src/psiutils/_version.py +1 -0
- {psiutils-0.2.19 → psiutils-0.2.20}/src/psiutils/buttons.py +1 -0
- psiutils-0.2.20/src/psiutils/icons/checkbox_checked.png +0 -0
- psiutils-0.2.20/src/psiutils/icons/checkbox_unchecked.png +0 -0
- psiutils-0.2.20/src/psiutils/icons/upload.png +0 -0
- {psiutils-0.2.19 → psiutils-0.2.20}/src/psiutils/text.py +1 -0
- psiutils-0.2.20/src/psiutils/treeview.py +149 -0
- psiutils-0.2.19/src/psiutils/_version.py +0 -1
- psiutils-0.2.19/src/psiutils/treeview.py +0 -85
- {psiutils-0.2.19 → psiutils-0.2.20}/README.md +0 -0
- {psiutils-0.2.19 → psiutils-0.2.20}/src/psiutils/__init__.py +0 -0
- {psiutils-0.2.19 → psiutils-0.2.20}/src/psiutils/_about_frame.py +0 -0
- {psiutils-0.2.19 → psiutils-0.2.20}/src/psiutils/_date_picker.py +0 -0
- {psiutils-0.2.19 → psiutils-0.2.20}/src/psiutils/_logger.py +0 -0
- {psiutils-0.2.19 → psiutils-0.2.20}/src/psiutils/_notify.py +0 -0
- {psiutils-0.2.19 → psiutils-0.2.20}/src/psiutils/constants.py +0 -0
- {psiutils-0.2.19 → psiutils-0.2.20}/src/psiutils/drag_manager.py +0 -0
- {psiutils-0.2.19 → psiutils-0.2.20}/src/psiutils/errors.py +0 -0
- {psiutils-0.2.19 → psiutils-0.2.20}/src/psiutils/icecream_init.py +0 -0
- {psiutils-0.2.19 → psiutils-0.2.20}/src/psiutils/icons/backup.png +0 -0
- {psiutils-0.2.19 → psiutils-0.2.20}/src/psiutils/icons/build.png +0 -0
- {psiutils-0.2.19 → psiutils-0.2.20}/src/psiutils/icons/cancel.png +0 -0
- {psiutils-0.2.19 → psiutils-0.2.20}/src/psiutils/icons/check.png +0 -0
- {psiutils-0.2.19 → psiutils-0.2.20}/src/psiutils/icons/clear.png +0 -0
- {psiutils-0.2.19 → psiutils-0.2.20}/src/psiutils/icons/code.png +0 -0
- {psiutils-0.2.19 → psiutils-0.2.20}/src/psiutils/icons/compare.png +0 -0
- {psiutils-0.2.19 → psiutils-0.2.20}/src/psiutils/icons/copy_clipboard.png +0 -0
- {psiutils-0.2.19 → psiutils-0.2.20}/src/psiutils/icons/copy_docs.png +0 -0
- {psiutils-0.2.19 → psiutils-0.2.20}/src/psiutils/icons/delete.png +0 -0
- {psiutils-0.2.19 → psiutils-0.2.20}/src/psiutils/icons/diff.png +0 -0
- {psiutils-0.2.19 → psiutils-0.2.20}/src/psiutils/icons/done.png +0 -0
- {psiutils-0.2.19 → psiutils-0.2.20}/src/psiutils/icons/download.png +0 -0
- {psiutils-0.2.19 → psiutils-0.2.20}/src/psiutils/icons/edit.png +0 -0
- {psiutils-0.2.19 → psiutils-0.2.20}/src/psiutils/icons/gear.png +0 -0
- {psiutils-0.2.19 → psiutils-0.2.20}/src/psiutils/icons/new.png +0 -0
- {psiutils-0.2.19 → psiutils-0.2.20}/src/psiutils/icons/next.png +0 -0
- {psiutils-0.2.19 → psiutils-0.2.20}/src/psiutils/icons/open.png +0 -0
- {psiutils-0.2.19 → psiutils-0.2.20}/src/psiutils/icons/pause.png +0 -0
- {psiutils-0.2.19 → psiutils-0.2.20}/src/psiutils/icons/preferences.png +0 -0
- {psiutils-0.2.19 → psiutils-0.2.20}/src/psiutils/icons/previous.png +0 -0
- {psiutils-0.2.19 → psiutils-0.2.20}/src/psiutils/icons/process.png +0 -0
- {psiutils-0.2.19 → psiutils-0.2.20}/src/psiutils/icons/redo.png +0 -0
- {psiutils-0.2.19 → psiutils-0.2.20}/src/psiutils/icons/refresh.png +0 -0
- {psiutils-0.2.19 → psiutils-0.2.20}/src/psiutils/icons/rename.png +0 -0
- {psiutils-0.2.19 → psiutils-0.2.20}/src/psiutils/icons/report.png +0 -0
- {psiutils-0.2.19 → psiutils-0.2.20}/src/psiutils/icons/reset.png +0 -0
- {psiutils-0.2.19 → psiutils-0.2.20}/src/psiutils/icons/restore.png +0 -0
- {psiutils-0.2.19 → psiutils-0.2.20}/src/psiutils/icons/restore_database.png +0 -0
- {psiutils-0.2.19 → psiutils-0.2.20}/src/psiutils/icons/restore_page.png +0 -0
- {psiutils-0.2.19 → psiutils-0.2.20}/src/psiutils/icons/revert.png +0 -0
- {psiutils-0.2.19 → psiutils-0.2.20}/src/psiutils/icons/save.png +0 -0
- {psiutils-0.2.19 → psiutils-0.2.20}/src/psiutils/icons/script.png +0 -0
- {psiutils-0.2.19 → psiutils-0.2.20}/src/psiutils/icons/search.png +0 -0
- {psiutils-0.2.19 → psiutils-0.2.20}/src/psiutils/icons/send.png +0 -0
- {psiutils-0.2.19 → psiutils-0.2.20}/src/psiutils/icons/start.png +0 -0
- {psiutils-0.2.19 → psiutils-0.2.20}/src/psiutils/icons/update.png +0 -0
- {psiutils-0.2.19 → psiutils-0.2.20}/src/psiutils/icons/upgrade.png +0 -0
- {psiutils-0.2.19 → psiutils-0.2.20}/src/psiutils/icons/windows.png +0 -0
- {psiutils-0.2.19 → psiutils-0.2.20}/src/psiutils/images/icon-error.png +0 -0
- {psiutils-0.2.19 → psiutils-0.2.20}/src/psiutils/images/icon-info.png +0 -0
- {psiutils-0.2.19 → psiutils-0.2.20}/src/psiutils/images/icon-query.png +0 -0
- {psiutils-0.2.19 → psiutils-0.2.20}/src/psiutils/known_paths.py +0 -0
- {psiutils-0.2.19 → psiutils-0.2.20}/src/psiutils/menus.py +0 -0
- {psiutils-0.2.19 → psiutils-0.2.20}/src/psiutils/messagebox.py +0 -0
- {psiutils-0.2.19 → psiutils-0.2.20}/src/psiutils/utilities.py +0 -0
- {psiutils-0.2.19 → psiutils-0.2.20}/src/psiutils/widgets.py +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = '0.2.20'
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
import tkinter as tk
|
|
4
|
+
from tkinter import ttk
|
|
5
|
+
import dateutil # type: ignore
|
|
6
|
+
from dateutil.parser import parse # type: ignore
|
|
7
|
+
from PIL import Image, ImageTk
|
|
8
|
+
|
|
9
|
+
CHECK_BOX_SIZE = (20, 20)
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def sort_treeview(tree: ttk.Treeview, col: int, reverse: bool) -> None:
|
|
13
|
+
"""Sort the Treeview by column."""
|
|
14
|
+
children = [
|
|
15
|
+
(tree.set(child, col), child) for child in tree.get_children('')
|
|
16
|
+
]
|
|
17
|
+
is_date = True
|
|
18
|
+
try:
|
|
19
|
+
date_children = []
|
|
20
|
+
for child in children:
|
|
21
|
+
if len(child[0]) < 8:
|
|
22
|
+
is_date = False
|
|
23
|
+
break
|
|
24
|
+
date = parse(child[0])
|
|
25
|
+
date_children.append((date, child[1]))
|
|
26
|
+
except dateutil.parser._parser.ParserError:
|
|
27
|
+
is_date = False
|
|
28
|
+
if is_date:
|
|
29
|
+
children = date_children
|
|
30
|
+
try:
|
|
31
|
+
children.sort(key=lambda t: float(t[0]), reverse=reverse)
|
|
32
|
+
except TypeError:
|
|
33
|
+
children.sort(key=lambda t: t[0], reverse=reverse)
|
|
34
|
+
except ValueError:
|
|
35
|
+
children.sort(reverse=reverse)
|
|
36
|
+
|
|
37
|
+
for index, (val, child) in enumerate(children):
|
|
38
|
+
tree.move(child, '', index)
|
|
39
|
+
|
|
40
|
+
tree.heading(col, command=lambda: sort_treeview(tree, col, not reverse))
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
class CheckTreeView(ttk.Treeview):
|
|
44
|
+
def __init__(
|
|
45
|
+
self,
|
|
46
|
+
master,
|
|
47
|
+
column_defs,
|
|
48
|
+
**kwargs):
|
|
49
|
+
"""
|
|
50
|
+
|
|
51
|
+
:param column_defs: a tuple defining column (key, text, width)
|
|
52
|
+
Other parameters are passed to the `TreeView`.
|
|
53
|
+
"""
|
|
54
|
+
super().__init__(master, **kwargs)
|
|
55
|
+
self.column_defs = column_defs
|
|
56
|
+
self["show"] = "tree headings"
|
|
57
|
+
self._configure_columns()
|
|
58
|
+
|
|
59
|
+
(
|
|
60
|
+
self.unchecked_image,
|
|
61
|
+
self.checked_image
|
|
62
|
+
) = self._get_checkbox_images()
|
|
63
|
+
|
|
64
|
+
if "selectmode" not in kwargs:
|
|
65
|
+
kwargs["selectmode"] = "none"
|
|
66
|
+
if "show" not in kwargs:
|
|
67
|
+
kwargs["show"] = "tree"
|
|
68
|
+
|
|
69
|
+
def _get_checkbox_images(
|
|
70
|
+
self) -> tuple[ImageTk.PhotoImage, ImageTk.PhotoImage]:
|
|
71
|
+
|
|
72
|
+
icon_path = f'{Path(__file__).parent}/icons/'
|
|
73
|
+
unchecked_img = Image.open(f"{icon_path}checkbox_unchecked.png")
|
|
74
|
+
unchecked_img = unchecked_img.resize(CHECK_BOX_SIZE, Image.LANCZOS)
|
|
75
|
+
unchecked = ImageTk.PhotoImage(unchecked_img)
|
|
76
|
+
|
|
77
|
+
checked_img = tk.PhotoImage(file=f"{icon_path}checkbox_checked.png")
|
|
78
|
+
checked_img = Image.open(f"{icon_path}checkbox_checked.png")
|
|
79
|
+
checked_img = checked_img.resize(CHECK_BOX_SIZE, Image.LANCZOS)
|
|
80
|
+
checked = ImageTk.PhotoImage(checked_img)
|
|
81
|
+
return (unchecked, checked)
|
|
82
|
+
|
|
83
|
+
def _configure_columns(self) -> None:
|
|
84
|
+
column_ids = [col[0] for col in self.column_defs]
|
|
85
|
+
self["columns"] = column_ids[1:]
|
|
86
|
+
|
|
87
|
+
# Configure each column
|
|
88
|
+
for index, (col_id, heading, width) in enumerate(self.column_defs):
|
|
89
|
+
if index == 0:
|
|
90
|
+
self.column(
|
|
91
|
+
"#0",
|
|
92
|
+
width=width,
|
|
93
|
+
minwidth=width,
|
|
94
|
+
stretch=False,
|
|
95
|
+
anchor="center")
|
|
96
|
+
self.heading("#0", text=heading)
|
|
97
|
+
else:
|
|
98
|
+
self.column(col_id, width=width, anchor="w", stretch=True)
|
|
99
|
+
self.heading(col_id, text=heading)
|
|
100
|
+
|
|
101
|
+
def populate(self, items: list[tuple], checked: bool = False) -> None:
|
|
102
|
+
self.delete(*self.get_children())
|
|
103
|
+
item_checked = (self.checked_image
|
|
104
|
+
if checked else self.unchecked_image)
|
|
105
|
+
for item in items:
|
|
106
|
+
iid = self.insert(
|
|
107
|
+
parent='',
|
|
108
|
+
index='end',
|
|
109
|
+
image=item_checked,
|
|
110
|
+
values=item
|
|
111
|
+
)
|
|
112
|
+
if checked:
|
|
113
|
+
self.item(iid, tags=("checked",))
|
|
114
|
+
else:
|
|
115
|
+
self.item(iid, tags=("unchecked"))
|
|
116
|
+
|
|
117
|
+
def item_click(self, event) -> int:
|
|
118
|
+
iid = self.identify_row(event.y)
|
|
119
|
+
if not iid:
|
|
120
|
+
return
|
|
121
|
+
|
|
122
|
+
current_img = self.item(iid, "image")[0]
|
|
123
|
+
if current_img == str(self.unchecked_image):
|
|
124
|
+
self.item(iid, image=self.checked_image, tags=("checked",))
|
|
125
|
+
else:
|
|
126
|
+
self.item(iid, image=self.unchecked_image, tags=("unchecked"))
|
|
127
|
+
|
|
128
|
+
return "break"
|
|
129
|
+
|
|
130
|
+
def checked_items(self) -> list[tuple]:
|
|
131
|
+
"""
|
|
132
|
+
Returns a list of the values (text columns) for all currently
|
|
133
|
+
checked rows.
|
|
134
|
+
|
|
135
|
+
Each returned tuple contains the values from the data columns only
|
|
136
|
+
(excludes the checkbox image in the tree column).
|
|
137
|
+
|
|
138
|
+
Example return value:
|
|
139
|
+
[("docs", "report.pdf", "Read this file"),
|
|
140
|
+
("code", "main.py", "Fix bug")]
|
|
141
|
+
"""
|
|
142
|
+
checked_items = []
|
|
143
|
+
|
|
144
|
+
for iid in self.get_children(''):
|
|
145
|
+
tags = self.item(iid, "tags")
|
|
146
|
+
if "checked" in tags:
|
|
147
|
+
values = self.item(iid, "values")
|
|
148
|
+
checked_items.append(values)
|
|
149
|
+
return checked_items
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = '0.2.19'
|
|
@@ -1,85 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
from tkinter import ttk
|
|
3
|
-
import dateutil # type: ignore
|
|
4
|
-
from dateutil.parser import parse # type: ignore
|
|
5
|
-
|
|
6
|
-
UNCHECKED = '\u2610'
|
|
7
|
-
CHECKED = '\u2612'
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
def sort_treeview(tree: ttk.Treeview, col: int, reverse: bool) -> None:
|
|
11
|
-
"""Sort the Treeview by column."""
|
|
12
|
-
children = [
|
|
13
|
-
(tree.set(child, col), child) for child in tree.get_children('')
|
|
14
|
-
]
|
|
15
|
-
is_date = True
|
|
16
|
-
try:
|
|
17
|
-
date_children = []
|
|
18
|
-
for child in children:
|
|
19
|
-
if len(child[0]) < 8:
|
|
20
|
-
is_date = False
|
|
21
|
-
break
|
|
22
|
-
date = parse(child[0])
|
|
23
|
-
date_children.append((date, child[1]))
|
|
24
|
-
except dateutil.parser._parser.ParserError:
|
|
25
|
-
is_date = False
|
|
26
|
-
if is_date:
|
|
27
|
-
children = date_children
|
|
28
|
-
try:
|
|
29
|
-
children.sort(key=lambda t: float(t[0]), reverse=reverse)
|
|
30
|
-
except TypeError:
|
|
31
|
-
children.sort(key=lambda t: t[0], reverse=reverse)
|
|
32
|
-
except ValueError:
|
|
33
|
-
children.sort(reverse=reverse)
|
|
34
|
-
|
|
35
|
-
for index, (val, child) in enumerate(children):
|
|
36
|
-
tree.move(child, '', index)
|
|
37
|
-
|
|
38
|
-
tree.heading(col, command=lambda: sort_treeview(tree, col, not reverse))
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
class CheckTreeView(ttk.Treeview):
|
|
42
|
-
def __init__(self, master=None, width=200, clicked=None,
|
|
43
|
-
unchecked=UNCHECKED, checked=CHECKED, **kwargs):
|
|
44
|
-
"""
|
|
45
|
-
:param width: the width of the check list
|
|
46
|
-
:param clicked: the optional function if a checkbox is clicked. Takes a
|
|
47
|
-
`iid` parameter.
|
|
48
|
-
:param unchecked: the character for an unchecked box (default is
|
|
49
|
-
"\u2610")
|
|
50
|
-
:param unchecked: the character for a checked box (default is "\u2612")
|
|
51
|
-
|
|
52
|
-
Other parameters are passed to the `TreeView`.
|
|
53
|
-
"""
|
|
54
|
-
if "selectmode" not in kwargs:
|
|
55
|
-
kwargs["selectmode"] = "none"
|
|
56
|
-
if "show" not in kwargs:
|
|
57
|
-
kwargs["show"] = "tree"
|
|
58
|
-
ttk.Treeview.__init__(self, master, **kwargs)
|
|
59
|
-
self.number_selected = 0
|
|
60
|
-
|
|
61
|
-
def item_click(self, pos_x: int, pos_y: int) -> int:
|
|
62
|
-
element = self.identify("element", pos_x, pos_y)
|
|
63
|
-
if element == "text":
|
|
64
|
-
iid = self.identify_row(pos_y)
|
|
65
|
-
self._toggle(iid)
|
|
66
|
-
return self.number_selected
|
|
67
|
-
|
|
68
|
-
def _toggle(self, iid):
|
|
69
|
-
"""
|
|
70
|
-
Toggle the checkbox `iid`
|
|
71
|
-
"""
|
|
72
|
-
values = list(self.item(iid).values())[2]
|
|
73
|
-
new_value = UNCHECKED
|
|
74
|
-
number = -1
|
|
75
|
-
if values[0] == UNCHECKED:
|
|
76
|
-
new_value = CHECKED
|
|
77
|
-
number = 1
|
|
78
|
-
values = [new_value] + list(values[1:])
|
|
79
|
-
self.item(iid, values=values)
|
|
80
|
-
self.number_selected = self.number_selected + number
|
|
81
|
-
|
|
82
|
-
def populate(self, items: list[tuple]) -> None:
|
|
83
|
-
for item in items:
|
|
84
|
-
values = [UNCHECKED] + list(item)
|
|
85
|
-
self.insert('', 'end', values=values)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|