188 lines
8.3 KiB
Python
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) |