Basic TL working

This commit is contained in:
dazedanon 2025-07-18 16:27:09 -05:00
parent e7b41c9f44
commit 5fd0ae7caf
3 changed files with 601 additions and 877 deletions

View file

@ -1,466 +0,0 @@
#!/usr/bin/env python3
"""
File Manager Tab for DazedMTLTool GUI
Manages input files from 'files' directory and output to 'translated' directory.
Users can add files through GUI or by copying them to the files folder.
"""
import os
import shutil
from pathlib import Path
from PyQt5.QtWidgets import (
QWidget, QVBoxLayout, QHBoxLayout, QLabel, QTreeWidget, QTreeWidgetItem,
QPushButton, QGroupBox, QSplitter, QTextEdit, QFileDialog, QMessageBox,
QProgressBar, QFrame, QHeaderView
)
from PyQt5.QtCore import Qt, QTimer
from PyQt5.QtGui import QFont
class FileManagerTab(QWidget):
"""File Manager tab for managing input and output files."""
def __init__(self, parent=None):
super().__init__(parent)
self.project_root = Path(__file__).parent.parent
self.files_dir = self.project_root / "files"
self.translated_dir = self.project_root / "translated"
# Ensure directories exist
self.files_dir.mkdir(exist_ok=True)
self.translated_dir.mkdir(exist_ok=True)
self.setup_ui()
self.refresh_file_lists()
# Auto-refresh timer
self.refresh_timer = QTimer()
self.refresh_timer.timeout.connect(self.refresh_file_lists)
self.refresh_timer.start(3000) # Refresh every 3 seconds
def setup_ui(self):
"""Set up the user interface."""
layout = QVBoxLayout()
# Title
title_label = QLabel("File Manager")
title_label.setStyleSheet("font-size: 16px; font-weight: bold; color: #007acc;")
layout.addWidget(title_label)
# Description
desc_label = QLabel(
"Input files are loaded from the 'files' directory. "
"Translated files will be saved to the 'translated' directory. "
"You can add files using the GUI or by copying them to the files folder."
)
desc_label.setWordWrap(True)
desc_label.setStyleSheet("color: #cccccc; margin-bottom: 10px;")
layout.addWidget(desc_label)
# Main splitter
splitter = QSplitter(Qt.Horizontal)
# Input files section
input_group = self.create_input_files_section()
splitter.addWidget(input_group)
# Output files section
output_group = self.create_output_files_section()
splitter.addWidget(output_group)
# Set equal sizes
splitter.setSizes([400, 400])
layout.addWidget(splitter)
# Action buttons
button_layout = self.create_action_buttons()
layout.addLayout(button_layout)
# Status bar
self.status_label = QLabel("Ready")
self.status_label.setStyleSheet("color: #cccccc; padding: 5px;")
layout.addWidget(self.status_label)
self.setLayout(layout)
def create_input_files_section(self):
"""Create the input files section."""
group = QGroupBox("Input Files (files directory)")
layout = QVBoxLayout()
# File tree
self.input_tree = QTreeWidget()
self.input_tree.setHeaderLabels(["Filename", "Size", "Modified"])
self.input_tree.header().setSectionResizeMode(0, QHeaderView.Stretch)
self.input_tree.header().setSectionResizeMode(1, QHeaderView.ResizeToContents)
self.input_tree.header().setSectionResizeMode(2, QHeaderView.ResizeToContents)
self.input_tree.itemSelectionChanged.connect(self.on_input_file_selected)
layout.addWidget(self.input_tree)
# Input buttons
input_button_layout = QHBoxLayout()
self.add_file_btn = QPushButton("Add Files")
self.add_file_btn.clicked.connect(self.add_files)
input_button_layout.addWidget(self.add_file_btn)
self.remove_file_btn = QPushButton("Remove Selected")
self.remove_file_btn.clicked.connect(self.remove_input_file)
self.remove_file_btn.setEnabled(False)
input_button_layout.addWidget(self.remove_file_btn)
self.open_files_folder_btn = QPushButton("Open Files Folder")
self.open_files_folder_btn.clicked.connect(self.open_files_folder)
input_button_layout.addWidget(self.open_files_folder_btn)
input_button_layout.addStretch()
layout.addLayout(input_button_layout)
group.setLayout(layout)
return group
def create_output_files_section(self):
"""Create the output files section."""
group = QGroupBox("Output Files (translated directory)")
layout = QVBoxLayout()
# File tree
self.output_tree = QTreeWidget()
self.output_tree.setHeaderLabels(["Filename", "Size", "Modified"])
self.output_tree.header().setSectionResizeMode(0, QHeaderView.Stretch)
self.output_tree.header().setSectionResizeMode(1, QHeaderView.ResizeToContents)
self.output_tree.header().setSectionResizeMode(2, QHeaderView.ResizeToContents)
self.output_tree.itemSelectionChanged.connect(self.on_output_file_selected)
layout.addWidget(self.output_tree)
# Output buttons
output_button_layout = QHBoxLayout()
self.view_output_btn = QPushButton("View Selected")
self.view_output_btn.clicked.connect(self.view_output_file)
self.view_output_btn.setEnabled(False)
output_button_layout.addWidget(self.view_output_btn)
self.delete_output_btn = QPushButton("Delete Selected")
self.delete_output_btn.clicked.connect(self.delete_output_file)
self.delete_output_btn.setEnabled(False)
output_button_layout.addWidget(self.delete_output_btn)
self.open_translated_folder_btn = QPushButton("Open Translated Folder")
self.open_translated_folder_btn.clicked.connect(self.open_translated_folder)
output_button_layout.addWidget(self.open_translated_folder_btn)
output_button_layout.addStretch()
layout.addLayout(output_button_layout)
group.setLayout(layout)
return group
def create_action_buttons(self):
"""Create main action buttons."""
layout = QHBoxLayout()
self.refresh_btn = QPushButton("Refresh File Lists")
self.refresh_btn.clicked.connect(self.refresh_file_lists)
layout.addWidget(self.refresh_btn)
self.clear_translated_btn = QPushButton("Clear All Translated Files")
self.clear_translated_btn.clicked.connect(self.clear_translated_files)
layout.addWidget(self.clear_translated_btn)
layout.addStretch()
# Auto-refresh indicator
self.auto_refresh_label = QLabel("Auto-refresh: ON")
self.auto_refresh_label.setStyleSheet("color: #00aa00; font-size: 10px;")
layout.addWidget(self.auto_refresh_label)
return layout
def refresh_file_lists(self):
"""Refresh both input and output file lists."""
self.refresh_input_files()
self.refresh_output_files()
self.update_status()
def refresh_input_files(self):
"""Refresh the input files tree."""
self.input_tree.clear()
if not self.files_dir.exists():
return
supported_extensions = {'.json', '.txt', '.csv', '.js', '.py', '.xml', '.html', '.md'}
for file_path in self.files_dir.iterdir():
if (file_path.is_file() and
file_path.suffix.lower() in supported_extensions and
file_path.name != '.gitkeep'):
item = QTreeWidgetItem()
item.setText(0, file_path.name)
# File size
size = file_path.stat().st_size
if size < 1024:
size_str = f"{size} B"
elif size < 1024 * 1024:
size_str = f"{size / 1024:.1f} KB"
else:
size_str = f"{size / (1024 * 1024):.1f} MB"
item.setText(1, size_str)
# Modified time
import datetime
mtime = datetime.datetime.fromtimestamp(file_path.stat().st_mtime)
item.setText(2, mtime.strftime("%Y-%m-%d %H:%M"))
# Store file path
item.setData(0, Qt.UserRole, str(file_path))
self.input_tree.addTopLevelItem(item)
def refresh_output_files(self):
"""Refresh the output files tree."""
self.output_tree.clear()
if not self.translated_dir.exists():
return
for file_path in self.translated_dir.iterdir():
if file_path.is_file() and file_path.name != '.gitkeep':
item = QTreeWidgetItem()
item.setText(0, file_path.name)
# File size
size = file_path.stat().st_size
if size < 1024:
size_str = f"{size} B"
elif size < 1024 * 1024:
size_str = f"{size / 1024:.1f} KB"
else:
size_str = f"{size / (1024 * 1024):.1f} MB"
item.setText(1, size_str)
# Modified time
import datetime
mtime = datetime.datetime.fromtimestamp(file_path.stat().st_mtime)
item.setText(2, mtime.strftime("%Y-%m-%d %H:%M"))
# Store file path
item.setData(0, Qt.UserRole, str(file_path))
self.output_tree.addTopLevelItem(item)
def update_status(self):
"""Update the status label."""
input_count = self.input_tree.topLevelItemCount()
output_count = self.output_tree.topLevelItemCount()
self.status_label.setText(f"Input files: {input_count} | Output files: {output_count}")
def on_input_file_selected(self):
"""Handle input file selection."""
selected = self.input_tree.selectedItems()
self.remove_file_btn.setEnabled(len(selected) > 0)
def on_output_file_selected(self):
"""Handle output file selection."""
selected = self.output_tree.selectedItems()
self.view_output_btn.setEnabled(len(selected) > 0)
self.delete_output_btn.setEnabled(len(selected) > 0)
def add_files(self):
"""Add files to the input directory."""
file_paths, _ = QFileDialog.getOpenFileNames(
self,
"Select Files to Add",
"",
"All Supported Files (*.json *.txt *.csv *.js *.py *.xml *.html *.md);;All Files (*.*)"
)
if not file_paths:
return
copied_count = 0
for file_path in file_paths:
source_path = Path(file_path)
dest_path = self.files_dir / source_path.name
try:
# Check if file already exists
if dest_path.exists():
reply = QMessageBox.question(
self,
"File Exists",
f"'{source_path.name}' already exists. Overwrite?",
QMessageBox.Yes | QMessageBox.No
)
if reply != QMessageBox.Yes:
continue
shutil.copy2(source_path, dest_path)
copied_count += 1
except Exception as e:
QMessageBox.warning(
self,
"Copy Error",
f"Failed to copy '{source_path.name}':\n{str(e)}"
)
if copied_count > 0:
QMessageBox.information(
self,
"Files Added",
f"Successfully added {copied_count} file(s) to the input directory."
)
self.refresh_input_files()
def remove_input_file(self):
"""Remove selected input file."""
selected = self.input_tree.selectedItems()
if not selected:
return
item = selected[0]
file_path = Path(item.data(0, Qt.UserRole))
reply = QMessageBox.question(
self,
"Confirm Removal",
f"Are you sure you want to remove '{file_path.name}' from the input directory?",
QMessageBox.Yes | QMessageBox.No
)
if reply == QMessageBox.Yes:
try:
file_path.unlink()
self.refresh_input_files()
QMessageBox.information(self, "File Removed", f"'{file_path.name}' has been removed.")
except Exception as e:
QMessageBox.warning(self, "Error", f"Failed to remove file:\n{str(e)}")
def view_output_file(self):
"""View selected output file."""
selected = self.output_tree.selectedItems()
if not selected:
return
item = selected[0]
file_path = Path(item.data(0, Qt.UserRole))
try:
# Open file with default system application
import subprocess
import platform
if platform.system() == 'Windows':
os.startfile(str(file_path))
elif platform.system() == 'Darwin': # macOS
subprocess.run(['open', str(file_path)])
else: # Linux
subprocess.run(['xdg-open', str(file_path)])
except Exception as e:
QMessageBox.warning(self, "Error", f"Failed to open file:\n{str(e)}")
def delete_output_file(self):
"""Delete selected output file."""
selected = self.output_tree.selectedItems()
if not selected:
return
item = selected[0]
file_path = Path(item.data(0, Qt.UserRole))
reply = QMessageBox.question(
self,
"Confirm Deletion",
f"Are you sure you want to delete '{file_path.name}' from the output directory?",
QMessageBox.Yes | QMessageBox.No
)
if reply == QMessageBox.Yes:
try:
file_path.unlink()
self.refresh_output_files()
QMessageBox.information(self, "File Deleted", f"'{file_path.name}' has been deleted.")
except Exception as e:
QMessageBox.warning(self, "Error", f"Failed to delete file:\n{str(e)}")
def clear_translated_files(self):
"""Clear all files from the translated directory."""
if self.output_tree.topLevelItemCount() == 0:
QMessageBox.information(self, "No Files", "There are no files to clear.")
return
reply = QMessageBox.question(
self,
"Confirm Clear All",
"Are you sure you want to delete ALL files from the translated directory?",
QMessageBox.Yes | QMessageBox.No
)
if reply == QMessageBox.Yes:
try:
deleted_count = 0
for file_path in self.translated_dir.iterdir():
if file_path.is_file() and file_path.name != '.gitkeep':
file_path.unlink()
deleted_count += 1
self.refresh_output_files()
QMessageBox.information(
self,
"Files Cleared",
f"Successfully deleted {deleted_count} file(s) from the translated directory."
)
except Exception as e:
QMessageBox.warning(self, "Error", f"Failed to clear files:\n{str(e)}")
def open_files_folder(self):
"""Open the files folder in the system file manager."""
try:
import subprocess
import platform
if platform.system() == 'Windows':
subprocess.run(['explorer', str(self.files_dir)])
elif platform.system() == 'Darwin': # macOS
subprocess.run(['open', str(self.files_dir)])
else: # Linux
subprocess.run(['xdg-open', str(self.files_dir)])
except Exception as e:
QMessageBox.warning(self, "Error", f"Failed to open folder:\n{str(e)}")
def open_translated_folder(self):
"""Open the translated folder in the system file manager."""
try:
import subprocess
import platform
if platform.system() == 'Windows':
subprocess.run(['explorer', str(self.translated_dir)])
elif platform.system() == 'Darwin': # macOS
subprocess.run(['open', str(self.translated_dir)])
else: # Linux
subprocess.run(['xdg-open', str(self.translated_dir)])
except Exception as e:
QMessageBox.warning(self, "Error", f"Failed to open folder:\n{str(e)}")
def get_input_files(self):
"""Get list of input files for processing."""
input_files = []
for i in range(self.input_tree.topLevelItemCount()):
item = self.input_tree.topLevelItem(i)
file_path = item.data(0, Qt.UserRole)
input_files.append(Path(file_path))
return input_files
def closeEvent(self, event):
"""Handle widget close event."""
if hasattr(self, 'refresh_timer'):
self.refresh_timer.stop()
event.accept()

