142 lines
6.3 KiB
Python
142 lines
6.3 KiB
Python
import os
|
|
import tkinter as tk
|
|
from typing import Optional, TYPE_CHECKING
|
|
|
|
from .cfd_app_config import LocaleStrings
|
|
|
|
if TYPE_CHECKING:
|
|
from custom_file_dialog import CustomFileDialog
|
|
|
|
|
|
class NavigationManager:
|
|
"""Manages directory navigation, history, and path handling."""
|
|
|
|
def __init__(self, dialog: 'CustomFileDialog') -> None:
|
|
"""
|
|
Initializes the NavigationManager.
|
|
|
|
Args:
|
|
dialog: The main CustomFileDialog instance.
|
|
"""
|
|
self.dialog = dialog
|
|
|
|
def handle_path_entry_return(self, event: tk.Event) -> None:
|
|
"""
|
|
Handles the Return key press in the path entry field.
|
|
"""
|
|
path_text = self.dialog.widget_manager.path_entry.get().strip()
|
|
is_sftp = self.dialog.current_fs_type == "sftp"
|
|
|
|
if is_sftp:
|
|
self.navigate_to(path_text)
|
|
else:
|
|
potential_path = os.path.realpath(os.path.expanduser(path_text))
|
|
if os.path.isdir(potential_path):
|
|
self.navigate_to(potential_path)
|
|
elif os.path.isfile(potential_path):
|
|
directory = os.path.dirname(potential_path)
|
|
filename = os.path.basename(potential_path)
|
|
self.navigate_to(directory, file_to_select=filename)
|
|
else:
|
|
self.dialog.widget_manager.search_status_label.config(
|
|
text=f"{LocaleStrings.CFD['path_not_found']}: {self.dialog.shorten_text(path_text, 50)}")
|
|
|
|
def navigate_to(self, path: str, file_to_select: Optional[str] = None) -> None:
|
|
"""
|
|
Navigates to a specified directory path, supporting both local and SFTP filesystems.
|
|
"""
|
|
try:
|
|
is_sftp = self.dialog.current_fs_type == "sftp"
|
|
|
|
if is_sftp:
|
|
# Resolve tilde to the remote home directory for SFTP
|
|
if path == '~' or path.startswith('~/'):
|
|
home_dir = self.dialog.sftp_manager.home_dir
|
|
if home_dir:
|
|
# Manual path joining with forward slashes
|
|
if path.startswith('~/'):
|
|
# home_dir might be '/', so avoid '//'
|
|
path = home_dir.rstrip('/') + '/' + path[2:]
|
|
else:
|
|
path = home_dir
|
|
else: # Fallback if home_dir is not set
|
|
path = '/'
|
|
|
|
# The SFTP manager will handle path validation.
|
|
if not self.dialog.sftp_manager.path_is_dir(path):
|
|
self.dialog.widget_manager.search_status_label.config(
|
|
text=f"Error: Directory '{os.path.basename(path)}' not found on SFTP server.")
|
|
return
|
|
real_path = path
|
|
else:
|
|
# Local filesystem logic
|
|
real_path = os.path.realpath(os.path.abspath(os.path.expanduser(path)))
|
|
if not os.path.isdir(real_path):
|
|
self.dialog.widget_manager.search_status_label.config(
|
|
text=f"{LocaleStrings.CFD['error_title']}: {LocaleStrings.CFD['directory']} '{os.path.basename(path)}' {LocaleStrings.CFD['not_found']}")
|
|
return
|
|
if not os.access(real_path, os.R_OK):
|
|
self.dialog.widget_manager.search_status_label.config(
|
|
text=f"{LocaleStrings.CFD['access_to']} '{os.path.basename(path)}' {LocaleStrings.CFD['denied']}")
|
|
return
|
|
|
|
self.dialog.current_dir = real_path
|
|
if self.dialog.history_pos < len(self.dialog.history) - 1:
|
|
self.dialog.history = self.dialog.history[:self.dialog.history_pos + 1]
|
|
if not self.dialog.history or self.dialog.history[-1] != self.dialog.current_dir:
|
|
self.dialog.history.append(self.dialog.current_dir)
|
|
self.dialog.history_pos = len(self.dialog.history) - 1
|
|
|
|
self.dialog.widget_manager.search_animation.stop()
|
|
self.dialog.selected_item_frames.clear()
|
|
self.dialog.result = None
|
|
|
|
self.dialog.view_manager.populate_files(item_to_select=file_to_select)
|
|
self.update_nav_buttons()
|
|
self.dialog.update_selection_info()
|
|
self.dialog.update_action_buttons_state()
|
|
|
|
except Exception as e:
|
|
error_message = f"Error navigating to '{path}': {e}"
|
|
self.dialog.widget_manager.search_status_label.config(text=error_message)
|
|
|
|
def go_back(self) -> None:
|
|
"""Navigates to the previous directory in the history."""
|
|
if self.dialog.history_pos > 0:
|
|
self.dialog.history_pos -= 1
|
|
self.dialog.current_dir = self.dialog.history[self.dialog.history_pos]
|
|
self._update_ui_after_navigation()
|
|
|
|
def go_forward(self) -> None:
|
|
"""Navigates to the next directory in the history."""
|
|
if self.dialog.history_pos < len(self.dialog.history) - 1:
|
|
self.dialog.history_pos += 1
|
|
self.dialog.current_dir = self.dialog.history[self.dialog.history_pos]
|
|
self._update_ui_after_navigation()
|
|
|
|
def go_up_level(self) -> None:
|
|
"""Navigates to the parent directory of the current directory."""
|
|
if self.dialog.current_fs_type == "sftp":
|
|
if self.dialog.current_dir and self.dialog.current_dir != "/":
|
|
new_path = self.dialog.current_dir.rsplit('/', 1)[0]
|
|
if not new_path:
|
|
new_path = "/"
|
|
self.navigate_to(new_path)
|
|
else:
|
|
new_path = os.path.dirname(self.dialog.current_dir)
|
|
if new_path != self.dialog.current_dir:
|
|
self.navigate_to(new_path)
|
|
|
|
def _update_ui_after_navigation(self) -> None:
|
|
"""Updates all necessary UI components after a navigation action."""
|
|
self.dialog.view_manager.populate_files()
|
|
self.update_nav_buttons()
|
|
self.dialog.update_selection_info()
|
|
self.dialog.update_action_buttons_state()
|
|
|
|
def update_nav_buttons(self) -> None:
|
|
"""Updates the state of the back and forward navigation buttons."""
|
|
self.dialog.widget_manager.back_button.config(
|
|
state=tk.NORMAL if self.dialog.history_pos > 0 else tk.DISABLED)
|
|
self.dialog.widget_manager.forward_button.config(state=tk.NORMAL if self.dialog.history_pos < len(
|
|
self.dialog.history) - 1 else tk.DISABLED) |