File-time-machine/gui/gui.py

325 lines
9.5 KiB
Python
Raw Normal View History

2024-12-06 11:41:02 -08:00
# This file was generated by the Tkinter Designer by Parth Jadhav
# https://github.com/ParthJadhav/Tkinter-Designer
# And modified by Mizuki Zou
# This was not made with quality in mind, but rather as a quick and dirty GUI. Keep this in mind while using it.
from pathlib import Path
from shutil import which
import os
import json
import time
import subprocess
import threading
# from tkinter import *
# Explicit imports to satisfy Flake8
from tkinter import Tk, Canvas, Entry, Text, Button, PhotoImage, filedialog, messagebox, Listbox, LEFT, BOTH, Scrollbar, RIGHT, END, HORIZONTAL, Toplevel
from tkinter.ttk import Progressbar
from tkinter.filedialog import askopenfilename
OUTPUT_PATH = Path(__file__).parent
ASSETS_PATH = OUTPUT_PATH / Path(r".")
config_path = ""
target_path = ""
windows_paths = ["C:\\Progam Files\\File Time Machine\\ftm.exe", "C:\\Program Files (x86)\\File Time Machine\\ftm.exe"]
path_windows = ""
if os.path.exists(windows_paths[0]):
path_windows = windows_paths[0]
elif os.path.exists(windows_paths[1]):
path_windows = windows_paths[1]
platform = os.name # nt for Windows, posix for Linux.
def relative_to_assets(path: str) -> Path:
return ASSETS_PATH / Path(path)
def select_dir_or_file(dir: bool): # If dir, we know it is the target path. Otherwise, it is the config file
global config_path, target_path, exists
if not exists:
messagebox.showerror("No binary", "FTM binary not found! You need to install it before using the gui.")
return
if dir:
messagebox.showwarning("Warning!", "This software is NOT stable, and will probably result in data loss if you use it!")
folder_selected = filedialog.askdirectory()
target_path = folder_selected
if folder_selected != "":
print(folder_selected)
window.title(folder_selected)
if not os.path.isdir(folder_selected+"/.time"):
if messagebox.askquestion('Config file','This folder is not currently being tracked, do you want to begin tracking it? A config folder will be created for you, and default settings will be applied. (No hashing, compression level 5, multithreading enabled)'):
os.mkdir(folder_selected+"/.time")
print("Starting to track "+folder_selected)
if platform == "posix":
config_path = folder_selected+"/.time/gui-config.json"
else:
config_path = folder_selected+"\\.time\\gui-config.json"
config_file = open(config_path, 'w')
print("Writing config to "+str(config_file))
config_file.write('''[
{
"folder_path": "'''+folder_selected+'''",
"get_hashes": false,
"thread_count": 0,
"brotli_compression_level": 5,
"snapshot_mode": "fastest",
"its_my_fault_if_i_lose_data": true
}
]''')
config_file.close()
else:
if not os.path.exists(folder_selected+"/.time/gui-config.json"):
print(folder_selected+"/.time/gui-config.json")
messagebox.showinfo("No config", "Could not find a config file, please specify one")
else:
config_path = folder_selected+"/.time/gui-config.json"
get_snap_list()
else:
config_path = askopenfilename()
print(config_path)
def get_snap_list():
global listbox, target_path
listbox.delete(0, END)
print(target_path+'/.time/snapshots.json')
if os.path.exists(target_path+'/.time/snapshots.json'):
with open(target_path+'/.time/snapshots.json') as f:
d = json.load(f)
for i in range(len(d)):
print(d[i]["date_created"])
listbox.insert(END, d[i]["date_created"])
else:
messagebox.showinfo("No Snapshots", "Did not find any snapshots to list.")
def create_snapshot():
global config_path
if config_path == "":
messagebox.showerror("Select folder", "You need to select a folder before you can create a snapshot!")
return
output = ""
progress_window = Toplevel()
progress_window.resizable(width=False, height=False)
progress_window.title("Creating snapshot...")
progress_window.geometry("300x100")
# Create a progress bar in the new window
progress = Progressbar(progress_window, orient=HORIZONTAL, length=280, mode='indeterminate')
progress.pack(pady=20)
if platform == "posix":
print("Running command 'ftm -c "+config_path+"'")
progress.start()
p1 = subprocess.Popen(['ftm', '-c', config_path], stdout=subprocess.PIPE)
else:
print("Running command '"+path_windows+" -c "+config_path+"'")
progress.start()
p1 = subprocess.Popen([path_windows, '-c', config_path], stdout=subprocess.PIPE)
# p1 = subprocess.Popen(['sleep', '3'], stdout=subprocess.PIPE)
output = p1.communicate()[0]
print(output)
progress.stop()
progress_window.destroy()
if "No files changed" in str(output):
messagebox.showwarning("No changed files", "There were no changed files, so I cannot take a snapshot!")
get_snap_list()
def restore_snapshot():
global listbox
# print(listbox.curselection()[0])
selection = listbox.curselection()[0]+1
if listbox.curselection() == ():
messagebox.showerror("No snapshot", "No snapshot is selected!")
return
progress_window = Toplevel()
progress_window.resizable(width=False, height=False)
progress_window.title("Restoring snapshot")
progress_window.geometry("300x100")
# Create a progress bar in the new window
progress = Progressbar(progress_window, orient=HORIZONTAL, length=280, mode='indeterminate')
progress.pack(pady=20)
progress.start()
print("Running 'ftm -c "+config_path+" restore --restore-index "+str(selection)+"'")
p1 = subprocess.Popen(
['ftm', '-c', config_path, 'restore', '--restore-index', str(selection)], stdout=subprocess.PIPE)
output = p1.communicate()[0]
print(output)
progress.stop()
progress_window.destroy()
if "Finished restoring" not in str(output):
messagebox.showerror("Error", "There was an issue restoring a snapshot! Error: "+str(output))
window = Tk()
window.geometry("443x428")
window.configure(bg = "#313244")
if platform == "posix":
exists = which("ftm")
else:
exists = os.path.exists(path_windows)
canvas = Canvas(
window,
bg = "#313244",
height = 428,
width = 443,
bd = 0,
highlightthickness = 0,
relief = "ridge"
)
canvas.place(x = 0, y = 0)
canvas.create_text(
90.0,
19.0,
anchor="nw",
text="FTM-GUI",
fill="#CDD6F4",
font=("Jost Regular", 32 * -1)
)
if exists:
canvas.create_rectangle(
228.0,
20.0,
416.0,
70.0,
fill="#A6E3A1",
outline="")
canvas.create_text(
260.0,
32.0,
anchor="nw",
text="Found ftm binary!",
fill="#000000",
font=("Jost Regular", 15 * -1)
)
else:
canvas.create_rectangle(
228.0,
20.0,
416.0,
70.0,
fill="#e78284",
outline="")
canvas.create_text(
250.0,
32.0,
anchor="nw",
text="No ftm binary found!",
fill="#000000",
font=("Jost Regular", 15 * -1)
)
listbox = Listbox(window, bg="#9399B2", selectmode='single')
scrollbar = Scrollbar(window, bg="#9399B2")
# Create scrollbox for list of snapshots
listbox.place(x=29, y=154, width=387, height=209) # Listbox within the rectangle
scrollbar.place(x=416, y=154, height=209) # Scrollbar on the right side of the Listbox
# Attach the Listbox to the Scrollbar
# for values in range(100):
# listbox.insert(END, values)
listbox.config(yscrollcommand=scrollbar.set)
scrollbar.config(command=listbox.yview)
canvas.create_rectangle( # Scrollbox rectangle
29.0,
154.0,
416.0,
363.0,
fill="#9399B2",
outline="")
canvas.create_text(
29.0,
128.0,
anchor="nw",
text="Available snapshots",
fill="#CDD6F4",
font=("Jost Regular", 15 * -1)
)
button_image_1 = PhotoImage(
file=relative_to_assets("button_1.png"))
button_1 = Button(
image=button_image_1,
borderwidth=0,
highlightthickness=0,
command=lambda: threading.Thread(target=restore_snapshot, daemon=True).start(),
relief="flat"
)
button_1.place(
x=26.0,
y=376.0,
width=196.0,
height=27.0
)
button_image_2 = PhotoImage(
file=relative_to_assets("button_2.png"))
button_2 = Button(
image=button_image_2,
borderwidth=0,
highlightthickness=0,
command=lambda: threading.Thread(target=create_snapshot, daemon=True).start(),
relief="flat"
)
button_2.place(
x=225.0,
y=376.0,
width=194.0,
height=26.0
)
button_image_3 = PhotoImage(
file=relative_to_assets("button_3.png"))
button_3 = Button(
image=button_image_3,
borderwidth=0,
highlightthickness=0,
command=lambda: select_dir_or_file(True),
relief="flat"
)
button_3.place(
x=17.0,
y=86.0,
width=194.0,
height=26.0
)
button_image_4 = PhotoImage(
file=relative_to_assets("button_4.png"))
button_4 = Button(
image=button_image_4,
borderwidth=0,
highlightthickness=0,
command=lambda: select_dir_or_file(False),
relief="flat"
)
button_4.place(
x=225.0,
y=86.0,
width=194.0,
height=26.0
)
image_image_1 = PhotoImage(
file=relative_to_assets("image_1.png"))
image_1 = canvas.create_image(
42.0,
42.0,
image=image_image_1
)
window.resizable(False, False)
window.mainloop()