Skip to content

Commit cfdf634

Browse files
committed
Fixed GUI sometimes crashing when drag-and-dropping files, schema not found result, fixed source and destination binary files frames having different heights, results are now also updated when you drag-and-drop file that already exists in the source widget.
1 parent 1726456 commit cfdf634

File tree

4 files changed

+88
-35
lines changed

4 files changed

+88
-35
lines changed

flatc_deserializer_frontend.py

Lines changed: 64 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,17 @@
33
"""
44
# pylint: disable=import-error, too-many-instance-attributes, too-many-statements
55
import os
6+
from collections.abc import Callable
7+
from importlib import import_module
68
from tkinter import ttk
9+
710
from PIL.ImageTk import PhotoImage
811
from PIL import Image
912
from i18n import t
1013
import customtkinter as CTk
1114
from CTkMenuBar import CTkMenuBar
1215
from CTkMessagebox import CTkMessagebox
13-
import pywinstyles
16+
1417
from main import init_localization, get_resource_path, execute_download, get_flatc_path, \
1518
get_binary_tuples
1619
from flatc_funcs import deserialize
@@ -56,14 +59,20 @@ def __init__(self):
5659
columns=("file", "file_size"), show="headings")
5760
self.src_binaries_table.heading("file", text=t("frontend.source_file_loc"))
5861
self.src_binaries_table.heading("file_size", text=t("frontend.file_size"))
59-
self.src_binaries_table.pack(fill=CTk.BOTH, expand=True, padx=10, pady=10)
60-
pywinstyles.apply_dnd(self.src_binaries_table.winfo_id(), self.on_binary_dropped)
62+
self.src_binaries_frame.grid_rowconfigure(0, weight=1)
63+
self.src_binaries_frame.grid_columnconfigure(0, weight=1)
64+
self.src_binaries_frame.grid_propagate(False)
65+
self.src_binaries_table.grid(row=0, column=0, padx=10, pady=10, sticky=CTk.NSEW)
66+
self.attempt_apply_dnd(self.src_binaries_table.winfo_id(), self.on_binary_dropped)
6167
self.src_schemas_frame = ttk.LabelFrame(self.src_files_frame,
6268
text=t("frontend.source_schemas"))
6369
self.src_schemas_frame.grid(row=1, column=0, padx=10, pady=10, sticky=CTk.NSEW)
6470
self.src_schemas_table = ttk.Treeview(self.src_schemas_frame, columns="file", show="")
65-
self.src_schemas_table.pack(fill=CTk.BOTH, expand=True, padx=10, pady=10)
66-
pywinstyles.apply_dnd(self.src_schemas_table.winfo_id(), self.on_schema_dropped)
71+
self.src_schemas_frame.grid_rowconfigure(0, weight=1)
72+
self.src_schemas_frame.grid_columnconfigure(0, weight=1)
73+
self.src_schemas_frame.grid_propagate(False)
74+
self.src_schemas_table.grid(row=0, column=0, padx=10, pady=10, sticky=CTk.NSEW)
75+
self.attempt_apply_dnd(self.src_schemas_table.winfo_id(), self.on_schema_dropped)
6776
self.dest_files_frame = ttk.LabelFrame(self.files_frame,
6877
text=t("frontend.destination_files"))
6978
self.dest_files_frame.grid_rowconfigure(0, weight=1)
@@ -79,9 +88,13 @@ def __init__(self):
7988
self.dest_binaries_table.heading("file", text=t("frontend.destination_file_loc"))
8089
self.dest_binaries_table.heading("result", text=t("frontend.result"))
8190
self.dest_binaries_table.heading("file_size", text=t("frontend.file_size"))
82-
self.dest_binaries_table.pack(fill=CTk.BOTH, expand=True, padx=10, pady=10)
91+
self.dest_binaries_frame.grid_rowconfigure(0, weight=1)
92+
self.dest_binaries_frame.grid_columnconfigure(0, weight=1)
93+
self.dest_binaries_frame.grid_propagate(False)
94+
self.dest_binaries_table.grid(row=0, column=0, padx=10, pady=10, sticky=CTk.NSEW)
8395
self.dest_options_frame = ttk.LabelFrame(self.dest_files_frame,
8496
text=t("frontend.destination_options"))
97+
self.dest_options_frame.grid_propagate(False)
8598
self.dest_options_frame.grid(row=1, column=0, padx=10, pady=10, sticky=CTk.NSEW)
8699
self.bottom_menu = CTkMenuBar(self, bg_color=None)
87100
img = Image.open(get_resource_path("images/flatbuffers-batch-logo-clean.png"))
@@ -90,6 +103,23 @@ def __init__(self):
90103
self.deserialize_button.configure(command=self.deserialize_button_pressed)
91104
self.bottom_menu.pack(side=CTk.RIGHT)
92105

106+
@staticmethod
107+
def attempt_apply_dnd(widget_id: int, dnd_event: Callable):
108+
"""
109+
Adding files drag-and-drop functionality to widget if it's supported.
110+
:param widget_id: Widget ID.
111+
:param dnd_event: Callable object for drag-and-drop event.
112+
"""
113+
if os.name != "nt":
114+
return
115+
try:
116+
mod = import_module("pywinstyles")
117+
except ModuleNotFoundError:
118+
return
119+
fun = getattr(mod, "apply_dnd", None)
120+
if fun is not None:
121+
fun(widget_id, dnd_event)
122+
93123
@staticmethod
94124
def flatc_button_pressed():
95125
"""
@@ -118,17 +148,26 @@ def add_src_binary(self, file: str):
118148
binary_path = os.path.abspath(file)
119149
if os.path.splitext(binary_path)[1].lower() == ".json":
120150
return
151+
binary_exists = self.src_binaries_table.exists(binary_path.casefold())
121152
src_values = (binary_path, t("frontend.size_kb") % (os.path.getsize(binary_path) / 1024))
122153
output_path = os.path.splitext(binary_path)[0] + ".json"
123154
if os.path.isfile(output_path):
124155
dest_values = (output_path, t("frontend.file_already_exists"),
125156
t("frontend.size_kb") % (os.path.getsize(output_path) / 1024))
126157
else:
127158
dest_values = (output_path, "", "")
128-
if self.src_binaries_table.exists(binary_path.casefold()):
129-
return
130-
self.src_binaries_table.insert("", "end", binary_path.casefold(), values=src_values)
131-
self.dest_binaries_table.insert("", "end", binary_path.casefold(), values=dest_values)
159+
if binary_exists:
160+
for j in range(2):
161+
self.src_binaries_table.set(binary_path.casefold(), j, src_values[j])
162+
self.src_binaries_table.update()
163+
for j in range(3):
164+
self.dest_binaries_table.set(binary_path.casefold(), j, dest_values[j])
165+
self.dest_binaries_table.update()
166+
else:
167+
self.src_binaries_table.insert("", "end", binary_path.casefold(), values=src_values)
168+
self.src_binaries_table.update()
169+
self.dest_binaries_table.insert("", "end", binary_path.casefold(), values=dest_values)
170+
self.dest_binaries_table.update()
132171

