From d3d141cca8fabdc75ee6789188c121023a003c24 Mon Sep 17 00:00:00 2001 From: Arda Aydin Date: Fri, 11 Sep 2026 13:06:30 +0300 Subject: [PATCH] Kit Manager: add Export as XLS button Saves the kit table to an Excel file with section headers, check marks, and all four data columns. Default filename is based on the open SAX file. Co-Authored-By: Claude Opus 4.6 --- app_state.py | 2 +- manage_kits.py | 70 +++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 70 insertions(+), 2 deletions(-) diff --git a/app_state.py b/app_state.py index 7dc62fe..078f5ca 100644 --- a/app_state.py +++ b/app_state.py @@ -8,7 +8,7 @@ so later rebinding would only ever be seen by the module that did it. import configparser import os -VERSION = "0.0.0.069" +VERSION = "0.0.0.070" PROPERTIES_FILE = os.path.join(os.path.dirname(os.path.abspath(__file__)), "editor.properties") DEFAULT_GRID_SIZE = 10 DEFAULT_ADD_TIMESTAMP = True diff --git a/manage_kits.py b/manage_kits.py index 9fa8408..93b503c 100644 --- a/manage_kits.py +++ b/manage_kits.py @@ -15,8 +15,9 @@ declared can be unticked, which turns its Action into REMOVE. An installed kit t declared starts unticked, and ticking it adds it at its newest build. """ +import os import tkinter as tk -from tkinter import messagebox, ttk +from tkinter import filedialog, messagebox, ttk import app_state import palette @@ -267,6 +268,9 @@ class KitsPanel: button_row, text="Update kits", command=self._update_marked, ).pack(side=tk.LEFT, padx=6) ttk.Button(button_row, text="Close", command=self.close).pack(side=tk.RIGHT) + ttk.Button( + button_row, text="Export as XLS", command=self._export_xls, + ).pack(side=tk.RIGHT, padx=6) self.rows = [] self.row_by_item = {} @@ -286,6 +290,70 @@ class KitsPanel: self._close_editor() self.frame.destroy() + def _export_xls(self): + try: + from openpyxl import Workbook + from openpyxl.styles import Font, PatternFill, Alignment + except ImportError: + messagebox.showerror("Export", "openpyxl is not installed.") + return + + default_name = "" + if app_state.current_file_path: + base = os.path.splitext(os.path.basename(app_state.current_file_path))[0] + default_name = f"{base}_kits.xlsx" + + path = filedialog.asksaveasfilename( + title="Export Kit Table", + defaultextension=".xlsx", + initialfile=default_name, + filetypes=[("Excel Files", "*.xlsx")], + ) + if not path: + return + + wb = Workbook() + ws = wb.active + ws.title = "Kits" + + headers = ["", "Kit name", "Installed", "Latest", "Action"] + header_font = Font(bold=True) + section_fill = PatternFill(start_color="DCDCDC", end_color="DCDCDC", fill_type="solid") + + for col, header in enumerate(headers, 1): + cell = ws.cell(row=1, column=col, value=header) + cell.font = header_font + + row_num = 2 + for row in self.rows: + if "section" in row: + cell = ws.cell(row=row_num, column=2, value=row["section"]) + cell.font = Font(bold=True) + for col in range(1, 6): + ws.cell(row=row_num, column=col).fill = section_fill + row_num += 1 + continue + + check = "✓" if row["checked"] else "" + ws.cell(row=row_num, column=1, value=check).alignment = Alignment(horizontal="center") + ws.cell(row=row_num, column=2, value=row["kit"]) + ws.cell(row=row_num, column=3, value=row["installed_text"]) + ws.cell(row=row_num, column=4, value=row["latest_text"]) + ws.cell(row=row_num, column=5, value=self._action_text(row)) + row_num += 1 + + ws.column_dimensions["A"].width = 4 + ws.column_dimensions["B"].width = 28 + ws.column_dimensions["C"].width = 16 + ws.column_dimensions["D"].width = 16 + ws.column_dimensions["E"].width = 30 + + try: + wb.save(path) + app_state.set_status(f"Kit table exported to {os.path.basename(path)}") + except Exception as e: + messagebox.showerror("Export", f"Could not save file:\n{e}") + def _close_editor(self): if self._editor_widget is not None: self._editor_widget.destroy()