disk_eraser/app/__init__.py

198 lines
9.0 KiB
Python
Raw 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
from app.utils_drive import *
class App:
drives: List[Drive] = []
selected = None
drive_tree = None
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:
self.drive_tree.insert("", END, values=(
drive.index, drive.name, drive.disk_type, self.__human_size(drive.capacity), drive.serial_num))
self.selected = None
def __load_drives(self):
if self.OS_TYPE == "Windows":
import wmi
c = wmi.WMI()
self.drives = []
if disks := c.Win32_DiskDrive():
for disk in disks:
self.drives.append(Drive(disk.Model, disk.Name, disk.InterfaceType, disk.DefaultBlockSize, int(
disk.Size), disk.SerialNumber, disk.Index))
elif self.OS_TYPE == "Linux":
from diskinfo import Disk, DiskInfo
di = DiskInfo()
disks = di.get_disk_list(sorting=True)
self.drives = []
for disk in disks:
if "zram" not in disk.get_path():
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()))
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")
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.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=YES, width=150, minwidth=100)
self.drive_tree.column("#5", stretch=YES, width=150, minwidth=100)
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 = item["values"]
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")
thread = None
self.progressbar = CTkProgressBar(master=self.bottom_frame, orientation="horizontal", width=200)
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]:
thread = drive.erase(self.method_box.get(), progressbar=self.progressbar, progress_label=self.progress_label)
self.__check_thread(thread)
def __check_thread(self, thread):
if thread.is_alive():
self.root.after(1000, lambda: self.__check_thread(thread))
else:
self.progress_label.pack_forget()
self.progressbar.pack_forget()
self.drive_tree.configure(selectmode="browse")
self.erase_button.configure(state='active')
CTkMessagebox(title="Успешно", message=f"{self.selected[1]} стёрт!")
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]}?",
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г.")