disk_eraser/app/__init__.py

229 lines
11 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import platform
from tkinter import ttk
from customtkinter import *
from CTkMenuBar import *
from CTkMessagebox import *
from typing import List
import time
from app.utils_drive import *
class App:
drives: List[Drive] = []
thread = None
selected = None
drive_tree = None
wipe_result = {"result": None,
"err": ""}
def __init__(self):
set_default_color_theme("dark-blue")
set_appearance_mode("dark")
self.OS_TYPE = platform.system()
self.root = CTk()
self.root.title("Disk Eraser")
self.root.geometry("800x300")
self.root.minsize(800, 300)
self.__load_menus()
self.__init_table()
self.__update_drives()
self.root.mainloop()
def __load_menus(self):
bg_color = self.root._apply_appearance_mode(ThemeManager.theme["CTkFrame"]["fg_color"])
main_menu = CTkMenuBar(self.root, bg_color=bg_color)
help_menu = main_menu.add_cascade("Справка")
dropdown1 = CustomDropdownMenu(widget=help_menu)
dropdown1.add_option(option="Помощь")
dropdown1.add_separator()
dropdown1.add_option(option="О программе", command=self.__open_about_window)
self.root.config(menu=main_menu)
self.bottom_frame = CTkFrame(self.root)
self.erase_button = CTkButton(
self.bottom_frame, text="Стереть диск", command=self.__erase_drive)
self.erase_button.pack(side=RIGHT)
update_button = CTkButton(
self.bottom_frame, text="Обновить", command=self.__update_drives)
update_button.pack(side=RIGHT, padx=5)
self.method_box = CTkComboBox(master=self.bottom_frame, values=list(erasing_methods.keys()), state="readonly")
self.method_box.pack(side=RIGHT, padx=6)
method_label = CTkLabel(master=self.bottom_frame, text="Метод: ")
method_label.pack(padx=5, side=RIGHT)
self.bottom_frame.pack(side=BOTTOM, fill=BOTH, padx=5, pady=5)
def __update_drives(self):
self.drive_tree.delete(*self.drive_tree.get_children())
self.__load_drives()
for drive in self.drives:
rec_method = "DoD 5220.22M"
if drive.disk_type == "HDD":
rec_method = "DoD 5220.22M,Гутмана"
drive.rec_method = rec_method
self.drive_tree.insert("", END, values=(
drive.index, drive.name, drive.disk_type, self.__human_size(drive.capacity), drive.serial_num, rec_method))
if self.selected is not None:
items = self.drive_tree.get_children("")
for item in items:
if self.drive_tree.item(item)["values"] == self.selected:
self.drive_tree.selection_add(item)
def __load_drives(self):
if self.OS_TYPE == "Windows":
import wmi
c = wmi.WMI()
self.drives = []
ws = wmi.WMI(namespace='root/Microsoft/Windows/Storage')
drives_mt = ws.MSFT_PhysicalDisk()
if disks := c.Win32_DiskDrive():
for disk in disks:
for drive in drives_mt:
if disk.Index == int(drive.DeviceId):
self.drives.append(Drive(disk.Model, disk.Name, drive.MediaType, disk.DefaultBlockSize, int(disk.Size), disk.SerialNumber, disk.Index))
elif self.OS_TYPE == "Linux":
from diskinfo import DiskInfo
di = DiskInfo()
disks = di.get_disk_list(sorting=True)
self.drives = []
for disk in disks:
if "zram" not in disk.get_path() and "loop" not in disk.get_path() and disk.get_size() != 0:
self.drives.append(Drive(disk.get_model(), disk.get_path(), disk.get_type_str(
), disk.get_logical_block_size(), int(disk.get_size()*512), disk.get_serial_number(), disk.get_device_id()))
print(disk)
def __init_table(self):
###Treeview Customisation (theme colors are selected)
bg_color = self.root._apply_appearance_mode(ThemeManager.theme["CTkFrame"]["fg_color"])
text_color = self.root._apply_appearance_mode(ThemeManager.theme["CTkLabel"]["text_color"])
selected_color = self.root._apply_appearance_mode(ThemeManager.theme["CTkButton"]["fg_color"])
treestyle = ttk.Style()
treestyle.theme_use("clam")
treestyle.configure("Treeview", background=bg_color, foreground=text_color, fieldbackground=bg_color, borderwidth=0)
treestyle.map('Treeview', background=[('selected', bg_color)], foreground=[('selected', selected_color)])
treestyle.configure("Treeview.Heading", background=bg_color, foreground=text_color, fieldbackground=bg_color, borderwidth=0)
treestyle.map('Treeview.Heading', background=[('selected', bg_color)], foreground=[('selected', selected_color)])
self.root.bind("<<TreeviewSelect>>", lambda event: self.root.focus_set())
# определяем столбцы
columns = ("index", "name", "type", "capacity", "serial_num", "method")
self.drive_tree = ttk.Treeview(
columns=columns, show="headings", selectmode="browse")
self.drive_tree.pack(fill=BOTH, expand=1, side=TOP)
# определяем заголовки
self.drive_tree.heading("index", text="ID", anchor=W, command=lambda: self.__sort(0, False))
self.drive_tree.heading("name", text="Имя", anchor=W, command=lambda: self.__sort(1, False))
self.drive_tree.heading("type", text="Тип", anchor=W, command=lambda: self.__sort(2, False))
self.drive_tree.heading("capacity", text="Объем", anchor=W, command=lambda: self.__sort(3, False))
self.drive_tree.heading("serial_num", text="Серийный номер", anchor=W, command=lambda: self.__sort(4, False))
self.drive_tree.heading("method", text="Рекомендуемый метод", anchor=W, command=lambda: self.__sort(5, False))
self.drive_tree.column("#1", stretch=NO, width=60, minwidth=60)
self.drive_tree.column("#2", stretch=YES, width=150, minwidth=120)
self.drive_tree.column("#3", stretch=NO, width=100, minwidth=100)
self.drive_tree.column("#4", stretch=NO, width=100, minwidth=50)
self.drive_tree.column("#5", stretch=YES, width=150, minwidth=100)
self.drive_tree.column("#6", stretch=YES, width=150, minwidth=150)
self.drive_tree.bind("<<TreeviewSelect>>", self.__drive_selected)
def __human_size(self, size):
units = ['Б', 'КБ', 'МБ', 'ГБ', 'ТБ', 'ПБ']
for unit in units:
if size < 1024:
return f"{size:.1f} {unit}"
size /= 1024
def __drive_selected(self, event):
for selected_item in self.drive_tree.selection():
item = self.drive_tree.item(selected_item)
self.selected_id = selected_item
self.selected = item["values"]
for drive in self.drives:
if drive.index == self.selected[0]:
method = drive.rec_method if "," not in drive.rec_method else drive.rec_method.split(",")[0]
self.method_box.set(method)
def __erase_drive(self):
method = self.method_box.get()
if self.selected is None:
self.__show_warning("Выберете носитель информации для стирания!")
elif method == "":
self.__show_warning("Выберете метод стирания данных!")
elif self.__ask_question():
self.erase_button.configure(state='disabled')
self.drive_tree.configure(selectmode="none")
self.thread = None
self.progressbar = CTkProgressBar(master=self.bottom_frame, orientation="horizontal", width=200)
self.progressbar.set(0)
self.progressbar.pack(side=LEFT, padx=6, pady=6)
self.progress_label = CTkLabel(self.bottom_frame, text="0 %")
self.progress_label.pack(side=LEFT, padx=5, pady=5)
for drive in self.drives:
if drive.index == self.selected[0]:
self.thread = drive.erase(self.method_box.get(), progressbar=self.progressbar, progress_label=self.progress_label, result=self.wipe_result)
self.start_time = time.time()
self.__check_thread()
def __check_thread(self):
if self.thread.is_alive():
self.root.after(1000, lambda: self.__check_thread())
else:
self.progress_label.pack_forget()
self.progressbar.pack_forget()
self.drive_tree.configure(selectmode="browse")
self.erase_button.configure(state='active')
if self.wipe_result["result"]:
print(f"Время затраченное на стирание: {time.time()-self.start_time}")
CTkMessagebox(title="Успешно", message=f"{self.selected[1]} стёрт!")
else:
CTkMessagebox(title="Ошибка", message=f"{self.wipe_result['err']}")
def __show_warning(self, text):
CTkMessagebox(title="Ошибка", message=text)
def __sort(self, col, reverse):
# получаем все значения столбцов в виде отдельного списка
l = [(self.drive_tree.set(k, col), k) for k in self.drive_tree.get_children("")]
# сортируем список
l.sort(reverse=reverse)
# переупорядочиваем значения в отсортированном порядке
for index, (_, k) in enumerate(l):
self.drive_tree.move(k, "", index)
# в следующий раз выполняем сортировку в обратном порядке
self.drive_tree.heading(col, command=lambda: self.__sort(col, not reverse))
def __ask_question(self):
msg = CTkMessagebox(title="Стереть", message=f"Вы уверены, что хотите стереть {self.selected[1]} с серийным номером {self.selected[4]}?",
icon="question", option_1="Отмена", option_2="Нет", option_3="Да")
response = msg.get()
if response == "Да":
return True
else:
return False
def __open_about_window(self):
CTkMessagebox(title="О программе", message="Программа для гарантированного стирания машинных носителей информации\n(c) Романько М.И., Россия, 2024г.")