755 lines
25 KiB
Python
755 lines
25 KiB
Python
import os
|
|
import sys
|
|
import tkinter as tk
|
|
from tkinter import ttk
|
|
from datetime import datetime
|
|
from docx import Document
|
|
from tkinter import filedialog
|
|
from PIL import Image
|
|
import tempfile
|
|
from docx.shared import Inches, Pt, RGBColor
|
|
import io
|
|
|
|
|
|
TEMPLATE_DOCX = "Corpus.docx"
|
|
|
|
def resource_path(relative_path: str) -> str:
|
|
try:
|
|
base_path = sys._MEIPASS
|
|
except Exception:
|
|
base_path = os.path.abspath(".")
|
|
return os.path.join(base_path, relative_path)
|
|
|
|
def image_to_png_stream(image_path: str) -> io.BytesIO:
|
|
with Image.open(image_path) as img:
|
|
if img.mode not in ("RGB", "RGBA"):
|
|
img = img.convert("RGB")
|
|
bio = io.BytesIO()
|
|
img.save(bio, format="PNG")
|
|
bio.seek(0)
|
|
return bio
|
|
|
|
|
|
def insert_image_at_placeholder(doc: Document, placeholder: str, image_path: str, width_inches: float = 6.20) -> bool:
|
|
if not image_path or not os.path.exists(image_path):
|
|
return False
|
|
try:
|
|
img_stream = image_to_png_stream(image_path)
|
|
except Exception as e:
|
|
raise ValueError(f"Não consegui abrir/convert a imagem:\n{image_path}\n\nDetalhes:\n{e}")
|
|
|
|
def replace_in_paragraph(p) -> bool:
|
|
full_text = "".join(run.text for run in p.runs)
|
|
if placeholder not in full_text:
|
|
return False
|
|
for r in p.runs:
|
|
r.text = ""
|
|
run = p.add_run()
|
|
run.add_picture(img_stream, width=Inches(width_inches))
|
|
return True
|
|
for p in doc.paragraphs:
|
|
if replace_in_paragraph(p):
|
|
return True
|
|
|
|
for table in doc.tables:
|
|
for row in table.rows:
|
|
for cell in row.cells:
|
|
for p in cell.paragraphs:
|
|
if replace_in_paragraph(p):
|
|
return True
|
|
for section in doc.sections:
|
|
for p in section.header.paragraphs:
|
|
if replace_in_paragraph(p):
|
|
return True
|
|
for p in section.footer.paragraphs:
|
|
if replace_in_paragraph(p):
|
|
return True
|
|
|
|
return False
|
|
|
|
|
|
def insert_images_at_placeholders(doc: Document, placeholders: dict, width_inches: float = 6.20) -> list:
|
|
missing = []
|
|
for placeholder, image_path in placeholders.items():
|
|
if not image_path:
|
|
continue
|
|
ok = insert_image_at_placeholder(doc, placeholder, image_path, width_inches=width_inches)
|
|
if not ok:
|
|
missing.append(placeholder)
|
|
return missing
|
|
|
|
def insert_tecnicas_utilizadas(doc: Document, placeholder: str, tecnicas: list) -> bool:
|
|
def replace_in_paragraph(p) -> bool:
|
|
full_text = "".join(run.text for run in p.runs)
|
|
if placeholder not in full_text:
|
|
return False
|
|
for r in p.runs:
|
|
r.text = ""
|
|
|
|
first_block = True
|
|
for t in tecnicas:
|
|
if not t.get("selected"):
|
|
continue
|
|
nome = (t.get("name") or "").strip()
|
|
desc = (t.get("desc") or "").strip()
|
|
fotos = t.get("photos") or []
|
|
|
|
if not nome:
|
|
continue
|
|
if not first_block:
|
|
p.add_run().add_break()
|
|
p.add_run().add_break()
|
|
|
|
run_title = p.add_run(nome)
|
|
run_title.font.name = "Verdana"
|
|
run_title.font.size = Pt(11)
|
|
run_title.font.color.rgb = RGBColor(0x4A, 0x66, 0xAC)
|
|
p.add_run().add_break()
|
|
|
|
if desc:
|
|
run_desc = p.add_run(desc)
|
|
run_desc.font.name = "Verdana"
|
|
run_desc.font.size = Pt(10)
|
|
run_desc.font.color.rgb = RGBColor(0x66, 0x66, 0x66)
|
|
p.add_run().add_break()
|
|
|
|
if fotos:
|
|
for i, image_path in enumerate(fotos):
|
|
if not image_path or not os.path.exists(image_path):
|
|
continue
|
|
try:
|
|
img_stream = image_to_png_stream(image_path)
|
|
except Exception as e:
|
|
raise ValueError(f"Não consegui abrir/convert a imagem:\n{image_path}\n\nDetalhes:\n{e}")
|
|
run_img = p.add_run()
|
|
run_img.add_picture(img_stream, width=Inches(2.80))
|
|
is_last = i == len(fotos) - 1
|
|
if not is_last:
|
|
if i % 2 == 0:
|
|
p.add_run(" ")
|
|
else:
|
|
p.add_run().add_break()
|
|
p.add_run().add_break()
|
|
|
|
first_block = False
|
|
|
|
return True
|
|
|
|
for p in doc.paragraphs:
|
|
if replace_in_paragraph(p):
|
|
return True
|
|
|
|
for table in doc.tables:
|
|
for row in table.rows:
|
|
for cell in row.cells:
|
|
for p in cell.paragraphs:
|
|
if replace_in_paragraph(p):
|
|
return True
|
|
|
|
for section in doc.sections:
|
|
for p in section.header.paragraphs:
|
|
if replace_in_paragraph(p):
|
|
return True
|
|
for p in section.footer.paragraphs:
|
|
if replace_in_paragraph(p):
|
|
return True
|
|
|
|
return False
|
|
|
|
def insert_metodos_utilizados(doc: Document, placeholder: str, values: dict) -> bool:
|
|
items = []
|
|
seen = set()
|
|
for group_key in ("inicio_pesquisa", "tecnicas"):
|
|
for t in values.get(group_key) or []:
|
|
if not t.get("selected"):
|
|
continue
|
|
name = (t.get("name") or "").strip()
|
|
if not name or name in seen:
|
|
continue
|
|
seen.add(name)
|
|
items.append(name)
|
|
|
|
if not items:
|
|
return False
|
|
|
|
def replace_in_paragraph(p) -> bool:
|
|
full_text = "".join(run.text for run in p.runs)
|
|
if placeholder not in full_text:
|
|
return False
|
|
for r in p.runs:
|
|
r.text = ""
|
|
|
|
for i, name in enumerate(items):
|
|
run = p.add_run(f"- {name}")
|
|
run.font.name = "Verdana"
|
|
run.font.size = Pt(10)
|
|
run.font.color.rgb = RGBColor(0x66, 0x66, 0x66)
|
|
if i < len(items) - 1:
|
|
p.add_run().add_break()
|
|
return True
|
|
|
|
for p in doc.paragraphs:
|
|
if replace_in_paragraph(p):
|
|
return True
|
|
|
|
for table in doc.tables:
|
|
for row in table.rows:
|
|
for cell in row.cells:
|
|
for p in cell.paragraphs:
|
|
if replace_in_paragraph(p):
|
|
return True
|
|
|
|
for section in doc.sections:
|
|
for p in section.header.paragraphs:
|
|
if replace_in_paragraph(p):
|
|
return True
|
|
for p in section.footer.paragraphs:
|
|
if replace_in_paragraph(p):
|
|
return True
|
|
|
|
return False
|
|
def insert_multiple_images_at_placeholder(doc: Document, placeholder: str, image_paths: list, width_inches: float = 2.80) -> bool:
|
|
if not image_paths:
|
|
return False
|
|
|
|
def replace_in_paragraph(p) -> bool:
|
|
full_text = "".join(run.text for run in p.runs)
|
|
if placeholder not in full_text:
|
|
return False
|
|
for r in p.runs:
|
|
r.text = ""
|
|
for i, image_path in enumerate(image_paths):
|
|
if not image_path or not os.path.exists(image_path):
|
|
continue
|
|
try:
|
|
img_stream = image_to_png_stream(image_path)
|
|
except Exception as e:
|
|
raise ValueError(f"Não consegui abrir/convert a imagem:\n{image_path}\n\nDetalhes:\n{e}")
|
|
run = p.add_run()
|
|
run.add_picture(img_stream, width=Inches(width_inches))
|
|
is_last = i == len(image_paths) - 1
|
|
if not is_last:
|
|
if i % 2 == 0:
|
|
p.add_run(" ")
|
|
else:
|
|
p.add_run().add_break()
|
|
return True
|
|
|
|
for p in doc.paragraphs:
|
|
if replace_in_paragraph(p):
|
|
return True
|
|
|
|
for table in doc.tables:
|
|
for row in table.rows:
|
|
for cell in row.cells:
|
|
for p in cell.paragraphs:
|
|
if replace_in_paragraph(p):
|
|
return True
|
|
|
|
for section in doc.sections:
|
|
for p in section.header.paragraphs:
|
|
if replace_in_paragraph(p):
|
|
return True
|
|
for p in section.footer.paragraphs:
|
|
if replace_in_paragraph(p):
|
|
return True
|
|
|
|
return False
|
|
|
|
|
|
def fatal_popup_and_exit(title: str, msg: str, exit_code: int = 1):
|
|
win = tk.Tk()
|
|
win.title(title)
|
|
win.geometry("520x260")
|
|
win.resizable(False, False)
|
|
frm = ttk.Frame(win, padding=14)
|
|
frm.pack(fill="both", expand=True)
|
|
ttk.Label(frm, text=title, font=("Segoe UI", 12, "bold")).pack(anchor="w", pady=(0, 8))
|
|
txt = tk.Text(frm, height=8, wrap="word")
|
|
txt.pack(fill="both", expand=True)
|
|
txt.insert("1.0", msg)
|
|
txt.config(state="disabled")
|
|
def close_and_exit():
|
|
win.destroy()
|
|
raise SystemExit(exit_code)
|
|
ttk.Button(frm, text="OK", command=close_and_exit).pack(anchor="e", pady=(10, 0))
|
|
win.protocol("WM_DELETE_WINDOW", close_and_exit)
|
|
win.mainloop()
|
|
|
|
def info_popup(title: str, msg: str):
|
|
win = tk.Toplevel()
|
|
win.title(title)
|
|
win.geometry("520x240")
|
|
win.resizable(False, False)
|
|
frm = ttk.Frame(win, padding=14)
|
|
frm.pack(fill="both", expand=True)
|
|
ttk.Label(frm, text=title, font=("Segoe UI", 12, "bold")).pack(anchor="w", pady=(0, 8))
|
|
txt = tk.Text(frm, height=7, wrap="word")
|
|
txt.pack(fill="both", expand=True)
|
|
txt.insert("1.0", msg)
|
|
txt.config(state="disabled")
|
|
def close():
|
|
win.destroy()
|
|
ttk.Button(frm, text="OK", command=close).pack(anchor="e", pady=(10, 0))
|
|
win.grab_set()
|
|
win.focus_force()
|
|
|
|
def replace_placeholders_in_doc(doc: Document, mapping: dict) -> None:
|
|
for p in doc.paragraphs:
|
|
text = p.text
|
|
new_text = text
|
|
for k, v in mapping.items():
|
|
new_text = new_text.replace(k, v)
|
|
if new_text != text:
|
|
p.text = new_text
|
|
for table in doc.tables:
|
|
for row in table.rows:
|
|
for cell in row.cells:
|
|
for p in cell.paragraphs:
|
|
text = p.text
|
|
new_text = text
|
|
for k, v in mapping.items():
|
|
new_text = new_text.replace(k, v)
|
|
if new_text != text:
|
|
p.text = new_text
|
|
|
|
def generate_output_filename() -> str:
|
|
stamp = datetime.now().strftime("%Y-%m-%d_%H-%M-%S")
|
|
return f"{stamp}.docx"
|
|
|
|
def build_presence_text(values: dict) -> str:
|
|
parts = []
|
|
present_people = []
|
|
|
|
presencas = values.get("presencas") or []
|
|
|
|
if not presencas:
|
|
if values.get("segurado_presente"):
|
|
presencas.append(
|
|
{
|
|
"tipo": "segurado",
|
|
"nome": values.get("segurado_nome"),
|
|
"info": values.get("segurado_info"),
|
|
}
|
|
)
|
|
if values.get("lesado_presente"):
|
|
presencas.append(
|
|
{
|
|
"tipo": "lesado",
|
|
"nome": values.get("lesado_nome"),
|
|
"info": values.get("lesado_info"),
|
|
}
|
|
)
|
|
if values.get("outro_presente"):
|
|
presencas.append(
|
|
{
|
|
"tipo": "outro",
|
|
"nome": values.get("outro_nome"),
|
|
"info": values.get("outro_info"),
|
|
}
|
|
)
|
|
|
|
def join_people(items: list) -> str:
|
|
if not items:
|
|
return ""
|
|
if len(items) == 1:
|
|
return items[0]
|
|
return ", ".join(items[:-1]) + " e " + items[-1]
|
|
|
|
for item in presencas:
|
|
tipo = (item.get("tipo") or "").strip().lower()
|
|
nome = (item.get("nome") or "").strip()
|
|
info = (item.get("info") or "").strip()
|
|
if not nome:
|
|
continue
|
|
|
|
if tipo == "segurado":
|
|
present_people.append(f"o segurado, {nome}")
|
|
if info:
|
|
parts.append(f"O segurado, {nome} informou que {info}.")
|
|
elif tipo == "lesado":
|
|
present_people.append(f"o lesado, {nome}")
|
|
if info:
|
|
parts.append(f"O lesado, {nome} informou que {info}.")
|
|
else:
|
|
present_people.append(nome)
|
|
if info:
|
|
parts.append(f"{nome} informou que {info}.")
|
|
|
|
header = ""
|
|
if present_people:
|
|
joined = join_people(present_people)
|
|
if len(present_people) == 1:
|
|
header = f"{joined} esteve presente aquando a pesquisa."
|
|
else:
|
|
header = f"{joined} estiveram presentes aquando a pesquisa."
|
|
|
|
if header and parts:
|
|
return header + "\n\n" + "\n".join(parts)
|
|
if header:
|
|
return header
|
|
if parts:
|
|
return "\n".join(parts)
|
|
return ""
|
|
|
|
def run_generation(values: dict, root: tk.Tk):
|
|
mapping = {
|
|
"{{nproc}}": (values.get("nproc") or "").strip(),
|
|
"{{segurado}}": (values.get("segurado") or "").strip(),
|
|
"{{comp}}": (values.get("comp") or "").strip(),
|
|
"{{terceiro}}": (values.get("terceiro") or "").strip(),
|
|
"{{data}}": (values.get("data") or "").strip(),
|
|
"{{local da visita}}": (values.get("local") or "").strip(),
|
|
"{{descriçãoimovel}}": (values.get("descriçãoimovel") or "").strip(),
|
|
"{{anoconstr}}": (values.get("anoconstr") or "").strip(),
|
|
"{{presencas}}": build_presence_text(values),
|
|
"{{descricao}}": (values.get("descricao") or "").strip(),
|
|
"{{area}}": (values.get("area") or "").strip(),
|
|
}
|
|
|
|
template_path = resource_path(TEMPLATE_DOCX)
|
|
if not os.path.exists(template_path):
|
|
try:
|
|
root.destroy()
|
|
except Exception:
|
|
pass
|
|
|
|
fatal_popup_and_exit(
|
|
"Erro: template não encontrado",
|
|
f"Não encontrei o template '{TEMPLATE_DOCX}'.\n\n"
|
|
f"Coloca o ficheiro '{TEMPLATE_DOCX}' na mesma pasta do executável e volta a executar."
|
|
)
|
|
return
|
|
|
|
output_docx = generate_output_filename()
|
|
|
|
try:
|
|
doc = Document(template_path)
|
|
replace_placeholders_in_doc(doc, mapping)
|
|
foto1_path = (values.get("foto1_path") or "").strip()
|
|
fotos2_paths = values.get("fotos2_paths") or []
|
|
placeholders = {
|
|
"{{foto1}}": foto1_path,
|
|
}
|
|
missing = insert_images_at_placeholders(doc, placeholders, width_inches=6.20)
|
|
if missing:
|
|
info_popup(
|
|
"Aviso",
|
|
"Não encontrei os placeholders no template (corpo/cabeçalho/rodapé):\n"
|
|
+ ", ".join(missing)
|
|
)
|
|
if fotos2_paths:
|
|
ok_multi = insert_multiple_images_at_placeholder(doc, "{{foto2}}", fotos2_paths, width_inches=2.80)
|
|
if not ok_multi:
|
|
info_popup(
|
|
"Aviso",
|
|
"Não encontrei o placeholder {{foto2}} no template (corpo/cabeçalho/rodapé)."
|
|
)
|
|
tecnicas = values.get("tecnicas") or []
|
|
if tecnicas:
|
|
ok_tecnicas = insert_tecnicas_utilizadas(doc, "{{tecnicasutilizadas}}", tecnicas)
|
|
if not ok_tecnicas:
|
|
info_popup(
|
|
"Aviso",
|
|
"Não encontrei o placeholder {{tecnicasutilizadas}} no template (corpo/cabeçalho/rodapé)."
|
|
)
|
|
inicio_pesquisa = values.get("inicio_pesquisa") or []
|
|
if inicio_pesquisa:
|
|
ok_inicio = insert_tecnicas_utilizadas(doc, "{{iniciopesquisa}}", inicio_pesquisa)
|
|
if not ok_inicio:
|
|
info_popup(
|
|
"Aviso",
|
|
"Não encontrei o placeholder {{iniciopesquisa}} no template (corpo/cabeçalho/rodapé)."
|
|
)
|
|
if values.get("inicio_pesquisa") or values.get("tecnicas"):
|
|
ok_metodos = insert_metodos_utilizados(doc, "{{metodosutilizados}}", values)
|
|
if not ok_metodos:
|
|
info_popup(
|
|
"Aviso",
|
|
"Não encontrei o placeholder {{metodosutilizados}} no template (corpo/cabeçalho/rodapé)."
|
|
)
|
|
doc.save(output_docx)
|
|
info_popup("Sucesso", f"Documento gerado com sucesso:\n\n{output_docx}")
|
|
|
|
except Exception as e:
|
|
try:
|
|
root.destroy()
|
|
except Exception:
|
|
pass
|
|
|
|
fatal_popup_and_exit(
|
|
"Erro ao gerar documento",
|
|
f"Falhou ao gerar o documento.\n\nDetalhes:\n{e}"
|
|
)
|
|
|
|
def choose_image(foto_var):
|
|
path = filedialog.askopenfilename(
|
|
title="Selecionar fotografia",
|
|
filetypes=[
|
|
("Imagens", "*.png *.jpg *.jpeg *.bmp"),
|
|
("Todos os ficheiros", "*.*"),
|
|
],
|
|
)
|
|
if path:
|
|
foto_var.set(path)
|
|
|
|
def choose_images(fotos_var, label_var):
|
|
paths = filedialog.askopenfilenames(
|
|
title="Selecionar fotografias",
|
|
filetypes=[
|
|
("Imagens", "*.png *.jpg *.jpeg *.bmp"),
|
|
("Todos os ficheiros", "*.*"),
|
|
],
|
|
)
|
|
if paths:
|
|
fotos_var.set(list(paths))
|
|
label_var.set(f"{len(paths)} imagem(ns)")
|
|
|
|
def main():
|
|
root = tk.Tk()
|
|
root.title("Preencher Corpus (Word)")
|
|
root.geometry("1120x640")
|
|
root.resizable(False, False)
|
|
|
|
frm = ttk.Frame(root, padding=16)
|
|
frm.pack(fill="both", expand=True)
|
|
|
|
fields = [("Nº do Processo:", "nproc"),("Segurado:", "segurado"),
|
|
("Companhia:", "comp"),
|
|
("Terceiro:", "terceiro"),
|
|
("Data da visita:", "data"),
|
|
("Local da visita:", "local"),
|
|
("Descrição do imóvel:", "descriçãoimovel"),
|
|
("Ano de Construção:", "anoconstr"),
|
|
("Descrição da pesquisa:", "descricao"),
|
|
("Área do do espaço:", "area")
|
|
]
|
|
|
|
entries = {}
|
|
foto_var = tk.StringVar(value="")
|
|
fotos2_var = tk.Variable(value=[])
|
|
fotos2_label = tk.StringVar(value="")
|
|
tecnicas_data = []
|
|
inicio_data = []
|
|
|
|
for i, (label, key) in enumerate(fields):
|
|
ttk.Label(frm, text=label).grid(row=i, column=0, sticky="w", pady=6)
|
|
ent = ttk.Entry(frm, width=80)
|
|
ent.grid(row=i, column=1, sticky="w", pady=6)
|
|
entries[key] = ent
|
|
if key == "descriçãoimovel":
|
|
ttk.Button(
|
|
frm,
|
|
text="Escolher imagem…",
|
|
command=lambda: choose_image(foto_var)
|
|
).grid(row=i, column=2, sticky="w", padx=8)
|
|
|
|
ttk.Label(
|
|
frm,
|
|
textvariable=foto_var,
|
|
width=28
|
|
).grid(row=i, column=4, sticky="w")
|
|
if key == "descricao":
|
|
ttk.Button(
|
|
frm,
|
|
text="Escolher imagens…",
|
|
command=lambda: choose_images(fotos2_var, fotos2_label)
|
|
).grid(row=i, column=2, sticky="w", padx=8)
|
|
|
|
ttk.Label(
|
|
frm,
|
|
textvariable=fotos2_label,
|
|
width=14
|
|
).grid(row=i, column=4, sticky="w")
|
|
|
|
def build_tecnicas_window(title: str, data_list: list):
|
|
win = tk.Toplevel(root)
|
|
win.title(title)
|
|
win.geometry("980x520")
|
|
win.resizable(False, False)
|
|
|
|
container = ttk.Frame(win, padding=16)
|
|
container.pack(fill="both", expand=True)
|
|
|
|
if not data_list:
|
|
tecnicas_list = [
|
|
"Controlo Visual",
|
|
"Medição de humidade",
|
|
"Câmara térmica",
|
|
"Câmara endoscópica",
|
|
"Obturação",
|
|
"Teste de pressão",
|
|
"Teste com corantes",
|
|
]
|
|
for nome in tecnicas_list:
|
|
data_list.append({
|
|
"name": nome,
|
|
"var": tk.BooleanVar(value=False),
|
|
"desc": tk.StringVar(value=""),
|
|
"photos": tk.Variable(value=[]),
|
|
"label": tk.StringVar(value=""),
|
|
})
|
|
|
|
def set_row_state(row_widgets, enabled: bool):
|
|
state = "normal" if enabled else "disabled"
|
|
for w in row_widgets:
|
|
w.configure(state=state)
|
|
|
|
for idx, item in enumerate(data_list):
|
|
row = ttk.Frame(container)
|
|
row.pack(fill="x", pady=6)
|
|
|
|
chk = ttk.Checkbutton(
|
|
row,
|
|
text=item["name"],
|
|
variable=item["var"],
|
|
command=lambda it=item: set_row_state(it["widgets"], it["var"].get())
|
|
)
|
|
chk.grid(row=0, column=0, sticky="w")
|
|
|
|
ttk.Label(row, text="Descrição:").grid(row=0, column=1, sticky="w", padx=(12, 4))
|
|
entry = ttk.Entry(row, textvariable=item["desc"], width=50)
|
|
entry.grid(row=0, column=2, sticky="w")
|
|
|
|
btn = ttk.Button(
|
|
row,
|
|
text="Escolher fotos…",
|
|
command=lambda it=item: choose_images(it["photos"], it["label"])
|
|
)
|
|
btn.grid(row=0, column=3, sticky="w", padx=10)
|
|
|
|
lbl = ttk.Label(row, textvariable=item["label"], width=18)
|
|
lbl.grid(row=0, column=4, sticky="w")
|
|
|
|
item["widgets"] = [entry, btn]
|
|
set_row_state(item["widgets"], item["var"].get())
|
|
|
|
ttk.Button(container, text="Fechar", command=win.destroy).pack(anchor="e", pady=(12, 0))
|
|
win.grab_set()
|
|
win.focus_force()
|
|
|
|
ttk.Button(
|
|
frm,
|
|
text="Técnicas utilizadas…",
|
|
command=lambda: build_tecnicas_window("Técnicas utilizadas", tecnicas_data)
|
|
).grid(row=len(fields), column=0, sticky="w", pady=(14, 0))
|
|
|
|
ttk.Button(
|
|
frm,
|
|
text="Início da pesquisa…",
|
|
command=lambda: build_tecnicas_window("Início da pesquisa", inicio_data)
|
|
).grid(row=len(fields), column=1, sticky="w", pady=(14, 0), padx=(12, 0))
|
|
|
|
presence_frame = ttk.LabelFrame(frm, text="Presencas na pesquisa", padding=12)
|
|
presence_frame.grid(row=len(fields) + 1, column=0, columnspan=4, sticky="w", pady=(12, 6))
|
|
|
|
presenca_rows = {
|
|
"segurado": [],
|
|
"lesado": [],
|
|
"outro": [],
|
|
}
|
|
type_frames = {}
|
|
type_labels = {
|
|
"segurado": "segurado",
|
|
"lesado": "lesado",
|
|
"outro": "outro",
|
|
}
|
|
|
|
def remove_presence_row(tipo: str, row_data: dict):
|
|
row_data["frame"].destroy()
|
|
presenca_rows[tipo] = [r for r in presenca_rows[tipo] if r is not row_data]
|
|
|
|
def add_presence_row(tipo: str):
|
|
container = type_frames[tipo]
|
|
row = ttk.Frame(container)
|
|
row.pack(fill="x", pady=3)
|
|
|
|
nome_var = tk.StringVar(value="")
|
|
info_var = tk.StringVar(value="")
|
|
|
|
ttk.Label(row, text=f"Nome do {type_labels[tipo]}:").grid(row=0, column=0, sticky="w")
|
|
ttk.Entry(row, textvariable=nome_var, width=30).grid(row=0, column=1, sticky="w", padx=6)
|
|
ttk.Label(row, text="Declaracoes:").grid(row=0, column=2, sticky="w", padx=(12, 0))
|
|
ttk.Entry(row, textvariable=info_var, width=42).grid(row=0, column=3, sticky="w", padx=6)
|
|
|
|
row_data = {
|
|
"frame": row,
|
|
"nome": nome_var,
|
|
"info": info_var,
|
|
}
|
|
|
|
ttk.Button(
|
|
row,
|
|
text="Remover",
|
|
command=lambda t=tipo, d=row_data: remove_presence_row(t, d)
|
|
).grid(row=0, column=4, sticky="w", padx=(8, 0))
|
|
|
|
presenca_rows[tipo].append(row_data)
|
|
|
|
def build_presence_section(parent, row_index: int, tipo: str, titulo: str):
|
|
sec = ttk.Frame(parent)
|
|
sec.grid(row=row_index, column=0, sticky="w", pady=4)
|
|
ttk.Label(sec, text=titulo).grid(row=0, column=0, sticky="w")
|
|
ttk.Button(
|
|
sec,
|
|
text=f"Adicionar {type_labels[tipo]}",
|
|
command=lambda t=tipo: add_presence_row(t)
|
|
).grid(row=0, column=1, sticky="w", padx=(10, 0))
|
|
|
|
container = ttk.Frame(sec)
|
|
container.grid(row=1, column=0, columnspan=2, sticky="w", pady=(6, 0))
|
|
type_frames[tipo] = container
|
|
|
|
build_presence_section(presence_frame, 0, "segurado", "Segurados")
|
|
build_presence_section(presence_frame, 1, "lesado", "Lesados")
|
|
build_presence_section(presence_frame, 2, "outro", "Outros")
|
|
|
|
add_presence_row("segurado")
|
|
|
|
|
|
def on_generate():
|
|
values = {k: e.get() for k, e in entries.items()}
|
|
values["foto1_path"] = foto_var.get()
|
|
values["fotos2_paths"] = list(fotos2_var.get()) if fotos2_var.get() else []
|
|
values["tecnicas"] = [
|
|
{
|
|
"name": t["name"],
|
|
"selected": t["var"].get(),
|
|
"desc": t["desc"].get(),
|
|
"photos": list(t["photos"].get()) if t["photos"].get() else [],
|
|
}
|
|
for t in tecnicas_data
|
|
]
|
|
values["inicio_pesquisa"] = [
|
|
{
|
|
"name": t["name"],
|
|
"selected": t["var"].get(),
|
|
"desc": t["desc"].get(),
|
|
"photos": list(t["photos"].get()) if t["photos"].get() else [],
|
|
}
|
|
for t in inicio_data
|
|
]
|
|
values["presencas"] = []
|
|
for tipo in ("segurado", "lesado", "outro"):
|
|
for row in presenca_rows[tipo]:
|
|
values["presencas"].append(
|
|
{
|
|
"tipo": tipo,
|
|
"nome": row["nome"].get(),
|
|
"info": row["info"].get(),
|
|
}
|
|
)
|
|
run_generation(values, root)
|
|
|
|
|
|
btns = ttk.Frame(frm)
|
|
btns.grid(row=len(fields) + 2, column=0, columnspan=2, sticky="w", pady=(18, 0))
|
|
|
|
ttk.Button(btns, text="Gerar Word", command=on_generate).pack(side="left")
|
|
ttk.Button(btns, text="Sair", command=root.destroy).pack(side="left", padx=10)
|
|
|
|
root.mainloop()
|
|
|
|
if __name__ == "__main__":
|
|
main()
|