From 1ed4e93553183cf9ae46d54e4a86e25b16c1cd20 Mon Sep 17 00:00:00 2001 From: Ircama Date: Thu, 25 Jul 2024 22:08:05 +0200 Subject: [PATCH] Add tree view to printer status UI --- ui.py | 139 +++++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 133 insertions(+), 6 deletions(-) diff --git a/ui.py b/ui.py index 91ba41f..6e9b31e 100644 --- a/ui.py +++ b/ui.py @@ -1,11 +1,12 @@ import tkinter as tk -from tkinter import ttk +from tkinter import ttk, Menu from tkinter.scrolledtext import ScrolledText import threading import ipaddress -from epson_print_conf import EpsonPrinter from find_printers import PrinterScanner -from pprint import pformat +from epson_print_conf import EpsonPrinter +import tkinter.font as tkfont + class EpsonPrinterUI(tk.Tk): def __init__(self): @@ -64,10 +65,60 @@ class EpsonPrinterUI(tk.Tk): status_frame.columnconfigure(0, weight=1) status_frame.rowconfigure(0, weight=1) + # ScrolledText widget self.status_text = ScrolledText(status_frame, height=10, width=50, wrap=tk.WORD) self.status_text.grid(row=0, column=0, pady=5, padx=5, sticky=(tk.W, tk.E, tk.N, tk.S)) - + + # Style configuration + style = ttk.Style(self) + default_font = style.lookup("Treeview.Heading", "font") + + # If the default_font is a tuple, split into components + if isinstance(default_font, tuple): + default_font_name, default_font_size = default_font[0], default_font[1] + else: + # If font is not a tuple, it might be a font string or other format. + default_font_name, default_font_size = tkfont.Font().actual('family'), tkfont.Font().actual('size') + + style.configure("Treeview.Heading", + font=(default_font_name, default_font_size - 2, "bold"), + background="lightblue", + foreground="darkblue") + + # Create and configure the Treeview widget + self.tree = ttk.Treeview(status_frame, style="Treeview") + self.tree.heading("#0", text="Status Information", anchor='w') + self.tree.grid(column=0, row=0, sticky=(tk.W, tk.E, tk.N, tk.S)) + + # Create a vertical scrollbar for the Treeview + tree_scrollbar = ttk.Scrollbar(status_frame, orient="vertical", command=self.tree.yview) + tree_scrollbar.grid(column=1, row=0, sticky=(tk.N, tk.S)) + + # Configure the Treeview to use the scrollbar + self.tree.configure(yscrollcommand=tree_scrollbar.set) + + # Create a context menu + self.context_menu = Menu(self, tearoff=0) + self.context_menu.add_command(label="Copy", command=self.copy_selected_item) + + # Bind the right-click event to the Treeview + self.tree.bind("", self.show_context_menu) + + # Hide the grid view initially + self.tree.grid_remove() + + def show_status_text_view(self): + """Show the status frame and hide the Treeview.""" + self.tree.grid_remove() + self.status_text.grid() + + def show_treeview(self): + """Show the Treeview and hide the status frame.""" + self.status_text.grid_remove() + self.tree.grid() + def print_status(self): + self.show_status_text_view() model = self.model_var.get() ip_address = self.ip_var.get() if not model or not self._is_valid_ip(ip_address): @@ -76,11 +127,17 @@ class EpsonPrinterUI(tk.Tk): printer = EpsonPrinter(model=model, hostname=ip_address) try: - self.status_text.insert(tk.END, f"[INFO] {pformat(printer.stats())}\n") + self.show_treeview() + # Populate the Treeview + self.populate_treeview('', self.tree, printer.stats()) + # Expand all nodes + self.expand_all(self.tree) except Exception as e: + self.show_status_text_view() self.status_text.insert(tk.END, f"[ERROR] {e}\n") - + def reset_waste_ink(self): + self.show_status_text_view() model = self.model_var.get() ip_address = self.ip_var.get() if not model or not self._is_valid_ip(ip_address): @@ -94,6 +151,7 @@ class EpsonPrinterUI(tk.Tk): self.status_text.insert(tk.END, f"[ERROR] {e}\n") def start_detect_printers(self): + self.show_status_text_view() self.status_text.insert(tk.END, "[INFO] Detecting printers... (this might take a while)\n") self.detect_button.config(state=tk.DISABLED) # disable button while processing @@ -101,6 +159,7 @@ class EpsonPrinterUI(tk.Tk): threading.Thread(target=self.detect_printers).start() def detect_printers(self): + self.show_status_text_view() printer_scanner=PrinterScanner() try: printers = printer_scanner.get_all_printers() @@ -121,6 +180,74 @@ class EpsonPrinterUI(tk.Tk): except ValueError: return False + def is_simple_type(self, data): + return isinstance(data, (str, int, float, bool)) + + def contains_parentheses(self, data): + """Check if a string representation contains parentheses.""" + if isinstance(data, (list, tuple, set)): + for item in data: + if isinstance(item, (tuple, list, set)): + return True + if isinstance(item, str) and ('(' in item or ')' in item): + return True + return False + + def populate_treeview(self, parent, treeview, data): + if isinstance(data, dict): + for key, value in data.items(): + if isinstance(value, (dict, list, set, tuple)): + node = treeview.insert(parent, 'end', text=key) + self.populate_treeview(node, treeview, value) + else: + treeview.insert(parent, 'end', text=f"{key}: {value}") + elif isinstance(data, list): + if all(self.is_simple_type(item) for item in data) and not self.contains_parentheses(data): + treeview.insert(parent, 'end', text=', '.join(map(str, data))) + else: + for item in data: + if isinstance(item, (dict, list, set, tuple)): + self.populate_treeview(parent, treeview, item) + else: + treeview.insert(parent, 'end', text=str(item)) + elif isinstance(data, set): + if not self.contains_parentheses(data): + treeview.insert(parent, 'end', text=', '.join(map(str, data))) + else: + for item in data: + treeview.insert(parent, 'end', text=str(item)) + elif isinstance(data, tuple): + treeview.insert(parent, 'end', text=str(data)) + else: + treeview.insert(parent, 'end', text=str(data)) + + def expand_all(self, treeview): + def recursive_expand(item): + treeview.item(item, open=True) + children = treeview.get_children(item) + for child in children: + recursive_expand(child) + + root_children = treeview.get_children() + for child in root_children: + recursive_expand(child) + + def show_context_menu(self, event): + """Show the context menu.""" + # Select the item under the cursor + item = self.tree.identify_row(event.y) + if item: + self.tree.selection_set(item) + self.context_menu.post(event.x_root, event.y_root) + + def copy_selected_item(self): + """Copy the selected Treeview item text to the clipboard.""" + selected_item = self.tree.selection() + if selected_item: + item_text = self.tree.item(selected_item[0], "text") + self.clipboard_clear() + self.clipboard_append(item_text) + if __name__ == "__main__": app = EpsonPrinterUI() app.mainloop()