From c4219337804efed505048323042f59a8e6e148a1 Mon Sep 17 00:00:00 2001 From: lsw Date: Wed, 2 Feb 2022 01:43:38 +0100 Subject: [PATCH] Add GUI --- controller/AppController.py | 16 ++++ controller/IAppController.py | 2 + controller/IMainWindowController.py | 2 + controller/MainWindowController.py | 10 ++ gui/IMainWindow.py | 2 + gui/MainWindow.py | 144 ++++++++++++++++++++++++++++ main.py | 11 ++- model/IProtocol.py | 30 ++++++ model/Protocol.py | 90 +++++++++++++++++ 9 files changed, 306 insertions(+), 1 deletion(-) create mode 100644 controller/AppController.py create mode 100644 controller/IAppController.py create mode 100644 controller/IMainWindowController.py create mode 100644 controller/MainWindowController.py create mode 100644 gui/IMainWindow.py create mode 100644 gui/MainWindow.py create mode 100644 model/IProtocol.py create mode 100644 model/Protocol.py diff --git a/controller/AppController.py b/controller/AppController.py new file mode 100644 index 0000000..b858286 --- /dev/null +++ b/controller/AppController.py @@ -0,0 +1,16 @@ +from controller.IAppController import * + +class AppController(IAppController): + def __init__(self, parser): + self.parser = parser + self.window_controller = None + + def set_window_controller(self, window_controller): + self.window_controller = window_controller + + def on_quit(self): + pass +# if self.connection.is_connected: +# self.connection.send_message(self.parser.buildEXIT()) +# if self.client_thread != None: +# self.client_thread.stop_loop() \ No newline at end of file diff --git a/controller/IAppController.py b/controller/IAppController.py new file mode 100644 index 0000000..25cf96a --- /dev/null +++ b/controller/IAppController.py @@ -0,0 +1,2 @@ +class IAppController: + pass \ No newline at end of file diff --git a/controller/IMainWindowController.py b/controller/IMainWindowController.py new file mode 100644 index 0000000..224a8c8 --- /dev/null +++ b/controller/IMainWindowController.py @@ -0,0 +1,2 @@ +class IEventHandler: + pass \ No newline at end of file diff --git a/controller/MainWindowController.py b/controller/MainWindowController.py new file mode 100644 index 0000000..c88fca8 --- /dev/null +++ b/controller/MainWindowController.py @@ -0,0 +1,10 @@ +from controller.IMainWindowController import * + +class MainWindowController(IEventHandler): + def __init__(self, parser, app_controller): + self.parser = parser + self.app_controller = app_controller + + def on_quit(self): + self.app_controller.on_quit() + pass \ No newline at end of file diff --git a/gui/IMainWindow.py b/gui/IMainWindow.py new file mode 100644 index 0000000..d286fbf --- /dev/null +++ b/gui/IMainWindow.py @@ -0,0 +1,2 @@ +class IMainWindow: + pass \ No newline at end of file diff --git a/gui/MainWindow.py b/gui/MainWindow.py new file mode 100644 index 0000000..b880a47 --- /dev/null +++ b/gui/MainWindow.py @@ -0,0 +1,144 @@ +import tkinter as tk +from tkinter import ttk +from tkinter import messagebox +from gui.IMainWindow import * + +class MainWindow(IMainWindow): + def __init__(self, controller): + self.controller = controller + self.root = tk.Tk() + self.root.title("SecCon - © Louis SWINNEN 2022") + self.root.config(bd=5) + self.host = tk.StringVar() + self.passw = tk.StringVar() + self.login = tk.StringVar() + self.tls = tk.BooleanVar() + self.port = tk.IntVar() + self.draw_window() + + def start_main_loop(self): + self.tf_host.focus() + self.root.mainloop() + + def draw_window(self): + self.draw_top_pane() + self.draw_center_pane() + self.draw_footer_pane() + self.not_connected_mode() + + def draw_top_pane(self): + top_pane = ttk.LabelFrame(self.root, padding=(3, 3, 12, 12), text=" Connection to FileFrontEnd ") + top_pane.pack(fill=tk.X) + top_pane.columnconfigure(1, weight=1) + + ttk.Label(top_pane, text="Host:").grid(row=0, column=0, sticky=tk.E) + self.tf_host = ttk.Entry(top_pane, textvariable=self.host) + self.tf_host.grid(row=0, column=1, sticky=tk.EW, padx=5, pady=5) + + ttk.Label(top_pane, text="Port:").grid(row=0, column=2, sticky=tk.E) + self.tf_port = ttk.Entry(top_pane, textvariable=self.port) + self.tf_port.grid(row=0, column=3, sticky=tk.EW, padx=5, pady=2) + + ttk.Label(top_pane, text="Login:").grid(row=1, column=0, sticky=tk.E) + self.tf_login = ttk.Entry(top_pane, textvariable=self.login) + self.tf_login.grid(row=1,column=1, sticky=tk.EW, padx=5, pady=5) + + ttk.Label(top_pane, text="Password:").grid(row=1, column=2, sticky=tk.E) + self.tf_password = ttk.Entry(top_pane, show="*", textvariable=self.passw) + self.tf_password.grid(row=1,column=3, sticky=tk.EW, padx=5, pady=2) + + inner_frame = ttk.Frame(top_pane) + inner_frame.grid(row=2, column=0, columnspan=4, sticky=tk.NSEW) + inner_frame.columnconfigure(1,weight=1) + + ttk.Label(inner_frame, text="Security:").grid(row=0, column=0, sticky=tk.E) + self.cb_tls = ttk.Checkbutton(inner_frame, text="with SSL/TLS", variable=self.tls) + self.cb_tls.grid(row=0, column=1, padx=5, pady=2, sticky=tk.W) + self.bt_signup = ttk.Button(inner_frame, text="Sign up", command=self.sign_up) + self.bt_signup.grid(row=0, column=2, padx=5, pady=2,sticky=tk.E) + self.bt_signin = ttk.Button(inner_frame, text="Sign in", command=self.sign_in) + self.bt_signin.grid(row=0, column=3, padx=5, pady=2, sticky=tk.E) + + + + def draw_center_pane(self): + title_pane = ttk.Frame(self.root, padding=(5, 0, 5, 0)) + ttk.Label(title_pane, text="My files:").grid(row=0, column=0, sticky=tk.E) + title_pane.pack(fill=tk.X) + center_pane = ttk.Frame(self.root, padding=(5, 0, 5, 0)) + center_pane.pack(fill=tk.BOTH, expand=True) + center_pane.columnconfigure(1, weight=1) + + self.scroll = ttk.Scrollbar(center_pane) + self.tv_files = ttk.Treeview(center_pane, yscrollcommand=self.scroll.set, height=6) + self.tv_files["columns"] = ["Filename", "Size"] + self.tv_files["show"] = "headings" + self.tv_files.heading("Filename", text="Filename") + self.tv_files.heading("Size", text="Filesize") + self.tv_files.pack(side=tk.LEFT, fill=tk.BOTH, expand=True, pady=5) + self.scroll.config(command=self.tv_files.yview) + self.scroll.pack(side=tk.RIGHT, fill=tk.Y, pady=5) + + bottom_pane = ttk.Frame(self.root, padding=(5, 0, 5, 0)) + bottom_pane.columnconfigure(1, weight=1) + self.bt_filelist = ttk.Button(bottom_pane, text="Refresh list", command=self.file_list) + self.bt_filelist.grid(row=0, column=0, padx=10, pady=2,sticky=tk.E) + self.bt_savefile = ttk.Button(bottom_pane, text="Upload file", command=self.save_file) + self.bt_savefile.grid(row=0, column=1, padx=10, pady=2,sticky=tk.E) + self.bt_getfile = ttk.Button(bottom_pane, text="Download file", command=self.get_file) + self.bt_getfile.grid(row=0, column=2, padx=10, pady=2,sticky=tk.E) + self.bt_removefile = ttk.Button(bottom_pane, text="Remove file", command=self.remove_file) + self.bt_removefile.grid(row=0, column=3, padx=10, pady=2,sticky=tk.E) + bottom_pane.pack(fill=tk.X) + + def draw_footer_pane(self): + footer_pane = ttk.Frame(self.root, padding=(5,10,5,0)) + footer_pane.pack(fill=tk.X) + footer_pane.columnconfigure(1, weight=1) + self.bt_about = ttk.Button(footer_pane, text="About", command=self.about) + self.bt_about.grid(row=0, column=0, pady=3, sticky=tk.E) + self.bt_quit = ttk.Button(footer_pane, text="Quit", command=self.quit) + self.bt_quit.grid(row=0, column=1, pady=3, sticky=tk.E) + + def not_connected_mode(self): + self.bt_filelist.state(["disabled"]) + self.bt_savefile.state(["disabled"]) + self.bt_getfile.state(["disabled"]) + self.bt_removefile.state(["disabled"]) + + def connected_mode(self): + self.tf_host.state(["disabled"]) + self.tf_port.state(["disabled"]) + self.tf_login.state(["disabled"]) + self.tf_password.state(["disabled"]) + self.bt_signin.state(["disabled"]) + self.bt_signup.state(["disabled"]) + self.cb_tls.state(["disabled"]) + self.bt_filelist.state(["!disabled"]) + self.bt_savefile.state(["!disabled"]) + self.bt_getfile.state(["!disabled"]) + self.bt_removefile.state(["!disabled"]) + + def sign_in(self): + pass + def sign_up(self): + pass + + def save_file(self): + pass + + def get_file(self): + pass + + def remove_file(self): + pass + + def file_list(self): + pass + + def about(self): + pass + + def quit(self): + self.root.destroy() + self.controller.on_quit() \ No newline at end of file diff --git a/main.py b/main.py index 82ac3f0..9ca96c2 100644 --- a/main.py +++ b/main.py @@ -1,2 +1,11 @@ +from gui.MainWindow import * +from controller.MainWindowController import * +from controller.AppController import * +from model.Protocol import * + if __name__ == '__main__': - print("Hello World") \ No newline at end of file + parser = Protocol() + app_controller = AppController(parser) + event_handler = MainWindowController(parser, app_controller) + window = MainWindow(event_handler) + window.start_main_loop() diff --git a/model/IProtocol.py b/model/IProtocol.py new file mode 100644 index 0000000..de63ada --- /dev/null +++ b/model/IProtocol.py @@ -0,0 +1,30 @@ +class IProtocol: + def build_SIGNIN(self, login, password): + pass + + def build_SIGNUP(self, login, password): + pass + + def build_FILELIST(self): + pass + + def build_SAVEFILE(self, filename, size): + pass + + def build_GETFILE(self, filename): + pass + + def build_REMOVEFILE(self, filename): + pass + + def build_SIGNOUT(self): + pass + + def parse(self, line, debug_enabled): + pass + + def parse_FILES(self, line): + pass + + def parse_GETFILEOK(self, line): + pass \ No newline at end of file diff --git a/model/Protocol.py b/model/Protocol.py new file mode 100644 index 0000000..48ea503 --- /dev/null +++ b/model/Protocol.py @@ -0,0 +1,90 @@ +from model.IProtocol import * +import re + +class Protocol(IProtocol): + RX_DIGIT = r"[0-9]" + RX_SIZE = r"(" + RX_DIGIT + "{1,10})" + RX_LINE = r"(\\x0d\\x0a){0,1}" + RX_PASSCHAR = r"[\x22-\xff]" + RX_BL = r" " + RX_FILENAME = r"(" + RX_PASSCHAR + "{1,20})" + RX_SIGNOK = r"SIGN_OK" + RX_LINE + RX_SIGNERROR = r"SIGN_ERROR" + RX_LINE + RX_FILES = r"FILES((" + RX_BL + RX_FILENAME + "!" + RX_SIZE + "){0,50})" + RX_LINE + RX_SAVEFILEOK = r"SAVEFILE_OK" + RX_LINE + RX_SAVEFILEERROR = r"SAVEFILE_ERROR" + RX_LINE + RX_GETFILEOK = r"GETFILE_OK" + RX_BL + RX_FILENAME + RX_BL + RX_SIZE + RX_LINE + RX_GETFILEERROR = r"GETFILE_ERROR" + RX_LINE + RX_REMOVEFILEOK = r"REMOVEFILE_OK" + RX_LINE + RX_REMOVEFILEERROR = r"REMOVEFILE_ERROR" + RX_LINE + ALL_MESSAGES = [RX_SIGNOK, RX_SIGNERROR, RX_FILES, RX_SAVEFILEOK, RX_SAVEFILEERROR, RX_GETFILEOK, RX_GETFILEERROR, RX_REMOVEFILEOK, RX_REMOVEFILEERROR] + PARSE_UNKNOWN = -1 + PARSE_SIGNOK = 0 + PARSE_SIGNERROR = 1 + PARSE_FILES = 2 + PARSE_SAVEFILEOK = 3 + PARSE_SAVEFILEERROR = 4 + PARSE_GETFILEOK = 5 + PARSE_GETFILEERROR = 6 + PARSE_REMOVEFILEOK = 7 + PARSE_REMOVEFILEERROR = 8 + + MSG_CLIENT_SIGNIN = "SIGNIN \r\n" + MSG_CLIENT_SIGNUP = "SIGNUP \r\n" + MSG_CLIENT_FILELIST = "FILELIST\r\n" + MSG_CLIENT_SAVEFILE = "SAVEFILE \r\n" + MSG_CLIENT_GETFILE = "GETFILE \r\n" + MSG_CLIENT_REMOVEFILE = "REMOVEFILE \r\n" + MSG_CLIENT_SIGNOUT = "SIGNOUT\r\n" + + def build_SIGNIN(self, login, password): + return Protocol.MSG_CLIENT_SIGNIN.replace("", login).replace("", password) + + def build_SIGNUP(self, login, password): + return Protocol.MSG_CLIENT_SIGNUP.replace("", login).replace("", password) + + def build_FILELIST(self): + return Protocol.MSG_CLIENT_FILELIST + + def build_SAVEFILE(self, filename, size): + return Protocol.MSG_CLIENT_SAVEFILE.replace("", filename).replace("", str(size)) + + def build_GETFILE(self, filename): + return Protocol.MSG_CLIENT_GETFILE.replace("", filename) + + def build_REMOVEFILE(self, filename): + return Protocol.MSG_CLIENT_REMOVEFILE.replace("", filename) + + def build_SIGNOUT(self): + return Protocol.MSG_CLIENT_SIGNOUT + + def parse(self, line, debug_enabled): + for i in range(len(Protocol.ALL_MESSAGES)): + if(re.match(Protocol.ALL_MESSAGES[i], line) != None): + if(debug_enabled): + print("OK REGEXP:" + Protocol.ALL_MESSAGES[i]) + return i + else: + if(debug_enabled): + print("KO REGEXP:" + Protocol.ALL_MESSAGES[i]) + return Protocol.PARSE_UNKNOWN + + def parse_FILES(self, line): + if(self.parse(line, False) == Protocol.PARSE_FILES): + tokens = re.match(Protocol.RX_FILES, line) + return [tokens[1]] + return None + + def parse_GETFILEOK(self, line): + if(self.parse(line, False) == Protocol.PARSE_GETFILEOK): + tokens = re.match(Protocol.RX_GETFILEOK, line) + return [tokens[1], tokens[2]] + return None + +if __name__ == '__main__': + protocol = Protocol() + line = input("> ") + while(line != ""): + val = protocol.parse(line, True) + print("Val =" + str(val)) + line = input("> ") \ No newline at end of file