View file

@ -22,7 +22,6 @@ from gui.rpgmaker_tab import RPGMakerTab
from gui.other_modules_tab import OtherModulesTab
from gui.log_viewer import LogViewer
from gui.file_manager import FileManager
from gui.file_manager_tab import FileManagerTab
from gui.translation_tab import TranslationTab
class DazedMTLGUI(QMainWindow):
@ -120,11 +119,7 @@ class DazedMTLGUI(QMainWindow):
self.config_tab.config_changed.connect(self.on_config_changed)
self.tab_widget.addTab(self.config_tab, "Configuration")
# File Manager Tab (New)
self.file_manager_tab = FileManagerTab()
self.tab_widget.addTab(self.file_manager_tab, "File Manager")
# Translation Execution Tab
# Translation Execution Tab (includes file management)
self.translation_tab = TranslationTab(self)
self.tab_widget.addTab(self.translation_tab, "Translation")
@ -336,14 +331,6 @@ class DazedMTLGUI(QMainWindow):
def set_progress(self, value):
"""Set the progress bar value (0-100)."""
self.progress_bar.setValue(value)
def get_input_files(self):
"""Get list of input files from the file manager."""
try:
return self.file_manager_tab.get_input_files()
except Exception as e:
print(f"Warning: Could not get input files: {e}")
return []
def main():

File diff suppressed because it is too large Load diff