Files
Brovski-Adress-Etiketten-Ve…/src/brovski-adress-etiketten-verwaltung.py

288 lines
10 KiB
Python

import csv
import os
import tkinter as tk
from configparser import NoOptionError
from configparser import ConfigParser
from tkinter import messagebox
from tkinter import ttk
import json
class Config:
parser: ConfigParser
def __init__(self):
"""
Config parser reading config.ini
Attributes:
self.parser: ConfigParser holding list of sections and options
self.__filename: Path and name to the config file
"""
self.parser = ConfigParser()
self.config_file_name = "files/config.ini"
self.root_path = os.path.dirname(os.path.abspath(__file__))
self.config_file = os.path.join(self.root_path, self.config_file_name)
self._load()
def _save(self):
with open(self.config_file, 'w') as outfile:
self.parser.write(outfile)
def _load(self):
self.parser.read(self.config_file)
def add_section(self, section):
self._load()
self.parser.add_section(section)
self._save()
def set(self, section: str, option: str, value: str):
self._load()
self.parser.set(section, option, value)
self._save()
def get(self, section: str, option: str):
self._load()
return self.parser.get(section, option)
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
title = "Brovski Adress-Etiketten Verwaltung"
self.root = tk.Tk(className="BrovskiAdressEtiketten")
self.root.title(title)
self.root.geometry(f"+{x_offset}+{y_offset}")
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)
self.aktiv = tk.StringVar()
self.firma = tk.StringVar()
self.name = tk.StringVar()
self.strasse = tk.StringVar()
self.plz_ort = tk.StringVar()
edit_frame = tk.Frame(self.root)
edit_frame.pack(side=tk.TOP, fill=tk.X)
tk.Label(edit_frame, text="Aktiv").grid(row=0, column=0)
tk.Label(edit_frame, text="Firma").grid(row=0, column=1)
tk.Label(edit_frame, text="Name").grid(row=0, column=2)
tk.Label(edit_frame, text="Strasse").grid(row=0, column=3)
tk.Label(edit_frame, text="Plz/Ort").grid(row=0, column=4)
edit_aktiv = tk.Checkbutton(edit_frame, variable=self.aktiv, onvalue="x", offvalue="")
edit_aktiv.grid(row=1, column=0)
edit_firma = tk.Entry(edit_frame, textvariable=self.firma)
edit_firma.grid(row=1, column=1)
edit_name = tk.Entry(edit_frame, textvariable=self.name)
edit_name.grid(row=1, column=2)
edit_strasse = tk.Entry(edit_frame, textvariable=self.strasse)
edit_strasse.grid(row=1, column=3)
edit_plz_ort = tk.Entry(edit_frame, textvariable=self.plz_ort)
edit_plz_ort.grid(row=1, column=4)
tk.Button(edit_frame, text="Update", command=self.update_record).grid(row=1, column=5)
data_frame = tk.Frame(self.root, bg="teal")
data_frame.pack(side=tk.TOP, fill=tk.BOTH, expand=True)
self.table = ttk.Treeview(data_frame, columns=("0", "1", "2", "3", "4"), show="headings")
self.table.heading('0', text="Aktiv")
self.table.heading('1', text="Firma")
self.table.heading('2', text="Name")
self.table.heading('3', text="Strasse")
self.table.heading('4', text="Plz/Ort")
self.table.pack()
self.table.bind("<ButtonRelease-1>", self.mouse_click)
self._load_file()
self.root.mainloop()
def insert_record(self):
if self.current_record is not None:
self.clear_entry_fields()
children = self.table.get_children()
values = [
"x",
"Firma",
"Name",
"Strasse",
"Plz/Ort",
]
self.table.insert('', 'end', values=values)
self._save_file()
def delete_record(self):
if self.current_record is None:
return
if messagebox.askyesno(
"Eintrag löschen?",
"Willst du diesen Eintrag wirklich löschen?\nDies kann nicht rückgängig gemacht werden"):
self.table.delete(self.current_record)
self.clear_entry_fields()
self._save_file()
def clear_entry_fields(self):
entry_var_list = [self.aktiv, self.firma, self.name, self.strasse, self.plz_ort]
for entry in entry_var_list:
entry.set("")
self.current_record = None
def mouse_click(self, event):
region = self.table.identify("region", event.x, event.y)
if region == "heading":
column = self.table.identify_column(event.x)
match column:
case "#1":
self.address_list.sort(key=lambda x: x[int(column[-1]) - 1])
self.populate_table()
case "#2":
self.address_list.sort(key=lambda x: x[int(column[-1]) - 1])
self.populate_table()
case "#3":
self.address_list.sort(key=lambda x: x[int(column[-1]) - 1])
self.populate_table()
case "#4":
self.address_list.sort(key=lambda x: x[int(column[-1]) - 1])
self.populate_table()
case "#5":
self.address_list.sort(key=lambda x: x[int(column[-1]) - 1])
self.populate_table()
case _:
print(column)
if region == "cell":
self.current_record = self.table.focus()
values = self.table.item(self.current_record, "values")
entry_var_list = [self.aktiv, self.firma, self.name, self.strasse, self.plz_ort]
for i in range(len(values)):
entry_var_list[i].set(values[i])
def update_record(self):
if self.current_record is None:
return
values = {
0: self.aktiv.get(),
1: self.firma.get(),
2: self.name.get(),
3: self.strasse.get(),
4: self.plz_ort.get(),
}
for key, value in values.items():
self.table.set(self.current_record, key, value)
self.clear_entry_fields()
self._save_file()
def _load_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}"
)
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):
self.export_table_to_address_list()
try:
with open(self.json_file, "w", encoding="utf-8") as f:
json.dump(self.address_list, f, indent=4, sort_keys=True)
except FileNotFoundError:
self.show_error(
message_title="Unexpected Error: File not found?!", message=f"{self.json_file_name} not found"
)
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:
writer = csv.writer(f, delimiter=",")
for address in self.address_list:
if address[0] != "x":
continue
del address[0]
if address[0] == "":
del address[0]
writer.writerow(address)
except FileNotFoundError:
self.show_error("Unexpected error", f"Could not write file {csv_file}")
def populate_table(self):
self.delete_all_table_items()
for index, item in enumerate(self.address_list):
self.table.insert('', 'end', iid=index, values=item)
def export_table_to_address_list(self):
self.address_list.clear()
for child in self.table.get_children():
self.address_list.append([])
for value in self.table.item(child)['values']:
self.address_list[-1].append(value)
def delete_all_table_items(self):
for item in self.table.get_children():
self.table.delete(item)
@staticmethod
def show_error(message_title: str, message: str):
messagebox.showwarning(title=message_title, message=message)
if __name__ == '__main__':
Application()