219 lines
No EOL
8.7 KiB
Python
219 lines
No EOL
8.7 KiB
Python
# tabs/sandbox_tab.py
|
|
import subprocess
|
|
from PyQt6.QtWidgets import (
|
|
QWidget, QVBoxLayout, QHBoxLayout, QLabel,
|
|
QLineEdit, QPushButton, QTableWidget, QTableWidgetItem,
|
|
QHeaderView, QMessageBox, QFormLayout
|
|
)
|
|
from PyQt6.QtCore import pyqtSignal, pyqtSlot, Qt
|
|
import database
|
|
|
|
class SandboxTab(QWidget):
|
|
# Signal emitted whenever data is added, modified, or deleted
|
|
data_mutated = pyqtSignal()
|
|
|
|
def __init__(self, parent=None):
|
|
super().__init__(parent)
|
|
|
|
# Main layout structure
|
|
main_layout = QVBoxLayout(self)
|
|
main_layout.setContentsMargins(30, 20, 30, 20)
|
|
main_layout.setSpacing(15)
|
|
|
|
# --- SECTION 1: FORM INPUT CRADLE ---
|
|
form_container = QWidget()
|
|
form_layout = QFormLayout(form_container)
|
|
form_layout.setLabelAlignment(Qt.AlignmentFlag.AlignRight)
|
|
form_layout.setSpacing(10)
|
|
|
|
# Input Form Fields
|
|
self.txt_english = QLineEdit()
|
|
self.txt_english.setPlaceholderText("Enter English phrase or word...")
|
|
self.txt_english.setStyleSheet("padding: 6px; font-size: 14px;")
|
|
|
|
self.txt_spanish = QLineEdit()
|
|
self.txt_spanish.setPlaceholderText("Introduce la frase en español...")
|
|
self.txt_spanish.setStyleSheet("padding: 6px; font-size: 14px;")
|
|
|
|
self.txt_context = QLineEdit()
|
|
self.txt_context.setPlaceholderText("e.g., Camino 2027, Café, Market conversation...")
|
|
self.txt_context.setStyleSheet("padding: 6px; font-size: 14px;")
|
|
|
|
self.txt_notes = QLineEdit()
|
|
self.txt_notes.setPlaceholderText("Grammar rules, formal vs informal nuances...")
|
|
self.txt_notes.setStyleSheet("padding: 6px; font-size: 14px;")
|
|
|
|
# Mount fields onto Form Layout
|
|
form_layout.addRow(QLabel("<b>English Text:</b>"), self.txt_english)
|
|
form_layout.addRow(QLabel("<b>Spanish Text:</b>"), self.txt_spanish)
|
|
form_layout.addRow(QLabel("<b>Source Context:</b>"), self.txt_context)
|
|
form_layout.addRow(QLabel("<b>Historical Notes:</b>"), self.txt_notes)
|
|
|
|
main_layout.addWidget(form_container)
|
|
|
|
# --- SECTION 2: AUDIO PREVIEW ACTION ROW ---
|
|
audio_layout = QHBoxLayout()
|
|
audio_layout.setSpacing(15)
|
|
|
|
self.btn_play_en = QPushButton("🔊 Test English Voice")
|
|
self.btn_play_en.setCursor(Qt.CursorShape.PointingHandCursor)
|
|
self.btn_play_en.setStyleSheet("""
|
|
QPushButton {
|
|
background-color: #E67E22;
|
|
color: white;
|
|
font-weight: bold;
|
|
font-size: 13px;
|
|
padding: 8px 16px;
|
|
border-radius: 4px;
|
|
}
|
|
QPushButton:hover { background-color: #D35400; }
|
|
""")
|
|
self.btn_play_en.clicked.connect(self.preview_english_audio)
|
|
|
|
self.btn_play_es = QPushButton("🔊 Test Mónica (Spanish)")
|
|
self.btn_play_es.setCursor(Qt.CursorShape.PointingHandCursor)
|
|
self.btn_play_es.setStyleSheet("""
|
|
QPushButton {
|
|
background-color: #9B59B6;
|
|
color: white;
|
|
font-weight: bold;
|
|
font-size: 13px;
|
|
padding: 8px 16px;
|
|
border-radius: 4px;
|
|
}
|
|
QPushButton:hover { background-color: #8E44AD; }
|
|
""")
|
|
self.btn_play_es.clicked.connect(self.preview_spanish_audio)
|
|
|
|
audio_layout.addWidget(self.btn_play_en)
|
|
audio_layout.addWidget(self.btn_play_es)
|
|
audio_layout.addStretch()
|
|
|
|
main_layout.addLayout(audio_layout)
|
|
|
|
# --- SECTION 3: DATA COMMIT CONTROL BAR ---
|
|
control_layout = QHBoxLayout()
|
|
|
|
self.btn_save = QPushButton("Save Translation Record")
|
|
self.btn_save.setCursor(Qt.CursorShape.PointingHandCursor)
|
|
self.btn_save.setStyleSheet("""
|
|
QPushButton {
|
|
background-color: #2980B9;
|
|
color: white;
|
|
font-weight: bold;
|
|
font-size: 14px;
|
|
padding: 10px 20px;
|
|
border-radius: 5px;
|
|
}
|
|
QPushButton:hover { background-color: #1F618D; }
|
|
""")
|
|
self.btn_save.clicked.connect(self.commit_translation_record)
|
|
|
|
self.btn_clear = QPushButton("Clear Fields")
|
|
self.btn_clear.setCursor(Qt.CursorShape.PointingHandCursor)
|
|
self.btn_clear.setStyleSheet("""
|
|
QPushButton {
|
|
background-color: #BDC3C7;
|
|
color: #34495E;
|
|
font-weight: bold;
|
|
font-size: 14px;
|
|
padding: 10px 20px;
|
|
border-radius: 5px;
|
|
}
|
|
QPushButton:hover { background-color: #95A5A6; }
|
|
""")
|
|
self.btn_clear.clicked.connect(self.clear_input_fields)
|
|
|
|
control_layout.addWidget(self.btn_save)
|
|
control_layout.addWidget(self.btn_clear)
|
|
control_layout.addStretch()
|
|
|
|
main_layout.addLayout(control_layout)
|
|
|
|
# --- SECTION 4: DATALIST DISPLAY REGION ---
|
|
self.table = QTableWidget()
|
|
self.table.setColumnCount(5)
|
|
self.table.setHorizontalHeaderLabels(["ID", "English Phrase", "Spanish Translation", "Context", "Notes"])
|
|
self.table.setSelectionBehavior(QTableWidget.SelectionBehavior.SelectRows)
|
|
self.table.setEditTriggers(QTableWidget.EditTrigger.NoEditTriggers)
|
|
|
|
# Tweak display headers to scale nicely
|
|
header = self.table.horizontalHeader()
|
|
header.setSectionResizeMode(0, QHeaderView.ResizeMode.ResizeToContents)
|
|
header.setSectionResizeMode(1, QHeaderView.ResizeMode.Stretch)
|
|
header.setSectionResizeMode(2, QHeaderView.ResizeMode.Stretch)
|
|
header.setSectionResizeMode(3, QHeaderView.ResizeMode.Interactive)
|
|
header.setSectionResizeMode(4, QHeaderView.ResizeMode.Interactive)
|
|
|
|
main_layout.addWidget(self.table)
|
|
|
|
# Populate live view from storage layout tracking engines
|
|
self.reload_table_display()
|
|
|
|
@pyqtSlot()
|
|
def preview_english_audio(self):
|
|
"""Auditions current text state inside the English text box field."""
|
|
text = self.txt_english.text().strip()
|
|
if text:
|
|
subprocess.Popen(["say", text])
|
|
|
|
@pyqtSlot()
|
|
def preview_spanish_audio(self):
|
|
"""Auditions current text state inside the Spanish text box field using Mónica."""
|
|
text = self.txt_spanish.text().strip()
|
|
if text:
|
|
subprocess.Popen(["say", "-v", "Monica", text])
|
|
|
|
@pyqtSlot()
|
|
def commit_translation_record(self):
|
|
"""Extracts text metrics out of input wrappers and saves down to database engine storage."""
|
|
en_text = self.txt_english.text().strip()
|
|
es_text = self.txt_spanish.text().strip()
|
|
context = self.txt_context.text().strip()
|
|
notes = self.txt_notes.text().strip()
|
|
|
|
if not en_text or not es_text:
|
|
QMessageBox.warning(self, "Validation Alert", "Both English and Spanish base text blocks are required.")
|
|
return
|
|
|
|
# Call explicit writing handlers down to SQLite database layer
|
|
database.insert_translation_explicit(en_text, es_text, context, notes)
|
|
|
|
# Wipe structural field items cleanly on completions loop
|
|
self.clear_input_fields()
|
|
|
|
# Sync state out across the rest of the app window elements
|
|
self.reload_table_display()
|
|
self.data_mutated.emit()
|
|
|
|
@pyqtSlot()
|
|
def clear_input_fields(self):
|
|
"""Flushes transient cache items out of form line elements."""
|
|
self.txt_english.clear()
|
|
self.txt_spanish.clear()
|
|
self.txt_context.clear()
|
|
self.txt_notes.clear()
|
|
|
|
def reload_table_display(self):
|
|
"""Refetches database rows and populates the master dashboard grid view."""
|
|
self.table.setRowCount(0)
|
|
records = database.get_all_translations_explicit()
|
|
|
|
for idx, row in enumerate(records):
|
|
self.table.insertRow(idx)
|
|
|
|
# Form clean mapping cell entities
|
|
item_id = QTableWidgetItem(str(row["translation_id"]))
|
|
item_en = QTableWidgetItem(row["en_text"])
|
|
item_es = QTableWidgetItem(row["es_text"])
|
|
item_ctx = QTableWidgetItem(row["source_context"] or "")
|
|
item_nts = QTableWidgetItem(row["notes"] or "")
|
|
|
|
# Align center the ID key indices
|
|
item_id.setTextAlignment(Qt.AlignmentFlag.AlignCenter)
|
|
|
|
self.table.setItem(idx, 0, item_id)
|
|
self.table.setItem(idx, 1, item_en)
|
|
self.table.setItem(idx, 2, item_es)
|
|
self.table.setItem(idx, 3, item_ctx)
|
|
self.table.setItem(idx, 4, item_nts) |