# --- FILE: gitsync_tool/gui/tabs/repo_tab.py --- import tkinter as tk from tkinter import ttk from typing import Callable, Optional from gitutility.gui.tooltip import Tooltip class RepoTab(ttk.Frame): """ The 'Repository / Bundle' tab in the main application notebook. This tab contains widgets for managing the local repository path, bundle operations, and basic repository initialization. """ # Constants for colors GREEN: str = "#90EE90" # LightGreen RED: str = "#F08080" # LightCoral def __init__(self, master: tk.Misc, **kwargs): """ Initializes the Repository / Bundle 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 by getting them from kwargs self.update_svn_status_callback = kwargs.get("update_svn_status_cb") self.browse_folder_callback = kwargs.get("browse_folder_cb") self.prepare_svn_for_git_callback = kwargs.get("prepare_svn_for_git_cb") self.create_git_bundle_callback = kwargs.get("create_git_bundle_cb") self.fetch_from_git_bundle_callback = kwargs.get("fetch_from_git_bundle_cb") self.open_gitignore_editor_callback = kwargs.get("open_gitignore_editor_cb") # Configure layout self.columnconfigure(1, weight=1) # Create widgets self._create_widgets() def _create_widgets(self) -> None: """Creates and arranges all widgets for this tab.""" # --- Paths and Bundle Names Frame --- paths_frame = ttk.LabelFrame(self, text="Paths & Bundle Names", padding=(10, 5)) paths_frame.pack(pady=5, fill="x") paths_frame.columnconfigure(1, weight=1) # Row indices for grid cl, ce, cb, ci = 0, 1, 2, 3 # Working Directory Path ttk.Label(paths_frame, text="Working Directory Path:").grid( row=0, column=cl, sticky=tk.W, padx=5, pady=3 ) self.svn_path_entry = ttk.Entry(paths_frame, width=60) self.svn_path_entry.grid(row=0, column=ce, sticky=tk.EW, padx=5, pady=3) self.svn_path_entry.bind( "", lambda e: self.update_svn_status_callback(self.svn_path_entry.get()), ) self.svn_path_entry.bind( "", lambda e: self.update_svn_status_callback(self.svn_path_entry.get()), ) Tooltip( self.svn_path_entry, "Path to the local Git repository working directory." ) self.svn_path_browse_button = ttk.Button( paths_frame, text="Browse...", width=9, command=lambda: self.browse_folder_callback(self.svn_path_entry), ) self.svn_path_browse_button.grid( row=0, column=cb, sticky=tk.W, padx=(0, 5), pady=3 ) self.svn_status_indicator = tk.Label( paths_frame, text="", width=2, height=1, relief=tk.SUNKEN, background=self.RED, anchor=tk.CENTER, ) self.svn_status_indicator.grid( row=0, column=ci, sticky=tk.E, padx=(0, 5), pady=3 ) Tooltip( self.svn_status_indicator, "Indicates if the path points to a valid Git repository (Green=Yes, Red=No).", ) # Bundle Target Directory ttk.Label(paths_frame, text="Bundle Target Directory:").grid( row=1, column=cl, sticky=tk.W, padx=5, pady=3 ) self.usb_path_entry = ttk.Entry(paths_frame, width=60) self.usb_path_entry.grid(row=1, column=ce, sticky=tk.EW, padx=5, pady=3) Tooltip( self.usb_path_entry, "Directory where bundle files will be created or read from (e.g., USB drive).", ) self.usb_path_browse_button = ttk.Button( paths_frame, text="Browse...", width=9, command=lambda: self.browse_folder_callback(self.usb_path_entry), ) self.usb_path_browse_button.grid( row=1, column=cb, sticky=tk.W, padx=(0, 5), pady=3 ) # Bundle Filenames ttk.Label(paths_frame, text="Create Bundle Filename:").grid( row=2, column=cl, sticky=tk.W, padx=5, pady=3 ) self.bundle_name_entry = ttk.Entry(paths_frame, width=60) self.bundle_name_entry.grid( row=2, column=ce, columnspan=2, sticky=tk.EW, padx=5, pady=3 ) Tooltip( self.bundle_name_entry, "Filename to use when creating a new bundle file (e.g., my_project.bundle).", ) ttk.Label(paths_frame, text="Fetch Bundle Filename:").grid( row=3, column=cl, sticky=tk.W, padx=5, pady=3 ) self.bundle_updated_name_entry = ttk.Entry(paths_frame, width=60) self.bundle_updated_name_entry.grid( row=3, column=ce, columnspan=2, sticky=tk.EW, padx=5, pady=3 ) Tooltip( self.bundle_updated_name_entry, "Filename of the bundle file to fetch updates from (e.g., update.bundle).", ) # --- Repository Actions Frame --- actions_frame = ttk.LabelFrame(self, text="Repository Actions", padding=(10, 5)) actions_frame.pack(pady=10, fill="x") self.prepare_svn_button = ttk.Button( actions_frame, text="Prepare Repository", command=self.prepare_svn_for_git_callback, state=tk.DISABLED, ) self.prepare_svn_button.pack(side=tk.LEFT, padx=(0, 5), pady=5) Tooltip( self.prepare_svn_button, "Initialize Git in the selected directory and configure .gitignore (if not already a Git repo).", ) self.create_bundle_button = ttk.Button( actions_frame, text="Create Bundle", command=self.create_git_bundle_callback, state=tk.DISABLED, ) self.create_bundle_button.pack(side=tk.LEFT, padx=5, pady=5) Tooltip( self.create_bundle_button, "Create a Git bundle file containing the entire repository history and refs.", ) self.fetch_bundle_button = ttk.Button( actions_frame, text="Fetch from Bundle", command=self.fetch_from_git_bundle_callback, state=tk.DISABLED, ) self.fetch_bundle_button.pack(side=tk.LEFT, padx=5, pady=5) Tooltip( self.fetch_bundle_button, "Fetch updates from a bundle file and merge them, or clone if the directory is empty.", ) self.edit_gitignore_button = ttk.Button( actions_frame, text="Edit .gitignore", width=12, command=self.open_gitignore_editor_callback, state=tk.DISABLED, ) self.edit_gitignore_button.pack(side=tk.LEFT, padx=5, pady=5) Tooltip(self.edit_gitignore_button, "Open an editor for the .gitignore file.") def update_svn_indicator(self, is_prepared: bool) -> None: """Updates the color and tooltip of the repository status indicator.""" color = self.GREEN if is_prepared else self.RED tip = ( "Repository is valid and prepared (found .git)." if is_prepared else "Directory is not a valid/prepared Git repository." ) if ( hasattr(self, "svn_status_indicator") and self.svn_status_indicator.winfo_exists() ): self.svn_status_indicator.config(background=color) Tooltip(self.svn_status_indicator, tip) def set_action_widgets_state(self, state: str) -> None: """Sets the state of all action widgets in this tab.""" widgets_to_toggle = [ self.prepare_svn_button, self.create_bundle_button, self.fetch_bundle_button, self.edit_gitignore_button, ] for widget in widgets_to_toggle: if widget and widget.winfo_exists(): widget.config(state=state)