133172
def on_schema_dropped(self, paths: list[str]):
134173
"""
@@ -154,6 +193,7 @@ def add_src_schema(self, file: str):
154193
if self.src_schemas_table.exists(schema_path.casefold()):
155194
return
156195
self.src_schemas_table.insert("", "end", schema_path.casefold(), values=[schema_path])
196+
self.src_schemas_table.update()
157197

158198
def deserialize_button_pressed(self):
159199
"""
@@ -171,7 +211,7 @@ def deserialize_button_pressed(self):
171211
self.dest_binaries_table.get_children("")]
172212
schema_paths = [self.src_schemas_table.set(i, 0) for i in
173213
self.src_schemas_table.get_children("")]
174-
binary_tuples = get_binary_tuples(binary_paths, schema_paths)
214+
binary_tuples = get_binary_tuples(binary_paths, schema_paths, True)
175215
for i, binary_tuple in enumerate(binary_tuples):
176216
self.deserialize_and_update_table(flatc_path, binary_tuple[1], binary_tuple[0],
177217
output_paths[i])
@@ -187,14 +227,19 @@ def deserialize_and_update_table(self, flatc_path: str, schema_path: str, binary
187227
"""
188228
json_path = deserialize(flatc_path, schema_path, binary_path, output_path, False)
189229
for i in self.dest_binaries_table.get_children(""):
190-
if os.path.samefile(i, binary_path):
191-
if json_path != "":
192-
self.dest_binaries_table.set(i, 1, t("frontend.result_done"))
193-
self.dest_binaries_table.set(i, 2, t("frontend.size_kb") % (
194-
os.path.getsize(json_path) / 1024))
195-
else:
196-
self.dest_binaries_table.set(i, 1, t("frontend.result_error"))
197-
self.dest_binaries_table.set(i, 2, "")
230+
if not os.path.samefile(i, binary_path):
231+
continue
232+
if json_path != "":
233+
self.dest_binaries_table.set(i, 1, t("frontend.result_done"))
234+
self.dest_binaries_table.set(i, 2, t("frontend.size_kb") % (
235+
os.path.getsize(json_path) / 1024))
236+
elif not os.path.isfile(schema_path):
237+
self.dest_binaries_table.set(i, 1, t("frontend.schema_not_found"))
238+
self.dest_binaries_table.set(i, 2, "")
239+
else:
240+
self.dest_binaries_table.set(i, 1, t("frontend.result_error"))
241+
self.dest_binaries_table.set(i, 2, "")
242+
self.dest_binaries_table.update()
198243

199244

200245
if __name__ == "__main__":

flatc_funcs.py

Lines changed: 9 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@
99
from i18n import t
1010

1111

12-
def deserialize(flatc_path: str, schema_path: str, binary_path: str, output_path: str = "", return_dict = True) -> dict:
12+
def deserialize(flatc_path: str, schema_path: str, binary_path: str, output_path: str = "",
13+
return_dict=True) -> dict:
1314
"""
1415
Десериализация бинарного файла, используя схему Flatbuffers.
1516
:param flatc_path: Путь к компилятору схемы.
@@ -19,6 +20,9 @@ def deserialize(flatc_path: str, schema_path: str, binary_path: str, output_path
1920
:param return_dict: Если True, возвращать словарь из прочитанного файла. Иначе - путь к файлу.
2021
:return: Десериализованный бинарный файл в виде словаря.
2122
"""
23+
if not os.path.isfile(flatc_path) or not os.path.isfile(schema_path) or not os.path.isfile(
24+
binary_path):
25+
return {} if return_dict else ""
2226
flatc_path = os.path.abspath(flatc_path)
2327
schema_path = os.path.abspath(schema_path)
2428
binary_path = os.path.abspath(binary_path)
@@ -46,27 +50,19 @@ def deserialize(flatc_path: str, schema_path: str, binary_path: str, output_path
4650
info(t("flatc_funcs.run_error"), " ".join(cpe.cmd), cpe.returncode)
4751
if cpe.stderr is not None and cpe.stderr != "":
4852
info(cpe.stderr)
49-
if return_dict:
50-
return {}
51-
return ""
53+
return {} if return_dict else ""
5254
if proc.stdout is not None and proc.stdout != "":
5355
info(t("flatc_funcs.run_ok"), " ".join(args))
5456
info(proc.stdout)
5557
if not os.path.isfile(json_path):
5658
info(t("flatc_funcs.json_error"), binary_path)
57-
if return_dict:
58-
return {}
59-
return ""
59+
return {} if return_dict else ""
6060
try:
6161
with open(json_path, "rb") as json_file:
6262
current_json_contents = json_file.read()
6363
except OSError:
6464
info(t("main.file_failed_to_open"), json_path)
65-
if return_dict:
66-
return {}
67-
return ""
65+
return {} if return_dict else ""
6866
if current_json_contents != previous_json_contents:
6967
info(t("flatc_funcs.json_ok"), binary_path, json_path)
70-
if return_dict:
71-
return loads(current_json_contents.decode("utf-8"))
72-
return json_path
68+
return loads(current_json_contents.decode("utf-8")) if return_dict else json_path

localization/en_US/frontend.yml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ source_files: Source files
33
source_binaries: Source binary files
44
source_schemas: Source schemas
55
destination_files: Destination files
6-
destination_binaries: Destination binaries
6+
destination_binaries: Destination binary files
77
deserialize: Deserialize
88
destination_options: Destination file options
99
button_add: Add...
@@ -18,4 +18,5 @@ file_already_exists: File already exists
1818
flatc_not_found: Flatbuffers Schema Compiler (flatc) not found.
1919
error: Error
2020
result_done: Done
21-
result_error: Error
21+
result_error: Error
22+
schema_not_found: Schema not found

main.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -194,35 +194,46 @@ def get_schema_paths(root_path: str) -> list[str]:
194194
return schema_paths
195195

196196

197-
def get_binary_tuples(binary_paths: list[str], schema_paths: list[str]) -> list[tuple[str, str]]:
197+
def get_binary_tuples(binary_paths: list[str], schema_paths: list[str], return_empty_pairs: bool = False) -> list[tuple[str, str]]:
198198
"""
199199
Получение списка кортежей из двух элементов: (путь к бинарному файлу, путь к соответствующему ему файлу схемы)
200200
:param binary_paths: Список путей к бинарным файлам или директориям с ними.
201201
:param schema_paths: Список путей к файлам схем.
202+
:param return_empty_pairs: True, если необходимо добавить в список файлы, к которым нет схем.
202203
:return: Кортеж из двух строковых элементов.
203204
"""
204205
binary_tuples = []
205206
for _, binary_path in enumerate(binary_paths):
206207
if os.path.isfile(binary_path):
208+
schema_found = False
207209
file_path = os.path.abspath(binary_path)
208210
for schema_path in schema_paths:
209211
schema_ext = os.path.splitext(os.path.basename(schema_path))[0]
210212
file_ext = os.path.splitext(file_path)[1][1:]
211213
if schema_ext.casefold() == file_ext.casefold():
214+
schema_found = True
212215
binary_tuples.append((file_path, schema_path))
213216
break
217+
if not schema_found and return_empty_pairs:
218+
binary_tuples.append((file_path, ""))
214219
continue
215220
if not os.path.isdir(binary_path):
221+
if return_empty_pairs:
222+
binary_tuples.append((binary_path, ""))
216223
continue
217224
for subdir, _, files in os.walk(binary_path):
218225
for file in files:
226+
schema_found = False
219227
file_path = os.path.abspath(os.path.join(subdir, file))
220228
for schema_path in schema_paths:
221229
schema_ext = os.path.splitext(os.path.basename(schema_path))[0]
222230
file_ext = os.path.splitext(file_path)[1][1:]
223231
if schema_ext.casefold() == file_ext.casefold():
232+
schema_found = True
224233
binary_tuples.append((file_path, schema_path))
225234
break
235+
if not schema_found and return_empty_pairs:
236+
binary_tuples.append((file_path, ""))
226237
return binary_tuples
227238

228239

0 commit comments

Comments
 (0)