Some checks failed
Build and Push Docker Image / build-and-push (push) Has been cancelled
- Implemented ExportWindow class for exporting data and graphs in various formats (JSON, XML, PDF). - Integrated ExportManager to handle export logic. - Added export option in the main application menu. - Enhanced user interface with data summary and export options. - Included error handling and success messages for export operations. - Updated dependencies in the lock file to include reportlab and lxml for PDF generation.
248 lines
8.6 KiB
Python
248 lines
8.6 KiB
Python
"""
|
|
Export Window for TheChart Application
|
|
|
|
Provides a GUI interface for exporting data and graphs to various formats.
|
|
"""
|
|
|
|
import tkinter as tk
|
|
from pathlib import Path
|
|
from tkinter import filedialog, messagebox, ttk
|
|
|
|
from export_manager import ExportManager
|
|
|
|
|
|
class ExportWindow:
|
|
"""Export window for data and graph export functionality."""
|
|
|
|
def __init__(self, parent: tk.Tk, export_manager: ExportManager) -> None:
|
|
self.parent = parent
|
|
self.export_manager = export_manager
|
|
|
|
# Create the export window
|
|
self.window = tk.Toplevel(parent)
|
|
self.window.title("Export Data")
|
|
self.window.geometry("500x450") # Made taller to ensure buttons are visible
|
|
self.window.resizable(False, False)
|
|
|
|
# Center the window
|
|
self._center_window()
|
|
|
|
# Make window modal
|
|
self.window.transient(parent)
|
|
self.window.grab_set()
|
|
|
|
# Setup the UI
|
|
self._setup_ui()
|
|
|
|
def _center_window(self) -> None:
|
|
"""Center the export window on the parent window."""
|
|
self.window.update_idletasks()
|
|
|
|
# Get window dimensions
|
|
width = self.window.winfo_width()
|
|
height = self.window.winfo_height()
|
|
|
|
# Get parent window position and size
|
|
parent_x = self.parent.winfo_rootx()
|
|
parent_y = self.parent.winfo_rooty()
|
|
parent_width = self.parent.winfo_width()
|
|
parent_height = self.parent.winfo_height()
|
|
|
|
# Calculate position to center on parent
|
|
x = parent_x + (parent_width // 2) - (width // 2)
|
|
y = parent_y + (parent_height // 2) - (height // 2)
|
|
|
|
self.window.geometry(f"{width}x{height}+{x}+{y}")
|
|
|
|
def _setup_ui(self) -> None:
|
|
"""Setup the export window UI."""
|
|
# Main frame
|
|
main_frame = ttk.Frame(self.window, padding="15")
|
|
main_frame.pack(fill=tk.BOTH, expand=True)
|
|
|
|
# Title
|
|
title_label = ttk.Label(
|
|
main_frame, text="Export Data & Graphs", font=("Arial", 14, "bold")
|
|
)
|
|
title_label.pack(pady=(0, 15))
|
|
|
|
# Create scrollable content area for the main content
|
|
content_frame = ttk.Frame(main_frame)
|
|
content_frame.pack(fill=tk.BOTH, expand=True)
|
|
|
|
# Export info section
|
|
self._create_info_section(content_frame)
|
|
|
|
# Export options section
|
|
self._create_options_section(content_frame)
|
|
|
|
# Buttons section - always at the bottom
|
|
self._create_buttons_section(main_frame)
|
|
|
|
def _create_info_section(self, parent: ttk.Frame) -> None:
|
|
"""Create the data information section."""
|
|
info_frame = ttk.LabelFrame(parent, text="Data Summary", padding="10")
|
|
info_frame.pack(fill=tk.X, pady=(0, 20))
|
|
|
|
# Get export info
|
|
export_info = self.export_manager.get_export_info()
|
|
|
|
# Display information
|
|
if export_info["has_data"]:
|
|
info_text = f"""Total Entries: {export_info["total_entries"]}
|
|
Date Range: {export_info["date_range"]["start"]} to {export_info["date_range"]["end"]}
|
|
Pathologies: {", ".join(export_info["pathologies"])}
|
|
Medicines: {", ".join(export_info["medicines"])}"""
|
|
else:
|
|
info_text = "No data available for export."
|
|
|
|
info_label = ttk.Label(info_frame, text=info_text, justify=tk.LEFT)
|
|
info_label.pack(anchor=tk.W)
|
|
|
|
def _create_options_section(self, parent: ttk.Frame) -> None:
|
|
"""Create the export options section."""
|
|
options_frame = ttk.LabelFrame(parent, text="Export Options", padding="10")
|
|
options_frame.pack(fill=tk.X, pady=(0, 20))
|
|
|
|
# Include graph option (for PDF export)
|
|
self.include_graph_var = tk.BooleanVar(value=True)
|
|
graph_check = ttk.Checkbutton(
|
|
options_frame,
|
|
text="Include graph in PDF export",
|
|
variable=self.include_graph_var,
|
|
)
|
|
graph_check.pack(anchor=tk.W, pady=(0, 10))
|
|
|
|
# Format selection
|
|
format_label = ttk.Label(options_frame, text="Export Format:")
|
|
format_label.pack(anchor=tk.W)
|
|
|
|
self.format_var = tk.StringVar(value="JSON")
|
|
formats = ["JSON", "XML", "PDF"]
|
|
|
|
for fmt in formats:
|
|
radio = ttk.Radiobutton(
|
|
options_frame, text=fmt, variable=self.format_var, value=fmt
|
|
)
|
|
radio.pack(anchor=tk.W, padx=(20, 0))
|
|
|
|
def _create_buttons_section(self, parent: ttk.Frame) -> None:
|
|
"""Create the buttons section."""
|
|
# Add a separator for visual clarity
|
|
separator = ttk.Separator(parent, orient="horizontal")
|
|
separator.pack(fill=tk.X, pady=(10, 10))
|
|
|
|
button_frame = ttk.Frame(parent)
|
|
button_frame.pack(fill=tk.X, pady=(0, 10))
|
|
|
|
# Export button with more prominent styling
|
|
export_btn = ttk.Button(
|
|
button_frame, text="Export...", command=self._handle_export
|
|
)
|
|
export_btn.pack(side=tk.LEFT, padx=(10, 10), pady=5)
|
|
|
|
# Cancel button
|
|
cancel_btn = ttk.Button(
|
|
button_frame, text="Cancel", command=self.window.destroy
|
|
)
|
|
cancel_btn.pack(side=tk.RIGHT, padx=(10, 10), pady=5)
|
|
|
|
def _handle_export(self) -> None:
|
|
"""Handle the export button click."""
|
|
# Check if we have data to export
|
|
export_info = self.export_manager.get_export_info()
|
|
if not export_info["has_data"]:
|
|
messagebox.showwarning(
|
|
"No Data", "There is no data available to export.", parent=self.window
|
|
)
|
|
return
|
|
|
|
# Get selected format
|
|
selected_format = self.format_var.get()
|
|
|
|
# Define file types for dialog
|
|
file_types = {
|
|
"JSON": [("JSON files", "*.json"), ("All files", "*.*")],
|
|
"XML": [("XML files", "*.xml"), ("All files", "*.*")],
|
|
"PDF": [("PDF files", "*.pdf"), ("All files", "*.*")],
|
|
}
|
|
|
|
# Default filename
|
|
default_name = f"thechart_export.{selected_format.lower()}"
|
|
|
|
# Show save dialog
|
|
filename = filedialog.asksaveasfilename(
|
|
parent=self.window,
|
|
title=f"Export as {selected_format}",
|
|
defaultextension=f".{selected_format.lower()}",
|
|
filetypes=file_types[selected_format],
|
|
initialfile=default_name,
|
|
)
|
|
|
|
if not filename:
|
|
return
|
|
|
|
# Perform export based on selected format
|
|
success = False
|
|
try:
|
|
if selected_format == "JSON":
|
|
success = self.export_manager.export_data_to_json(filename)
|
|
elif selected_format == "XML":
|
|
success = self.export_manager.export_data_to_xml(filename)
|
|
elif selected_format == "PDF":
|
|
include_graph = self.include_graph_var.get()
|
|
success = self.export_manager.export_to_pdf(
|
|
filename, include_graph=include_graph
|
|
)
|
|
|
|
if success:
|
|
messagebox.showinfo(
|
|
"Export Successful",
|
|
f"Data exported successfully to:\n{filename}",
|
|
parent=self.window,
|
|
)
|
|
# Ask if user wants to open the file location
|
|
if messagebox.askyesno(
|
|
"Open Location",
|
|
"Would you like to open the file location?",
|
|
parent=self.window,
|
|
):
|
|
self._open_file_location(filename)
|
|
|
|
self.window.destroy()
|
|
else:
|
|
messagebox.showerror(
|
|
"Export Failed",
|
|
f"Failed to export data as {selected_format}. "
|
|
"Please check the logs for more details.",
|
|
parent=self.window,
|
|
)
|
|
|
|
except Exception as e:
|
|
messagebox.showerror(
|
|
"Export Error",
|
|
f"An error occurred during export:\n{str(e)}",
|
|
parent=self.window,
|
|
)
|
|
|
|
def _open_file_location(self, filepath: str) -> None:
|
|
"""Open the file location in the system file manager."""
|
|
try:
|
|
file_path = Path(filepath)
|
|
directory = file_path.parent
|
|
|
|
# Use system-specific command to open file manager
|
|
import subprocess
|
|
import sys
|
|
|
|
if sys.platform == "win32":
|
|
subprocess.run(["explorer", str(directory)], check=False)
|
|
elif sys.platform == "darwin":
|
|
subprocess.run(["open", str(directory)], check=False)
|
|
else: # Linux and other Unix-like systems
|
|
subprocess.run(["xdg-open", str(directory)], check=False)
|
|
|
|
except Exception:
|
|
# If opening file location fails, just ignore silently
|
|
pass
|