Listing 13-13: Complete Site Manager

##############################################################################
# Python From Scratch
# Autor: Nilo Ney Coutinho Menezes
# Editora Novatec (c) 2010-2024
# Site: https://pythonfromscratch.com
#
# File: listing\chapter 13\13.13 - Complete Site Manager.py
# Description: Complete Site Manager
##############################################################################

import tkinter as tk
import tkinter.ttk as ttk
from tkinter.filedialog import askopenfilename, asksaveasfilename
from tkinter.messagebox import askquestion, showinfo
from manager import SiteManager
from window import Window

class App(tk.Tk):
    MIN_X = 800
    MIN_Y = 200
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.title("Web Sites Bookmarker")
        self.geometry(f"{self.MIN_X}x{self.MIN_Y}")
        self.create_controls()
        self.manager = SiteManager()
        self.manager.load("data.json")
        self.show_data()
        self.minsize(self.MIN_X, self.MIN_Y)

    def create_controls(self):
        self.frame = ttk.Frame(self)
        self.frame.grid(row=0, column=0, columnspan=2, padx=10, pady=10, sticky=tk.NSEW)
        self.grid_rowconfigure(0, weight=1)
        self.table = ttk.Treeview(
            self.frame, columns=["url", "category", "date", "notes"],
            show="headings")
        self.table.heading("url", text="URL")
        self.table.heading("category", text="Category")
        self.table.column("category", anchor=tk.CENTER)
        self.table.heading("date", text="Date")
        self.table.column("date", anchor=tk.CENTER)
        self.table.heading("notes", text="Notes")
        self.table.grid(row=0, column=0, sticky=tk.NSEW)
        self.table.config(selectmode="browse")
        scrollbar = ttk.Scrollbar(self.frame, orient=tk.VERTICAL, command=self.table.yview)
        self.table.configure(yscroll=scrollbar.set)
        self.table.bind("<Double-Button-1>", self.open_window)
        scrollbar.grid(row=0, column=1, sticky=tk.NS)
        self.frame.grid_columnconfigure(0, weight=1)
        self.frame.grid_rowconfigure(0, weight=1)
        self.frame.pack(expand=True, fill=tk.BOTH, padx=10, pady=10)
        self.menu = tk.Menu(self)
        self.m_file = tk.Menu(self.menu, tearoff=0)
        self.m_file.add_command(label="Load", command=self.load)
        self.m_file.add_command(label="Save", command=self.save)
        self.m_sites = tk.Menu(self.menu, tearoff=0)
        self.m_sites.add_command(label="Add", command=self.add)
        self.m_sites.add_command(label="Delete", command=self.delete)
        self.m_sites.add_separator()
        self.m_sites.add_command(label="Delete all", command=self.delete_all)
        self.menu.add_cascade(label="File", menu=self.m_file)
        self.menu.add_cascade(label="Sites", menu=self.m_sites)
        self.menu.add_command(label="About", command=self.about)
        self.config(menu=self.menu)

    def add(self):
        self.show_site(None)

    def delete(self):
        if selected_id := self.get_selected():
            del self.manager.sites[selected_id]
            self.table.delete(selected_id)

    def delete_all(self):
        if askquestion(title="Delete all sites", message="Are you sure to delete all sites?") == "yes":
            self.clear()

    def clear(self):
        self.manager.sites.clear()
        self.table.delete(*self.table.get_children())

    def about(self):
        showinfo(title="About",
            message="Introduction to Programming with Python. \nhttps://pythonfromscratch.com ")

    def load(self):
        if name := askopenfilename(filetypes=[("JSON", "*.json")]):
            self.clear()
            self.manager.load(name)
            self.show_data()

    def save(self):
        if name := asksaveasfilename(
            filetypes=[("JSON", "*.json")], defaultextension=".json"):
            self.manager.save(name)

    def add_site_to_table(self, site):
        self.table.insert("", tk.END,
            values=(site.url, site.category, site.date, site.notes),
            iid=site.id)

    def show_data(self):
        for site in self.manager.sites.values():
            self.add_site_to_table(site)

    def get_selected(self):
        if item_selected := self.table.selection():
            selected_id = item_selected[0]
            return selected_id
        return None

    def open_window(self, event):
        if selected_id := self.get_selected():
            site = self.manager.sites[selected_id]
        else:
            site = None
        self.show_site(site)

    def show_site(self, site):
        self.window = Window(self, site, on_change=self.update)
        self.window.grab_set()

    def update(self, site):
        if self.table.exists(site.id):
            self.table.item(site.id, text="",
                values=(site.url, site.category, site.date, site.notes))
        else:
            self.add_site_to_table(site)
        self.manager.sites[site.id] = site

App().mainloop()
Click here to download the file