SXXXXXXX_GitUtility/gitutility/gui/tabs/history_tab.py
2025-07-29 08:41:44 +02:00

188 lines
8.3 KiB
Python

# --- FILE: gitsync_tool/gui/tabs/history_tab.py ---
import tkinter as tk
from tkinter import ttk, messagebox
from typing import Callable, List, Optional
from gitutility.gui.tooltip import Tooltip
from gitutility.logging_setup import log_handler
class HistoryTab(ttk.Frame):
"""
The 'History' tab in the main application notebook.
This tab provides a treeview for browsing the Git commit history and
widgets for filtering the view.
"""
def __init__(self, master: tk.Misc, **kwargs):
"""
Initializes the History tab.
Args:
master: The parent widget (the ttk.Notebook).
**kwargs: Dictionary of callbacks from the main controller.
"""
super().__init__(master, padding=(10, 10))
# Store callbacks
self.refresh_history_callback = kwargs.get('refresh_history_cb')
self.view_commit_details_callback = kwargs.get('view_commit_details_cb')
# --- Get a reference to the main frame for shared components ---
self.main_frame = self.master.master
# --- Tkinter Variables specific to this tab ---
self.history_branch_filter_var = tk.StringVar()
# Configure layout
self.rowconfigure(1, weight=1)
self.columnconfigure(0, weight=1)
# Create widgets
self._create_widgets()
# ... (il resto del file rimane identico) ...
def _create_widgets(self) -> None:
"""Creates and arranges all widgets for this tab."""
# --- Controls Frame (Filter and Refresh) ---
controls_frame = ttk.Frame(self)
controls_frame.grid(row=0, column=0, sticky="ew", padx=5, pady=5)
controls_frame.columnconfigure(1, weight=1)
ttk.Label(controls_frame, text="Filter History by Branch/Tag:").pack(side=tk.LEFT, padx=(0, 5))
self.history_branch_filter_combo = ttk.Combobox(
controls_frame,
textvariable=self.history_branch_filter_var,
state="readonly",
width=40,
)
self.history_branch_filter_combo.pack(side=tk.LEFT, expand=True, fill=tk.X, padx=5)
self.history_branch_filter_combo.bind("<<ComboboxSelected>>", lambda e: self.refresh_history_callback())
Tooltip(self.history_branch_filter_combo, "Select a branch or tag to filter the commit history.")
self.refresh_history_button = ttk.Button(
controls_frame, text="Refresh History", command=self.refresh_history_callback, state=tk.DISABLED
)
self.refresh_history_button.pack(side=tk.LEFT, padx=5)
Tooltip(self.refresh_history_button, "Reload commit history based on the selected filter.")
# --- Treeview Frame for History ---
content_frame = ttk.Frame(self)
content_frame.grid(row=1, column=0, sticky="nsew", padx=5, pady=(0, 5))
content_frame.rowconfigure(0, weight=1)
content_frame.columnconfigure(0, weight=1)
columns = ("hash", "datetime", "author", "details")
self.history_tree = ttk.Treeview(
content_frame, columns=columns, show="headings", selectmode="browse", height=15
)
self.history_tree.heading("hash", text="Hash", anchor="w")
self.history_tree.heading("datetime", text="Date/Time", anchor="w")
self.history_tree.heading("author", text="Author", anchor="w")
self.history_tree.heading("details", text="Subject / Refs", anchor="w")
self.history_tree.column("hash", width=80, stretch=tk.NO, anchor="w")
self.history_tree.column("datetime", width=140, stretch=tk.NO, anchor="w")
self.history_tree.column("author", width=150, stretch=tk.NO, anchor="w")
self.history_tree.column("details", width=450, stretch=tk.YES, anchor="w")
tree_scrollbar_y = ttk.Scrollbar(content_frame, orient=tk.VERTICAL, command=self.history_tree.yview)
tree_scrollbar_x = ttk.Scrollbar(content_frame, orient=tk.HORIZONTAL, command=self.history_tree.xview)
self.history_tree.configure(yscrollcommand=tree_scrollbar_y.set, xscrollcommand=tree_scrollbar_x.set)
self.history_tree.grid(row=0, column=0, sticky="nsew")
tree_scrollbar_y.grid(row=0, column=1, sticky="ns")
tree_scrollbar_x.grid(row=1, column=0, columnspan=2, sticky="ew")
self.history_tree.bind("<Double-Button-1>", self._on_history_double_click)
Tooltip(self.history_tree, "Double-click a commit line to view details.")
def set_action_widgets_state(self, state: str) -> None:
"""Sets the state of all action widgets in this tab."""
combo_state = "readonly" if state == tk.NORMAL else tk.DISABLED
widgets = {
self.history_branch_filter_combo: combo_state,
self.refresh_history_button: state,
}
for widget, widget_state in widgets.items():
if widget and widget.winfo_exists():
widget.config(state=widget_state)
if self.history_tree and self.history_tree.winfo_exists():
if state == tk.DISABLED:
self.history_tree.unbind("<Double-Button-1>")
else:
self.history_tree.bind("<Double-Button-1>", self._on_history_double_click)
def update_history_display(self, log_lines: List[str]) -> None:
"""Populates the history treeview with parsed log data."""
func_name = "update_history_display (Tree)"
if not self.history_tree.winfo_exists(): return
for item_id in self.history_tree.get_children():
self.history_tree.delete(item_id)
if not isinstance(log_lines, list):
self.history_tree.insert("", "end", values=("", "", "", "(Error: Invalid data received)"))
return
if not log_lines:
self.history_tree.insert("", "end", values=("", "", "", "(No history found)"))
return
for i, line in enumerate(log_lines):
line_str = str(line).strip()
if not line_str or line_str.startswith("("): continue
try:
parts = line_str.split("|", 2)
part1 = parts[0].strip()
commit_author = parts[1].strip()
commit_details = parts[2].strip()
first_space = part1.find(" ")
commit_hash = part1[:first_space]
commit_datetime = part1[first_space:].strip()[:16]
except Exception:
commit_hash, commit_datetime, commit_author, commit_details = "Error", "", "", line_str
self.history_tree.insert(
"", "end", iid=i, values=(commit_hash, commit_datetime, commit_author, commit_details)
)
self.history_tree.yview_moveto(0.0)
self.history_tree.xview_moveto(0.0)
def update_history_branch_filter(self, branches_tags: List[str]):
"""Updates the options in the branch/tag filter combobox."""
if not self.history_branch_filter_combo.winfo_exists(): return
opts = ["-- All History --"] + sorted(branches_tags if branches_tags else [])
self.history_branch_filter_combo["values"] = opts
current_selection = self.history_branch_filter_var.get()
if current_selection not in opts:
self.history_branch_filter_var.set(opts[0])
def _on_history_double_click(self, event: tk.Event) -> None:
"""Handles double-click on a commit in the history tree."""
func_name = "_on_history_double_click"
try:
selected_iid = self.history_tree.focus()
if not selected_iid: return
item_data = self.history_tree.item(selected_iid)
item_values = item_data.get("values")
if item_values and len(item_values) > 0:
commit_hash = str(item_values[0]).strip()
if commit_hash and not commit_hash.startswith("(") and callable(self.view_commit_details_callback):
log_handler.log_info(f"Requesting details for hash: '{commit_hash}'", func_name=func_name)
self.view_commit_details_callback(commit_hash)
except Exception as e:
log_handler.log_exception(f"Error handling history double-click: {e}", func_name=func_name)
messagebox.showerror("Error", f"Could not process history selection:\n{e}", parent=self)