diff --git a/src/brovski-adress-etiketten-verwaltung.py b/src/brovski-adress-etiketten-verwaltung.py index 588f317..ebcedff 100644 --- a/src/brovski-adress-etiketten-verwaltung.py +++ b/src/brovski-adress-etiketten-verwaltung.py @@ -1,12 +1,88 @@ import csv import os +import sys import tkinter as tk -from configparser import NoOptionError +from tkinter import font, filedialog +from configparser import NoSectionError, NoOptionError from configparser import ConfigParser from tkinter import messagebox from tkinter import ttk import json +class SettingsWindow(tk.Toplevel): + def __init__(self, root: tk.Tk): + super().__init__() + self.root = root + self.protocol("WM_DELETE_WINDOW", self.close_window) + self.geometry(f"500x330+{self.root.winfo_x()+20}+{self.root.winfo_y()+20}") + + self.config = Config() + + self.json_file = tk.StringVar() + self.csv_file = tk.StringVar() + + title = font.Font(family='Ubuntu Mono', size=20, weight=font.BOLD) + tk.Label(self, text="Einstellungen", font=title).pack(pady=20) + + path_frame = tk.Frame(self) + path_frame.pack(pady=(10, 40)) + + tk.Label(path_frame, text="Datenpfad JSON Datei").grid(row=0, column=0) + tk.Entry(path_frame, textvariable=self.json_file, width=50).grid(row=1, column=0) + tk.Button(path_frame, text="Pfad", command=self.set_json_path).grid(row=1, column=1) + + tk.Label(path_frame, text="Datenpfad CSV Export Datei").grid(row=2, column=0) + tk.Entry(path_frame, textvariable=self.csv_file, width=50).grid(row=3, column=0) + tk.Button(path_frame, text="Pfad", command=self.set_csv_path).grid(row=3, column=1) + + bottom_frame = tk.Frame(self) + bottom_frame.pack() + tk.Button(bottom_frame, text="Ok", command=self.ok).pack(side=tk.LEFT) + tk.Button(bottom_frame, text="Abbrechen", command=self.cancel).pack(side=tk.LEFT) + + self.load_config() + + def set_json_path(self): + self.json_file.set(filedialog.askdirectory(initialdir="~/", title="Datenpfad JSON Datei")) + + def set_csv_path(self): + self.csv_file.set(filedialog.askdirectory(initialdir="~/", title="Datenpfad CSV Datei")) + + def load_config(self): + try: + self.json_file.set(self.config.get("json", "path")) + except NoSectionError: + self.config.add_section("json") + self.config.set("json", "path", "") + except NoOptionError: + self.config.set("json", "path", "") + + try: + self.csv_file.set(self.config.get("csv", "path")) + except NoSectionError: + self.config.add_section("csv") + self.config.set("csv", "path", "") + except NoOptionError: + self.config.set("csv", "path", "") + + def ok(self): + self.config.set("json", "path", self.json_file.get()) + self.config.set("csv", "path", self.csv_file.get()) + self.close_window() + + def cancel(self): + self.close_window() + + def close_window(self): + if self.json_file.get() == "" or self.csv_file.get() == "": + messagebox.showwarning(title="Fehlerhafte Konfiguration", message="Pfad für JSON oder CSV Datei fehlt") + return + self.destroy_window() + + def destroy_window(self): + self.root.update() + self.root.deiconify() + self.destroy() class Config: parser: ConfigParser @@ -51,16 +127,6 @@ class Config: class Application: def __init__(self): - self.config = Config() - - self.address_list = [] - self.current_record: int | None = None - - # json vars - self.json_file_name = "files/address_data.json" - self.root_path = os.path.dirname(os.path.abspath(__file__)) - self.json_file = os.path.join(self.root_path, self.json_file_name) - # tkinter settings x_offset = 700 y_offset = 400 @@ -68,14 +134,37 @@ class Application: self.root = tk.Tk(className="BrovskiAdressEtiketten") self.root.title(title) + self.root.protocol("WM_DELETE_WINDOW", self.on_close) self.root.geometry(f"+{x_offset}+{y_offset}") + self.config = Config() + self.config_good = False + + self.address_list = [] + self.current_record: int | None = None + + # init paths to json and csv file + self.json_file_name ="brovski-adress-etiketten-verwaltung.json" + self.csv_file_name = "brovski-adress-etiketten.csv" + self.json_path = "" + self.csv_path = "" + self.load_config() + self.json_file = os.path.join(self.json_path, self.json_file_name) + self.csv_file = os.path.join(self.csv_path, self.csv_file_name) + + # leave application if settings are bad + if not self.config_good: + self.show_error("Fehler Konfiguration", + "Die Konfiguration ist fehlerhaft, bitte prüfe deine config.ini") + sys.exit() top_frame = tk.Frame(self.root) top_frame.pack(side=tk.TOP, fill=tk.X) button_width = 8 - tk.Button(top_frame, text="Export CSV", command=self.export_csv, width=button_width).grid(row=0, column=2) - tk.Button(top_frame, text="Insert", command=self.insert_record, width=button_width).grid(row=0, column=0) - tk.Button(top_frame, text="Delete", command=self.delete_record, width=button_width).grid(row=0, column=1) + tk.Button(top_frame, text="Insert", command=self.insert_record, width=button_width).pack(side=tk.LEFT) + tk.Button(top_frame, text="Delete", command=self.delete_record, width=button_width).pack(side=tk.LEFT) + tk.Button(top_frame, text="Export CSV", command=self.export_csv, width=button_width).pack(side=tk.LEFT) + tk.Button(top_frame, text="Quit", command=self.on_close, width=button_width).pack(side=tk.RIGHT) + tk.Button(top_frame, text="Settings", command=self.show_settings, width=button_width).pack(side=tk.RIGHT) self.aktiv = tk.StringVar() self.firma = tk.StringVar() @@ -115,10 +204,36 @@ class Application: self.table.bind("", self.mouse_click) - self._load_file() + self._load_json_file() self.root.mainloop() + def load_config(self): + try: + self.json_path = self.config.get("json", "path") + self.csv_path = self.config.get("csv", "path") + self.config_good = True + except NoSectionError: + self.show_config_error() + self.show_settings() + except NoOptionError: + self.show_config_error() + self.show_settings() + + + def show_config_error(self): + if self.show_error("Fehlerhafte Konfiguration", + "Konnte benötigte Parameter in config.ini nicht finden"): + print("Fehlerhafte Konfiguration") + + def on_close(self): + self.root.destroy() + + def show_settings(self): + self.root.withdraw() + settings = SettingsWindow(self.root) + settings.wait_window() + def insert_record(self): if self.current_record is not None: self.clear_entry_fields() @@ -131,7 +246,7 @@ class Application: "Plz/Ort", ] self.table.insert('', 'end', values=values) - self._save_file() + self._save_json_file() def delete_record(self): if self.current_record is None: @@ -143,7 +258,7 @@ class Application: self.table.delete(self.current_record) self.clear_entry_fields() - self._save_file() + self._save_json_file() def clear_entry_fields(self): @@ -197,24 +312,24 @@ class Application: self.table.set(self.current_record, key, value) self.clear_entry_fields() - self._save_file() + self._save_json_file() - def _load_file(self): + def _load_json_file(self): try: with open(self.json_file, "r", encoding="utf-8") as f: self.address_list = json.load(f) self.address_list.sort(key=lambda x: (x[0], x[1])) except FileNotFoundError: self.show_error( - message_title="File not found", - message=f"{self.json_file_name} not found, creating empty file at {self.root_path}" + message_title="Datei nicht gefunden", + message=f"{self.json_file_name} nicht gefunden, erstelle leere Datei unter {self.json_path}" ) - self.address_list = [["firma", "name", "adresse", "plz/ort"]] + self.address_list = [["", "firma", "name", "adresse", "plz/ort"]] with open(self.json_file, "w", encoding="utf-8") as f: json.dump(self.address_list, f) self.populate_table() - def _save_file(self): + def _save_json_file(self): self.export_table_to_address_list() try: with open(self.json_file, "w", encoding="utf-8") as f: @@ -226,31 +341,7 @@ class Application: def export_csv(self): try: - file_name = self.config.get("csv", "file_name") - except NoOptionError: - self.show_error("Error: Option missing", "Option file_name is missing [csv]") - return - - try: - path = self.config.get("csv", "path") - except NoOptionError: - self.show_error("Error: Option missing", "Option path is missing [csv]") - return - - if file_name == "": - self.show_error("Error: Bad config file", "var file_name for section [csv] not set") - return - - if path == "": - self.show_error( - "Alert: CSV path not set", - f"var path for section [csv] not set, file will be saved in {self.root_path}" - ) - path = self.root_path - - csv_file = os.path.join(path, file_name) - try: - with open(csv_file, "w", encoding="utf-8") as f: + with open(self.csv_file, "w", encoding="utf-8") as f: writer = csv.writer(f, delimiter=",") for address in self.address_list: if address[0] != "x": @@ -260,7 +351,7 @@ class Application: del address[0] writer.writerow(address) except FileNotFoundError: - self.show_error("Unexpected error", f"Could not write file {csv_file}") + self.show_error("Unexpected error", f"Could not write file {self.csv_file}") def populate_table(self): self.delete_all_table_items()