Optimización del sistema de menús en la interfaz gráfica, incluyendo la adición de un menú para archivos recientes y mejoras en la gestión de archivos. Se refactorizan las funciones de carga y guardado de archivos para incluir la actualización de la lista de archivos recientes. Se mejora la legibilidad del código eliminando espacios innecesarios y ajustando la estructura de las funciones.
This commit is contained in:
parent
0b5a2579d5
commit
7ce08833e8
|
@ -36,6 +36,4 @@ hacer_por_dia = faltan/dias_faltan
|
||||||
# Minimo para terminar
|
# Minimo para terminar
|
||||||
promedio_ideal = total/(dias_pasados+dias_faltan)
|
promedio_ideal = total/(dias_pasados+dias_faltan)
|
||||||
|
|
||||||
h = Today()
|
|
||||||
f = Date('23/2/25') + x
|
|
||||||
x=?
|
|
||||||
|
|
420
app/gui_menus.py
420
app/gui_menus.py
|
@ -1,12 +1,11 @@
|
||||||
"""
|
"""
|
||||||
Sistema de Menús y Diálogos para la Calculadora MAV CAS Híbrida
|
Sistema de Menús y Diálogos para la Calculadora MAV CAS Híbrida
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import time
|
import time
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from PySide6.QtWidgets import (
|
from PySide6.QtWidgets import QMenuBar, QMenu, QMessageBox, QFileDialog
|
||||||
QMenuBar, QMenu, QMessageBox, QFileDialog
|
|
||||||
)
|
|
||||||
from PySide6.QtGui import QAction, QKeySequence
|
from PySide6.QtGui import QAction, QKeySequence
|
||||||
from PySide6.QtCore import QTimer
|
from PySide6.QtCore import QTimer
|
||||||
from PySide6.QtWidgets import QApplication
|
from PySide6.QtWidgets import QApplication
|
||||||
|
@ -14,224 +13,272 @@ from PySide6.QtWidgets import QApplication
|
||||||
|
|
||||||
class MenuManager:
|
class MenuManager:
|
||||||
"""Gestor del sistema de menús"""
|
"""Gestor del sistema de menús"""
|
||||||
|
|
||||||
def __init__(self, main_window):
|
def __init__(self, main_window):
|
||||||
self.main_window = main_window
|
self.main_window = main_window
|
||||||
self.logger = main_window.logger
|
self.logger = main_window.logger
|
||||||
|
|
||||||
def setup_menu(self):
|
def setup_menu(self):
|
||||||
"""Configura el menú completo"""
|
"""Configura el menú completo"""
|
||||||
menubar = self.main_window.menuBar()
|
menubar = self.main_window.menuBar()
|
||||||
|
|
||||||
# Menú Archivo
|
# Menú Archivo
|
||||||
file_menu = menubar.addMenu("Archivo")
|
file_menu = menubar.addMenu("Archivo")
|
||||||
|
|
||||||
new_action = QAction("Nuevo", self.main_window)
|
new_action = QAction("Nuevo", self.main_window)
|
||||||
new_action.setShortcut(QKeySequence.New)
|
new_action.setShortcut(QKeySequence.New)
|
||||||
new_action.triggered.connect(self.new_session)
|
new_action.triggered.connect(self.new_session)
|
||||||
file_menu.addAction(new_action)
|
file_menu.addAction(new_action)
|
||||||
|
|
||||||
file_menu.addSeparator()
|
file_menu.addSeparator()
|
||||||
|
|
||||||
load_action = QAction("Cargar...", self.main_window)
|
load_action = QAction("Cargar...", self.main_window)
|
||||||
load_action.setShortcut(QKeySequence.Open)
|
load_action.setShortcut(QKeySequence.Open)
|
||||||
load_action.triggered.connect(self.load_file)
|
load_action.triggered.connect(self.load_file)
|
||||||
file_menu.addAction(load_action)
|
file_menu.addAction(load_action)
|
||||||
|
|
||||||
save_action = QAction("Guardar como...", self.main_window)
|
save_action = QAction("Guardar como...", self.main_window)
|
||||||
save_action.setShortcut(QKeySequence.Save)
|
save_action.setShortcut(QKeySequence.Save)
|
||||||
save_action.triggered.connect(self.save_file)
|
save_action.triggered.connect(self.save_file)
|
||||||
file_menu.addAction(save_action)
|
file_menu.addAction(save_action)
|
||||||
|
|
||||||
|
# Menú de archivos recientes
|
||||||
|
self.recent_files_menu = file_menu.addMenu("Archivos recientes")
|
||||||
|
self._update_recent_files_menu()
|
||||||
|
|
||||||
file_menu.addSeparator()
|
file_menu.addSeparator()
|
||||||
|
|
||||||
exit_action = QAction("Salir", self.main_window)
|
exit_action = QAction("Salir", self.main_window)
|
||||||
exit_action.triggered.connect(self.main_window.close)
|
exit_action.triggered.connect(self.main_window.close)
|
||||||
file_menu.addAction(exit_action)
|
file_menu.addAction(exit_action)
|
||||||
|
|
||||||
# Menú Editar
|
# Menú Editar
|
||||||
edit_menu = menubar.addMenu("Editar")
|
edit_menu = menubar.addMenu("Editar")
|
||||||
|
|
||||||
clear_input_action = QAction("Limpiar entrada", self.main_window)
|
clear_input_action = QAction("Limpiar entrada", self.main_window)
|
||||||
clear_input_action.triggered.connect(self.clear_input)
|
clear_input_action.triggered.connect(self.clear_input)
|
||||||
edit_menu.addAction(clear_input_action)
|
edit_menu.addAction(clear_input_action)
|
||||||
|
|
||||||
clear_output_action = QAction("Limpiar salida", self.main_window)
|
clear_output_action = QAction("Limpiar salida", self.main_window)
|
||||||
clear_output_action.triggered.connect(self.clear_output)
|
clear_output_action.triggered.connect(self.clear_output)
|
||||||
edit_menu.addAction(clear_output_action)
|
edit_menu.addAction(clear_output_action)
|
||||||
|
|
||||||
edit_menu.addSeparator()
|
edit_menu.addSeparator()
|
||||||
|
|
||||||
clear_history_action = QAction("Limpiar historial", self.main_window)
|
clear_history_action = QAction("Limpiar historial", self.main_window)
|
||||||
clear_history_action.triggered.connect(self.clear_history)
|
clear_history_action.triggered.connect(self.clear_history)
|
||||||
edit_menu.addAction(clear_history_action)
|
edit_menu.addAction(clear_history_action)
|
||||||
|
|
||||||
# Menú Ver
|
# Menú Ver
|
||||||
view_menu = menubar.addMenu("Ver")
|
view_menu = menubar.addMenu("Ver")
|
||||||
|
|
||||||
toggle_latex_action = QAction("📐 Panel LaTeX", self.main_window)
|
toggle_latex_action = QAction("📐 Panel LaTeX", self.main_window)
|
||||||
toggle_latex_action.setShortcut(QKeySequence("F12"))
|
toggle_latex_action.setShortcut(QKeySequence("F12"))
|
||||||
toggle_latex_action.triggered.connect(self.main_window._toggle_latex_panel)
|
toggle_latex_action.triggered.connect(self.main_window._toggle_latex_panel)
|
||||||
view_menu.addAction(toggle_latex_action)
|
view_menu.addAction(toggle_latex_action)
|
||||||
|
|
||||||
view_menu.addSeparator()
|
view_menu.addSeparator()
|
||||||
|
|
||||||
# Submenu de fuentes
|
# Submenu de fuentes
|
||||||
font_menu = view_menu.addMenu("Tamaño de fuente")
|
font_menu = view_menu.addMenu("Tamaño de fuente")
|
||||||
|
|
||||||
font_small_action = QAction("Pequeña (11px)", self.main_window)
|
font_small_action = QAction("Pequeña (11px)", self.main_window)
|
||||||
font_small_action.setCheckable(True)
|
font_small_action.setCheckable(True)
|
||||||
font_small_action.triggered.connect(lambda: self.set_font_size(False))
|
font_small_action.triggered.connect(lambda: self.set_font_size(False))
|
||||||
font_menu.addAction(font_small_action)
|
font_menu.addAction(font_small_action)
|
||||||
|
|
||||||
font_large_action = QAction("Grande (14px)", self.main_window)
|
font_large_action = QAction("Grande (14px)", self.main_window)
|
||||||
font_large_action.setCheckable(True)
|
font_large_action.setCheckable(True)
|
||||||
font_large_action.triggered.connect(lambda: self.set_font_size(True))
|
font_large_action.triggered.connect(lambda: self.set_font_size(True))
|
||||||
font_menu.addAction(font_large_action)
|
font_menu.addAction(font_large_action)
|
||||||
|
|
||||||
# Marcar el tamaño actual
|
# Marcar el tamaño actual
|
||||||
is_large = self.main_window.settings_manager.get_setting("font_size_large", False)
|
is_large = self.main_window.settings_manager.get_setting(
|
||||||
|
"font_size_large", False
|
||||||
|
)
|
||||||
if is_large:
|
if is_large:
|
||||||
font_large_action.setChecked(True)
|
font_large_action.setChecked(True)
|
||||||
else:
|
else:
|
||||||
font_small_action.setChecked(True)
|
font_small_action.setChecked(True)
|
||||||
|
|
||||||
self.font_small_action = font_small_action
|
self.font_small_action = font_small_action
|
||||||
self.font_large_action = font_large_action
|
self.font_large_action = font_large_action
|
||||||
|
|
||||||
view_menu.addSeparator()
|
view_menu.addSeparator()
|
||||||
|
|
||||||
system_info_action = QAction("Información del sistema", self.main_window)
|
system_info_action = QAction("Información del sistema", self.main_window)
|
||||||
system_info_action.triggered.connect(self.show_types_info)
|
system_info_action.triggered.connect(self.show_types_info)
|
||||||
view_menu.addAction(system_info_action)
|
view_menu.addAction(system_info_action)
|
||||||
|
|
||||||
# Menú Herramientas
|
# Menú Herramientas
|
||||||
tools_menu = menubar.addMenu("Herramientas")
|
tools_menu = menubar.addMenu("Herramientas")
|
||||||
|
|
||||||
reload_types_action = QAction("Recargar Tipos Personalizados", self.main_window)
|
reload_types_action = QAction("Recargar Tipos Personalizados", self.main_window)
|
||||||
reload_types_action.triggered.connect(self.reload_types)
|
reload_types_action.triggered.connect(self.reload_types)
|
||||||
tools_menu.addAction(reload_types_action)
|
tools_menu.addAction(reload_types_action)
|
||||||
|
|
||||||
tools_menu.addSeparator()
|
tools_menu.addSeparator()
|
||||||
|
|
||||||
# Menú de diagnóstico
|
# Menú de diagnóstico
|
||||||
diag_menu = tools_menu.addMenu("Diagnóstico")
|
diag_menu = tools_menu.addMenu("Diagnóstico")
|
||||||
|
|
||||||
mathjax_diag_action = QAction("🔍 Diagnóstico MathJax", self.main_window)
|
mathjax_diag_action = QAction("🔍 Diagnóstico MathJax", self.main_window)
|
||||||
mathjax_diag_action.triggered.connect(self._diagnose_mathjax)
|
mathjax_diag_action.triggered.connect(self._diagnose_mathjax)
|
||||||
diag_menu.addAction(mathjax_diag_action)
|
diag_menu.addAction(mathjax_diag_action)
|
||||||
|
|
||||||
latex_status_action = QAction("📊 Estado Panel LaTeX", self.main_window)
|
latex_status_action = QAction("📊 Estado Panel LaTeX", self.main_window)
|
||||||
latex_status_action.triggered.connect(self._show_latex_panel_status)
|
latex_status_action.triggered.connect(self._show_latex_panel_status)
|
||||||
diag_menu.addAction(latex_status_action)
|
diag_menu.addAction(latex_status_action)
|
||||||
|
|
||||||
save_html_action = QAction("💾 Guardar HTML del Panel LaTeX", self.main_window)
|
save_html_action = QAction("💾 Guardar HTML del Panel LaTeX", self.main_window)
|
||||||
save_html_action.triggered.connect(self._save_latex_html)
|
save_html_action.triggered.connect(self._save_latex_html)
|
||||||
diag_menu.addAction(save_html_action)
|
diag_menu.addAction(save_html_action)
|
||||||
|
|
||||||
diag_menu.addSeparator()
|
diag_menu.addSeparator()
|
||||||
|
|
||||||
copy_debug_action = QAction("📋 Copiar Debug al Portapapeles", self.main_window)
|
copy_debug_action = QAction("📋 Copiar Debug al Portapapeles", self.main_window)
|
||||||
copy_debug_action.setShortcut(QKeySequence("Ctrl+Shift+C"))
|
copy_debug_action.setShortcut(QKeySequence("Ctrl+Shift+C"))
|
||||||
copy_debug_action.triggered.connect(self._copy_debug_to_clipboard)
|
copy_debug_action.triggered.connect(self._copy_debug_to_clipboard)
|
||||||
diag_menu.addAction(copy_debug_action)
|
diag_menu.addAction(copy_debug_action)
|
||||||
|
|
||||||
# Menú Tipos
|
# Menú Tipos
|
||||||
types_menu = menubar.addMenu("Tipos")
|
types_menu = menubar.addMenu("Tipos")
|
||||||
|
|
||||||
types_info_action = QAction("Información de tipos", self.main_window)
|
types_info_action = QAction("Información de tipos", self.main_window)
|
||||||
types_info_action.triggered.connect(self.show_types_info)
|
types_info_action.triggered.connect(self.show_types_info)
|
||||||
types_menu.addAction(types_info_action)
|
types_menu.addAction(types_info_action)
|
||||||
|
|
||||||
types_menu.addSeparator()
|
types_menu.addSeparator()
|
||||||
|
|
||||||
types_syntax_action = QAction("Sintaxis de tipos", self.main_window)
|
types_syntax_action = QAction("Sintaxis de tipos", self.main_window)
|
||||||
types_syntax_action.triggered.connect(self.show_types_syntax)
|
types_syntax_action.triggered.connect(self.show_types_syntax)
|
||||||
types_menu.addAction(types_syntax_action)
|
types_menu.addAction(types_syntax_action)
|
||||||
|
|
||||||
# Menú Ayuda
|
# Menú Ayuda
|
||||||
help_menu = menubar.addMenu("Ayuda")
|
help_menu = menubar.addMenu("Ayuda")
|
||||||
|
|
||||||
quick_guide_action = QAction("Guía rápida", self.main_window)
|
quick_guide_action = QAction("Guía rápida", self.main_window)
|
||||||
quick_guide_action.triggered.connect(self.show_quick_guide)
|
quick_guide_action.triggered.connect(self.show_quick_guide)
|
||||||
help_menu.addAction(quick_guide_action)
|
help_menu.addAction(quick_guide_action)
|
||||||
|
|
||||||
syntax_help_action = QAction("Sintaxis", self.main_window)
|
syntax_help_action = QAction("Sintaxis", self.main_window)
|
||||||
syntax_help_action.triggered.connect(self.show_syntax_help)
|
syntax_help_action.triggered.connect(self.show_syntax_help)
|
||||||
help_menu.addAction(syntax_help_action)
|
help_menu.addAction(syntax_help_action)
|
||||||
|
|
||||||
sympy_funcs_action = QAction("Funciones SymPy", self.main_window)
|
sympy_funcs_action = QAction("Funciones SymPy", self.main_window)
|
||||||
sympy_funcs_action.triggered.connect(self.show_sympy_functions)
|
sympy_funcs_action.triggered.connect(self.show_sympy_functions)
|
||||||
help_menu.addAction(sympy_funcs_action)
|
help_menu.addAction(sympy_funcs_action)
|
||||||
|
|
||||||
help_menu.addSeparator()
|
help_menu.addSeparator()
|
||||||
|
|
||||||
about_action = QAction("Acerca de", self.main_window)
|
about_action = QAction("Acerca de", self.main_window)
|
||||||
about_action.triggered.connect(self.show_about)
|
about_action.triggered.connect(self.show_about)
|
||||||
help_menu.addAction(about_action)
|
help_menu.addAction(about_action)
|
||||||
|
|
||||||
# ========== FUNCIONES DE MENÚ ARCHIVO ==========
|
# ========== FUNCIONES DE MENÚ ARCHIVO ==========
|
||||||
|
|
||||||
def new_session(self):
|
def new_session(self):
|
||||||
"""Inicia una nueva sesión"""
|
"""Inicia una nueva sesión"""
|
||||||
self.clear_input()
|
self.clear_input()
|
||||||
self.clear_output()
|
self.clear_output()
|
||||||
self.main_window.latex_panel.clear_equations()
|
self.main_window.latex_panel.clear_equations()
|
||||||
if hasattr(self.main_window, '_latex_equations'):
|
if hasattr(self.main_window, "_latex_equations"):
|
||||||
self.main_window._latex_equations.clear()
|
self.main_window._latex_equations.clear()
|
||||||
self.main_window._update_status("✨ Nueva sesión iniciada")
|
self.main_window._update_status("✨ Nueva sesión iniciada")
|
||||||
|
|
||||||
def load_file(self):
|
def load_file(self):
|
||||||
"""Carga archivo en el editor"""
|
"""Carga archivo en el editor"""
|
||||||
filepath, _ = QFileDialog.getOpenFileName(
|
filepath, _ = QFileDialog.getOpenFileName(
|
||||||
self.main_window, "Cargar archivo", "",
|
self.main_window,
|
||||||
"Archivos de texto (*.txt);;Archivos Python (*.py);;Todos los archivos (*.*)"
|
"Cargar archivo",
|
||||||
|
"",
|
||||||
|
"Archivos de texto (*.txt);;Archivos Python (*.py);;Todos los archivos (*.*)",
|
||||||
)
|
)
|
||||||
|
|
||||||
if filepath:
|
if filepath:
|
||||||
try:
|
self._load_file_content(filepath)
|
||||||
with open(filepath, "r", encoding="utf-8") as f:
|
|
||||||
content = f.read()
|
def _load_file_content(self, filepath: str):
|
||||||
|
"""Carga el contenido de un archivo en el editor."""
|
||||||
self.main_window.input_text.setPlainText(content)
|
try:
|
||||||
self.main_window._evaluate_and_update()
|
with open(filepath, "r", encoding="utf-8") as f:
|
||||||
self.main_window._update_status(f"📁 Archivo cargado: {Path(filepath).name}")
|
content = f.read()
|
||||||
|
|
||||||
except Exception as e:
|
self.main_window.input_text.setPlainText(content)
|
||||||
QMessageBox.critical(self.main_window, "Error", f"No se pudo cargar el archivo:\n{e}")
|
self.main_window._evaluate_and_update()
|
||||||
|
self.main_window._update_status(
|
||||||
|
f"📁 Archivo cargado: {Path(filepath).name}"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Añadir a recientes y actualizar menú
|
||||||
|
self.main_window.settings_manager.add_recent_file(filepath)
|
||||||
|
self._update_recent_files_menu()
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
QMessageBox.critical(
|
||||||
|
self.main_window, "Error", f"No se pudo cargar el archivo:\n{e}"
|
||||||
|
)
|
||||||
|
|
||||||
def save_file(self):
|
def save_file(self):
|
||||||
"""Guarda contenido del editor"""
|
"""Guarda contenido del editor"""
|
||||||
filepath, _ = QFileDialog.getSaveFileName(
|
filepath, _ = QFileDialog.getSaveFileName(
|
||||||
self.main_window, "Guardar archivo", "",
|
self.main_window,
|
||||||
"Archivos de texto (*.txt);;Archivos Python (*.py);;Todos los archivos (*.*)"
|
"Guardar archivo",
|
||||||
|
"",
|
||||||
|
"Archivos de texto (*.txt);;Archivos Python (*.py);;Todos los archivos (*.*)",
|
||||||
)
|
)
|
||||||
|
|
||||||
if filepath:
|
if filepath:
|
||||||
try:
|
try:
|
||||||
content = self.main_window.input_text.toPlainText()
|
content = self.main_window.input_text.toPlainText()
|
||||||
with open(filepath, "w", encoding="utf-8") as f:
|
with open(filepath, "w", encoding="utf-8") as f:
|
||||||
f.write(content)
|
f.write(content)
|
||||||
|
|
||||||
self.main_window._update_status(f"💾 Archivo guardado: {Path(filepath).name}")
|
self.main_window._update_status(
|
||||||
|
f"💾 Archivo guardado: {Path(filepath).name}"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Añadir a recientes y actualizar menú
|
||||||
|
self.main_window.settings_manager.add_recent_file(filepath)
|
||||||
|
self._update_recent_files_menu()
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
QMessageBox.critical(self.main_window, "Error", f"No se pudo guardar el archivo:\n{e}")
|
QMessageBox.critical(
|
||||||
|
self.main_window, "Error", f"No se pudo guardar el archivo:\n{e}"
|
||||||
|
)
|
||||||
|
|
||||||
|
def _update_recent_files_menu(self):
|
||||||
|
"""Actualiza el menú de archivos recientes"""
|
||||||
|
self.recent_files_menu.clear()
|
||||||
|
recent_files = self.main_window.settings_manager.get_setting("recent_files", [])
|
||||||
|
|
||||||
|
if not recent_files:
|
||||||
|
empty_action = QAction("(Vacío)", self.main_window)
|
||||||
|
empty_action.setEnabled(False)
|
||||||
|
self.recent_files_menu.addAction(empty_action)
|
||||||
|
return
|
||||||
|
|
||||||
|
for filepath in recent_files:
|
||||||
|
action = QAction(filepath, self.main_window)
|
||||||
|
action.triggered.connect(
|
||||||
|
lambda checked=False, path=filepath: self._load_file_content(path)
|
||||||
|
)
|
||||||
|
self.recent_files_menu.addAction(action)
|
||||||
|
|
||||||
# ========== FUNCIONES DE MENÚ EDITAR ==========
|
# ========== FUNCIONES DE MENÚ EDITAR ==========
|
||||||
|
|
||||||
def clear_input(self):
|
def clear_input(self):
|
||||||
"""Limpia panel de entrada"""
|
"""Limpia panel de entrada"""
|
||||||
self.main_window.input_text.clear()
|
self.main_window.input_text.clear()
|
||||||
self.main_window._clear_output()
|
self.main_window._clear_output()
|
||||||
|
|
||||||
def clear_output(self):
|
def clear_output(self):
|
||||||
"""Limpia panel de salida y LaTeX"""
|
"""Limpia panel de salida y LaTeX"""
|
||||||
self.main_window._clear_output()
|
self.main_window._clear_output()
|
||||||
self.main_window.latex_panel.clear_equations()
|
self.main_window.latex_panel.clear_equations()
|
||||||
if hasattr(self.main_window, '_latex_equations'):
|
if hasattr(self.main_window, "_latex_equations"):
|
||||||
self.main_window._latex_equations.clear()
|
self.main_window._latex_equations.clear()
|
||||||
|
|
||||||
def clear_history(self):
|
def clear_history(self):
|
||||||
"""Limpia el archivo de historial"""
|
"""Limpia el archivo de historial"""
|
||||||
try:
|
try:
|
||||||
|
@ -239,24 +286,26 @@ class MenuManager:
|
||||||
os.remove(self.main_window.HISTORY_FILE)
|
os.remove(self.main_window.HISTORY_FILE)
|
||||||
self.main_window._update_status("✓ Historial limpiado")
|
self.main_window._update_status("✓ Historial limpiado")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
QMessageBox.critical(self.main_window, "Error", f"No se pudo limpiar el historial:\n{e}")
|
QMessageBox.critical(
|
||||||
|
self.main_window, "Error", f"No se pudo limpiar el historial:\n{e}"
|
||||||
|
)
|
||||||
|
|
||||||
def set_font_size(self, is_large: bool):
|
def set_font_size(self, is_large: bool):
|
||||||
"""Cambia el tamaño de fuente de los paneles"""
|
"""Cambia el tamaño de fuente de los paneles"""
|
||||||
# Guardar configuración
|
# Guardar configuración
|
||||||
self.main_window.settings_manager.set_setting("font_size_large", is_large)
|
self.main_window.settings_manager.set_setting("font_size_large", is_large)
|
||||||
|
|
||||||
# Actualizar checkboxes
|
# Actualizar checkboxes
|
||||||
self.font_small_action.setChecked(not is_large)
|
self.font_small_action.setChecked(not is_large)
|
||||||
self.font_large_action.setChecked(is_large)
|
self.font_large_action.setChecked(is_large)
|
||||||
|
|
||||||
# Aplicar nuevo tamaño
|
# Aplicar nuevo tamaño
|
||||||
font_size = 14 if is_large else 11
|
font_size = 14 if is_large else 11
|
||||||
self._apply_font_size_to_panels(font_size)
|
self._apply_font_size_to_panels(font_size)
|
||||||
|
|
||||||
status_text = f"🔤 Fuente cambiada a {'grande' if is_large else 'pequeña'} ({font_size}px)"
|
status_text = f"🔤 Fuente cambiada a {'grande' if is_large else 'pequeña'} ({font_size}px)"
|
||||||
self.main_window._update_status(status_text)
|
self.main_window._update_status(status_text)
|
||||||
|
|
||||||
def _apply_font_size_to_panels(self, font_size: int):
|
def _apply_font_size_to_panels(self, font_size: int):
|
||||||
"""Aplica el tamaño de fuente a los paneles de texto"""
|
"""Aplica el tamaño de fuente a los paneles de texto"""
|
||||||
style_update = f"""
|
style_update = f"""
|
||||||
|
@ -264,26 +313,26 @@ class MenuManager:
|
||||||
font-size: {font_size}px;
|
font-size: {font_size}px;
|
||||||
}}
|
}}
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# Actualizar estilo de los paneles principales
|
# Actualizar estilo de los paneles principales
|
||||||
current_style = self.main_window.styleSheet()
|
current_style = self.main_window.styleSheet()
|
||||||
# Reemplazar solo la parte de font-size en QPlainTextEdit y QTextEdit
|
# Reemplazar solo la parte de font-size en QPlainTextEdit y QTextEdit
|
||||||
import re
|
import re
|
||||||
|
|
||||||
# Patrón para encontrar y reemplazar font-size en QPlainTextEdit y QTextEdit
|
# Patrón para encontrar y reemplazar font-size en QPlainTextEdit y QTextEdit
|
||||||
pattern = r'(QPlainTextEdit, QTextEdit\s*\{[^}]*?)font-size:\s*\d+px;([^}]*\})'
|
pattern = r"(QPlainTextEdit, QTextEdit\s*\{[^}]*?)font-size:\s*\d+px;([^}]*\})"
|
||||||
replacement = rf'\1font-size: {font_size}px;\2'
|
replacement = rf"\1font-size: {font_size}px;\2"
|
||||||
|
|
||||||
new_style = re.sub(pattern, replacement, current_style)
|
new_style = re.sub(pattern, replacement, current_style)
|
||||||
|
|
||||||
# Si no se encontró el patrón, agregar el estilo
|
# Si no se encontró el patrón, agregar el estilo
|
||||||
if new_style == current_style:
|
if new_style == current_style:
|
||||||
new_style += style_update
|
new_style += style_update
|
||||||
|
|
||||||
self.main_window.setStyleSheet(new_style)
|
self.main_window.setStyleSheet(new_style)
|
||||||
|
|
||||||
# ========== FUNCIONES DE MENÚ HERRAMIENTAS ==========
|
# ========== FUNCIONES DE MENÚ HERRAMIENTAS ==========
|
||||||
|
|
||||||
def reload_types(self):
|
def reload_types(self):
|
||||||
"""Recarga el sistema de tipos"""
|
"""Recarga el sistema de tipos"""
|
||||||
try:
|
try:
|
||||||
|
@ -293,13 +342,15 @@ class MenuManager:
|
||||||
self.main_window._update_status("✓ Sistema de tipos recargado")
|
self.main_window._update_status("✓ Sistema de tipos recargado")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.logger.error(f"Error recargando tipos: {e}")
|
self.logger.error(f"Error recargando tipos: {e}")
|
||||||
QMessageBox.critical(self.main_window, "Error", f"Error recargando tipos:\n{e}")
|
QMessageBox.critical(
|
||||||
|
self.main_window, "Error", f"Error recargando tipos:\n{e}"
|
||||||
|
)
|
||||||
|
|
||||||
def show_types_info(self):
|
def show_types_info(self):
|
||||||
"""Muestra información sobre tipos disponibles"""
|
"""Muestra información sobre tipos disponibles"""
|
||||||
try:
|
try:
|
||||||
context_info = self.main_window.engine.get_context_info()
|
context_info = self.main_window.engine.get_context_info()
|
||||||
|
|
||||||
info_text = f"""INFORMACIÓN DEL SISTEMA ALGEBRAICO PURO
|
info_text = f"""INFORMACIÓN DEL SISTEMA ALGEBRAICO PURO
|
||||||
|
|
||||||
Ecuaciones en el sistema: {context_info.get('equations', 0)}
|
Ecuaciones en el sistema: {context_info.get('equations', 0)}
|
||||||
|
@ -313,39 +364,58 @@ CARACTERÍSTICAS:
|
||||||
• Evaluación numérica inteligente
|
• Evaluación numérica inteligente
|
||||||
• Atajo x=? equivale a solve(x)
|
• Atajo x=? equivale a solve(x)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
self._show_info_dialog("Información del Sistema", info_text)
|
self._show_info_dialog("Información del Sistema", info_text)
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
QMessageBox.critical(self.main_window, "Error", f"Error obteniendo información:\n{e}")
|
QMessageBox.critical(
|
||||||
|
self.main_window, "Error", f"Error obteniendo información:\n{e}"
|
||||||
|
)
|
||||||
|
|
||||||
def show_types_syntax(self):
|
def show_types_syntax(self):
|
||||||
"""Muestra sintaxis de tipos disponibles"""
|
"""Muestra sintaxis de tipos disponibles"""
|
||||||
try:
|
try:
|
||||||
types_info = self.main_window.engine.get_available_types()
|
types_info = self.main_window.engine.get_available_types()
|
||||||
syntax_text = "SINTAXIS DE TIPOS DISPONIBLES\n\n"
|
syntax_text = "SINTAXIS DE TIPOS DISPONIBLES\n\n"
|
||||||
|
|
||||||
# Aquí iría el código para mostrar sintaxis
|
# Aquí iría el código para mostrar sintaxis
|
||||||
# Similar al original pero adaptado para PySide6
|
# Similar al original pero adaptado para PySide6
|
||||||
|
|
||||||
self._show_info_dialog("Sintaxis de Tipos", syntax_text)
|
self._show_info_dialog("Sintaxis de Tipos", syntax_text)
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
QMessageBox.critical(self.main_window, "Error", f"Error obteniendo sintaxis:\n{e}")
|
QMessageBox.critical(
|
||||||
|
self.main_window, "Error", f"Error obteniendo sintaxis:\n{e}"
|
||||||
|
)
|
||||||
|
|
||||||
# ========== FUNCIONES DE DIAGNÓSTICO ==========
|
# ========== FUNCIONES DE DIAGNÓSTICO ==========
|
||||||
|
|
||||||
def _diagnose_mathjax(self):
|
def _diagnose_mathjax(self):
|
||||||
"""Ejecuta diagnóstico de MathJax"""
|
"""Ejecuta diagnóstico de MathJax"""
|
||||||
if not hasattr(self.main_window.latex_panel, '_webview_available') or not self.main_window.latex_panel._webview_available:
|
if (
|
||||||
QMessageBox.warning(self.main_window, "Diagnóstico", "Panel LaTeX no usa WebEngine (usando fallback)")
|
not hasattr(self.main_window.latex_panel, "_webview_available")
|
||||||
|
or not self.main_window.latex_panel._webview_available
|
||||||
|
):
|
||||||
|
QMessageBox.warning(
|
||||||
|
self.main_window,
|
||||||
|
"Diagnóstico",
|
||||||
|
"Panel LaTeX no usa WebEngine (usando fallback)",
|
||||||
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
# Aquí iría el código de diagnóstico
|
# Aquí iría el código de diagnóstico
|
||||||
# Por ahora solo mostrar estado
|
# Por ahora solo mostrar estado
|
||||||
status = "WebEngine disponible" if self.main_window.latex_panel._webview_available else "Usando fallback HTML"
|
status = (
|
||||||
equations = len(self.main_window._latex_equations) if hasattr(self.main_window, '_latex_equations') else 0
|
"WebEngine disponible"
|
||||||
|
if self.main_window.latex_panel._webview_available
|
||||||
|
else "Usando fallback HTML"
|
||||||
|
)
|
||||||
|
equations = (
|
||||||
|
len(self.main_window._latex_equations)
|
||||||
|
if hasattr(self.main_window, "_latex_equations")
|
||||||
|
else 0
|
||||||
|
)
|
||||||
|
|
||||||
info = f"""DIAGNÓSTICO MATHJAX
|
info = f"""DIAGNÓSTICO MATHJAX
|
||||||
|
|
||||||
Estado: {status}
|
Estado: {status}
|
||||||
|
@ -355,16 +425,22 @@ Panel visible: {self.main_window.latex_panel_visible}
|
||||||
Para depuración completa, revise la consola del navegador
|
Para depuración completa, revise la consola del navegador
|
||||||
en el WebEngineView.
|
en el WebEngineView.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
self._show_info_dialog("Diagnóstico MathJax", info)
|
self._show_info_dialog("Diagnóstico MathJax", info)
|
||||||
|
|
||||||
def _show_latex_panel_status(self):
|
def _show_latex_panel_status(self):
|
||||||
"""Muestra estado del panel LaTeX"""
|
"""Muestra estado del panel LaTeX"""
|
||||||
panel_exists = hasattr(self.main_window, 'latex_panel')
|
panel_exists = hasattr(self.main_window, "latex_panel")
|
||||||
panel_visible = self.main_window.latex_panel_visible if panel_exists else False
|
panel_visible = self.main_window.latex_panel_visible if panel_exists else False
|
||||||
webview_available = self.main_window.latex_panel._webview_available if panel_exists else False
|
webview_available = (
|
||||||
equations_count = len(self.main_window._latex_equations) if hasattr(self.main_window, '_latex_equations') else 0
|
self.main_window.latex_panel._webview_available if panel_exists else False
|
||||||
|
)
|
||||||
|
equations_count = (
|
||||||
|
len(self.main_window._latex_equations)
|
||||||
|
if hasattr(self.main_window, "_latex_equations")
|
||||||
|
else 0
|
||||||
|
)
|
||||||
|
|
||||||
status_message = f"""ESTADO DEL PANEL LATEX
|
status_message = f"""ESTADO DEL PANEL LATEX
|
||||||
|
|
||||||
COMPONENTES:
|
COMPONENTES:
|
||||||
|
@ -381,24 +457,27 @@ PARA SOLUCIONAR:
|
||||||
2. Si WebEngine no está disponible:
|
2. Si WebEngine no está disponible:
|
||||||
→ Instalar con: pip install PySide6-WebEngine
|
→ Instalar con: pip install PySide6-WebEngine
|
||||||
"""
|
"""
|
||||||
|
|
||||||
self._show_info_dialog("Estado Panel LaTeX", status_message)
|
self._show_info_dialog("Estado Panel LaTeX", status_message)
|
||||||
|
|
||||||
def _save_latex_html(self):
|
def _save_latex_html(self):
|
||||||
"""Guarda el HTML del panel LaTeX para diagnóstico"""
|
"""Guarda el HTML del panel LaTeX para diagnóstico"""
|
||||||
try:
|
try:
|
||||||
# Obtener HTML del panel LaTeX
|
# Obtener HTML del panel LaTeX
|
||||||
latex_panel = self.main_window.latex_panel
|
latex_panel = self.main_window.latex_panel
|
||||||
|
|
||||||
if hasattr(latex_panel, '_webview_available') and latex_panel._webview_available:
|
if (
|
||||||
|
hasattr(latex_panel, "_webview_available")
|
||||||
|
and latex_panel._webview_available
|
||||||
|
):
|
||||||
# Panel con WebEngine
|
# Panel con WebEngine
|
||||||
if hasattr(latex_panel, 'webview') and latex_panel._webview_initialized:
|
if hasattr(latex_panel, "webview") and latex_panel._webview_initialized:
|
||||||
# Obtener HTML actual del WebView
|
# Obtener HTML actual del WebView
|
||||||
def on_html_received(html_content):
|
def on_html_received(html_content):
|
||||||
self._save_html_to_file(html_content, "webview_current")
|
self._save_html_to_file(html_content, "webview_current")
|
||||||
|
|
||||||
latex_panel.webview.page().toHtml(on_html_received)
|
latex_panel.webview.page().toHtml(on_html_received)
|
||||||
|
|
||||||
# También guardar el HTML base generado
|
# También guardar el HTML base generado
|
||||||
base_html = latex_panel._generate_mathjax_html()
|
base_html = latex_panel._generate_mathjax_html()
|
||||||
self._save_html_to_file(base_html, "webview_base")
|
self._save_html_to_file(base_html, "webview_base")
|
||||||
|
@ -408,66 +487,71 @@ PARA SOLUCIONAR:
|
||||||
self._save_html_to_file(base_html, "webview_not_initialized")
|
self._save_html_to_file(base_html, "webview_not_initialized")
|
||||||
else:
|
else:
|
||||||
# Panel con fallback text browser
|
# Panel con fallback text browser
|
||||||
if hasattr(latex_panel, 'text_browser'):
|
if hasattr(latex_panel, "text_browser"):
|
||||||
fallback_html = latex_panel.text_browser.toHtml()
|
fallback_html = latex_panel.text_browser.toHtml()
|
||||||
self._save_html_to_file(fallback_html, "fallback_textbrowser")
|
self._save_html_to_file(fallback_html, "fallback_textbrowser")
|
||||||
else:
|
else:
|
||||||
self._save_html_to_file("No hay contenido HTML disponible", "no_content")
|
self._save_html_to_file(
|
||||||
|
"No hay contenido HTML disponible", "no_content"
|
||||||
|
)
|
||||||
|
|
||||||
QMessageBox.information(
|
QMessageBox.information(
|
||||||
self.main_window,
|
self.main_window,
|
||||||
"HTML Guardado",
|
"HTML Guardado",
|
||||||
"El HTML del panel LaTeX ha sido guardado en ./debug_html/ para diagnóstico."
|
"El HTML del panel LaTeX ha sido guardado en ./debug_html/ para diagnóstico.",
|
||||||
)
|
)
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.logger.error(f"Error guardando HTML del panel LaTeX: {e}")
|
self.logger.error(f"Error guardando HTML del panel LaTeX: {e}")
|
||||||
QMessageBox.critical(
|
QMessageBox.critical(
|
||||||
self.main_window,
|
self.main_window, "Error", f"Error guardando HTML: {e}"
|
||||||
"Error",
|
|
||||||
f"Error guardando HTML: {e}"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
def _save_html_to_file(self, html_content, file_suffix):
|
def _save_html_to_file(self, html_content, file_suffix):
|
||||||
"""Guarda contenido HTML a un archivo"""
|
"""Guarda contenido HTML a un archivo"""
|
||||||
# Crear directorio de debug si no existe
|
# Crear directorio de debug si no existe
|
||||||
debug_dir = Path("./debug_html")
|
debug_dir = Path("./debug_html")
|
||||||
debug_dir.mkdir(exist_ok=True)
|
debug_dir.mkdir(exist_ok=True)
|
||||||
|
|
||||||
# Generar nombre de archivo con timestamp
|
# Generar nombre de archivo con timestamp
|
||||||
timestamp = time.strftime("%Y%m%d_%H%M%S")
|
timestamp = time.strftime("%Y%m%d_%H%M%S")
|
||||||
filename = f"latex_panel_{file_suffix}_{timestamp}.html"
|
filename = f"latex_panel_{file_suffix}_{timestamp}.html"
|
||||||
filepath = debug_dir / filename
|
filepath = debug_dir / filename
|
||||||
|
|
||||||
try:
|
try:
|
||||||
with open(filepath, "w", encoding="utf-8") as f:
|
with open(filepath, "w", encoding="utf-8") as f:
|
||||||
f.write(html_content)
|
f.write(html_content)
|
||||||
|
|
||||||
self.logger.info(f"HTML guardado en: {filepath}")
|
self.logger.info(f"HTML guardado en: {filepath}")
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.logger.error(f"Error escribiendo archivo HTML: {e}")
|
self.logger.error(f"Error escribiendo archivo HTML: {e}")
|
||||||
|
|
||||||
def _copy_debug_to_clipboard(self):
|
def _copy_debug_to_clipboard(self):
|
||||||
"""Copia información de debug completa al portapapeles"""
|
"""Copia información de debug completa al portapapeles"""
|
||||||
try:
|
try:
|
||||||
# Obtener contenido de entrada
|
# Obtener contenido de entrada
|
||||||
input_content = self.main_window.input_text.toPlainText()
|
input_content = self.main_window.input_text.toPlainText()
|
||||||
|
|
||||||
# Obtener contenido de salida (texto plano)
|
# Obtener contenido de salida (texto plano)
|
||||||
output_content = self.main_window.output_text.toPlainText()
|
output_content = self.main_window.output_text.toPlainText()
|
||||||
|
|
||||||
# Obtener información del sistema
|
# Obtener información del sistema
|
||||||
context_info = self.main_window.engine.get_context_info()
|
context_info = self.main_window.engine.get_context_info()
|
||||||
|
|
||||||
# Obtener ecuaciones LaTeX si están disponibles
|
# Obtener ecuaciones LaTeX si están disponibles
|
||||||
latex_equations = ""
|
latex_equations = ""
|
||||||
if hasattr(self.main_window, '_latex_equations') and self.main_window._latex_equations:
|
if (
|
||||||
latex_equations = "\\n".join([
|
hasattr(self.main_window, "_latex_equations")
|
||||||
f"[{eq['type']}] {eq['content']}"
|
and self.main_window._latex_equations
|
||||||
for eq in self.main_window._latex_equations
|
):
|
||||||
])
|
latex_equations = "\\n".join(
|
||||||
|
[
|
||||||
|
f"[{eq['type']}] {eq['content']}"
|
||||||
|
for eq in self.main_window._latex_equations
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
# Crear reporte de debug completo
|
# Crear reporte de debug completo
|
||||||
debug_report = f"""=== REPORTE DEBUG CALCULADORA MAV ===
|
debug_report = f"""=== REPORTE DEBUG CALCULADORA MAV ===
|
||||||
Timestamp: {time.strftime('%Y-%m-%d %H:%M:%S')}
|
Timestamp: {time.strftime('%Y-%m-%d %H:%M:%S')}
|
||||||
|
@ -493,20 +577,26 @@ MathJax listo: {getattr(self.main_window.latex_panel, '_mathjax_ready', False)}
|
||||||
Panel LaTeX visible: {self.main_window.latex_panel_visible}
|
Panel LaTeX visible: {self.main_window.latex_panel_visible}
|
||||||
|
|
||||||
=== FIN REPORTE ==="""
|
=== FIN REPORTE ==="""
|
||||||
|
|
||||||
# Copiar al portapapeles
|
# Copiar al portapapeles
|
||||||
clipboard = QApplication.clipboard()
|
clipboard = QApplication.clipboard()
|
||||||
clipboard.setText(debug_report)
|
clipboard.setText(debug_report)
|
||||||
|
|
||||||
# Mostrar confirmación
|
# Mostrar confirmación
|
||||||
self.main_window._update_status("📋 Información de debug copiada al portapapeles", 3000)
|
self.main_window._update_status(
|
||||||
|
"📋 Información de debug copiada al portapapeles", 3000
|
||||||
|
)
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.logger.error(f"Error copiando debug: {e}")
|
self.logger.error(f"Error copiando debug: {e}")
|
||||||
QMessageBox.critical(self.main_window, "Error", f"Error copiando debug al portapapeles:\\n{e}")
|
QMessageBox.critical(
|
||||||
|
self.main_window,
|
||||||
|
"Error",
|
||||||
|
f"Error copiando debug al portapapeles:\\n{e}",
|
||||||
|
)
|
||||||
|
|
||||||
# ========== FUNCIONES DE MENÚ AYUDA ==========
|
# ========== FUNCIONES DE MENÚ AYUDA ==========
|
||||||
|
|
||||||
def show_quick_guide(self):
|
def show_quick_guide(self):
|
||||||
"""Muestra guía rápida"""
|
"""Muestra guía rápida"""
|
||||||
guide = """# Calculadora MAV - CAS Híbrido
|
guide = """# Calculadora MAV - CAS Híbrido
|
||||||
|
@ -543,9 +633,9 @@ El sistema detecta automáticamente tipos disponibles en custom_types/
|
||||||
- Escriba "." después de cualquier objeto para ver métodos
|
- Escriba "." después de cualquier objeto para ver métodos
|
||||||
- El sistema usa los tipos registrados automáticamente
|
- El sistema usa los tipos registrados automáticamente
|
||||||
"""
|
"""
|
||||||
|
|
||||||
self._show_info_dialog("Guía Rápida", guide)
|
self._show_info_dialog("Guía Rápida", guide)
|
||||||
|
|
||||||
def show_syntax_help(self):
|
def show_syntax_help(self):
|
||||||
"""Muestra ayuda de sintaxis"""
|
"""Muestra ayuda de sintaxis"""
|
||||||
syntax = """# Sintaxis del CAS Híbrido
|
syntax = """# Sintaxis del CAS Híbrido
|
||||||
|
@ -575,9 +665,9 @@ variable=? # Atajo para solve(variable)
|
||||||
x = valor # Crea Symbol('x')
|
x = valor # Crea Symbol('x')
|
||||||
expresión # Evaluación simbólica automática
|
expresión # Evaluación simbólica automática
|
||||||
"""
|
"""
|
||||||
|
|
||||||
self._show_info_dialog("Sintaxis", syntax)
|
self._show_info_dialog("Sintaxis", syntax)
|
||||||
|
|
||||||
def show_sympy_functions(self):
|
def show_sympy_functions(self):
|
||||||
"""Muestra funciones SymPy disponibles"""
|
"""Muestra funciones SymPy disponibles"""
|
||||||
functions = """# Funciones SymPy Disponibles
|
functions = """# Funciones SymPy Disponibles
|
||||||
|
@ -613,9 +703,9 @@ plot3d(expr, (x, x1, x2), (y, y1, y2))
|
||||||
## Constantes
|
## Constantes
|
||||||
pi, E, I (imaginario), oo (infinito)
|
pi, E, I (imaginario), oo (infinito)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
self._show_info_dialog("Funciones SymPy", functions)
|
self._show_info_dialog("Funciones SymPy", functions)
|
||||||
|
|
||||||
def show_about(self):
|
def show_about(self):
|
||||||
"""Muestra información sobre la aplicación"""
|
"""Muestra información sobre la aplicación"""
|
||||||
about = """Calculadora MAV - CAS Híbrido
|
about = """Calculadora MAV - CAS Híbrido
|
||||||
|
@ -638,9 +728,9 @@ Desarrollado para cálculo matemático avanzado
|
||||||
con soporte especializado para redes,
|
con soporte especializado para redes,
|
||||||
programación y análisis numérico.
|
programación y análisis numérico.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
QMessageBox.about(self.main_window, "Acerca de", about)
|
QMessageBox.about(self.main_window, "Acerca de", about)
|
||||||
|
|
||||||
def _show_info_dialog(self, title: str, content: str):
|
def _show_info_dialog(self, title: str, content: str):
|
||||||
"""Muestra diálogo de información con scroll"""
|
"""Muestra diálogo de información con scroll"""
|
||||||
dialog = QMessageBox(self.main_window)
|
dialog = QMessageBox(self.main_window)
|
||||||
|
@ -648,4 +738,4 @@ programación y análisis numérico.
|
||||||
dialog.setIcon(QMessageBox.Information)
|
dialog.setIcon(QMessageBox.Information)
|
||||||
dialog.setText(content[:200] + "..." if len(content) > 200 else content)
|
dialog.setText(content[:200] + "..." if len(content) > 200 else content)
|
||||||
dialog.setDetailedText(content)
|
dialog.setDetailedText(content)
|
||||||
dialog.exec()
|
dialog.exec()
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
"""
|
"""
|
||||||
Sistema de Configuración y Persistencia para la Calculadora MAV CAS Híbrida
|
Sistema de Configuración y Persistencia para la Calculadora MAV CAS Híbrida
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import json
|
import json
|
||||||
import logging
|
import logging
|
||||||
|
@ -10,15 +11,15 @@ from PySide6.QtCore import QTimer
|
||||||
|
|
||||||
class SettingsManager:
|
class SettingsManager:
|
||||||
"""Gestor de configuración y persistencia"""
|
"""Gestor de configuración y persistencia"""
|
||||||
|
|
||||||
SETTINGS_FILE = "./.data/settings.json"
|
SETTINGS_FILE = "./.data/settings.json"
|
||||||
HISTORY_FILE = "./.data/history.txt"
|
HISTORY_FILE = "./.data/history.txt"
|
||||||
|
|
||||||
def __init__(self, main_window):
|
def __init__(self, main_window):
|
||||||
self.main_window = main_window
|
self.main_window = main_window
|
||||||
self.logger = logging.getLogger(__name__)
|
self.logger = logging.getLogger(__name__)
|
||||||
self.settings = self._load_settings()
|
self.settings = self._load_settings()
|
||||||
|
|
||||||
def _load_settings(self) -> Dict[str, Any]:
|
def _load_settings(self) -> Dict[str, Any]:
|
||||||
"""Carga configuración de la aplicación"""
|
"""Carga configuración de la aplicación"""
|
||||||
if os.path.exists(self.SETTINGS_FILE):
|
if os.path.exists(self.SETTINGS_FILE):
|
||||||
|
@ -33,37 +34,38 @@ class SettingsManager:
|
||||||
"debug_mode": False,
|
"debug_mode": False,
|
||||||
"latex_panel_visible": False,
|
"latex_panel_visible": False,
|
||||||
"latex_panel_width": 300,
|
"latex_panel_width": 300,
|
||||||
"font_size_large": False # False = pequeña (11px), True = grande (14px)
|
"font_size_large": False, # False = pequeña (11px), True = grande (14px)
|
||||||
|
"recent_files": [],
|
||||||
}
|
}
|
||||||
|
|
||||||
def _save_settings(self):
|
def _save_settings(self):
|
||||||
"""Guarda configuraciones"""
|
"""Guarda configuraciones"""
|
||||||
try:
|
try:
|
||||||
# Crear directorio si no existe
|
# Crear directorio si no existe
|
||||||
os.makedirs(os.path.dirname(self.SETTINGS_FILE), exist_ok=True)
|
os.makedirs(os.path.dirname(self.SETTINGS_FILE), exist_ok=True)
|
||||||
|
|
||||||
# Guardar geometría
|
# Guardar geometría
|
||||||
geometry = self.main_window.geometry()
|
geometry = self.main_window.geometry()
|
||||||
self.settings["window_geometry"] = {
|
self.settings["window_geometry"] = {
|
||||||
"x": geometry.x(),
|
"x": geometry.x(),
|
||||||
"y": geometry.y(),
|
"y": geometry.y(),
|
||||||
"width": geometry.width(),
|
"width": geometry.width(),
|
||||||
"height": geometry.height()
|
"height": geometry.height(),
|
||||||
}
|
}
|
||||||
|
|
||||||
# Guardar tamaños del splitter
|
# Guardar tamaños del splitter
|
||||||
if hasattr(self.main_window, 'main_splitter'):
|
if hasattr(self.main_window, "main_splitter"):
|
||||||
self.settings["splitter_sizes"] = self.main_window.main_splitter.sizes()
|
self.settings["splitter_sizes"] = self.main_window.main_splitter.sizes()
|
||||||
|
|
||||||
self.settings["latex_panel_visible"] = self.main_window.latex_panel_visible
|
self.settings["latex_panel_visible"] = self.main_window.latex_panel_visible
|
||||||
self.settings["debug_mode"] = getattr(self.main_window, 'debug', False)
|
self.settings["debug_mode"] = getattr(self.main_window, "debug", False)
|
||||||
|
|
||||||
with open(self.SETTINGS_FILE, "w", encoding="utf-8") as f:
|
with open(self.SETTINGS_FILE, "w", encoding="utf-8") as f:
|
||||||
json.dump(self.settings, f, indent=4, ensure_ascii=False)
|
json.dump(self.settings, f, indent=4, ensure_ascii=False)
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.logger.error(f"Error guardando configuración: {e}")
|
self.logger.error(f"Error guardando configuración: {e}")
|
||||||
|
|
||||||
def _load_history(self):
|
def _load_history(self):
|
||||||
"""Carga historial de entrada"""
|
"""Carga historial de entrada"""
|
||||||
try:
|
try:
|
||||||
|
@ -76,13 +78,13 @@ class SettingsManager:
|
||||||
QTimer.singleShot(100, self.main_window._evaluate_and_update)
|
QTimer.singleShot(100, self.main_window._evaluate_and_update)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.logger.error(f"Error cargando historial: {e}")
|
self.logger.error(f"Error cargando historial: {e}")
|
||||||
|
|
||||||
def _save_history(self):
|
def _save_history(self):
|
||||||
"""Guarda historial de entrada"""
|
"""Guarda historial de entrada"""
|
||||||
try:
|
try:
|
||||||
# Crear directorio si no existe
|
# Crear directorio si no existe
|
||||||
os.makedirs(os.path.dirname(self.HISTORY_FILE), exist_ok=True)
|
os.makedirs(os.path.dirname(self.HISTORY_FILE), exist_ok=True)
|
||||||
|
|
||||||
content = self.main_window.input_text.toPlainText()
|
content = self.main_window.input_text.toPlainText()
|
||||||
if content:
|
if content:
|
||||||
with open(self.HISTORY_FILE, "w", encoding="utf-8") as f:
|
with open(self.HISTORY_FILE, "w", encoding="utf-8") as f:
|
||||||
|
@ -91,36 +93,56 @@ class SettingsManager:
|
||||||
os.remove(self.HISTORY_FILE)
|
os.remove(self.HISTORY_FILE)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.logger.error(f"Error guardando historial: {e}")
|
self.logger.error(f"Error guardando historial: {e}")
|
||||||
|
|
||||||
def _restore_geometry(self):
|
def _restore_geometry(self):
|
||||||
"""Restaura geometría guardada"""
|
"""Restaura geometría guardada"""
|
||||||
try:
|
try:
|
||||||
geom = self.settings.get("window_geometry")
|
geom = self.settings.get("window_geometry")
|
||||||
if geom and isinstance(geom, dict):
|
if geom and isinstance(geom, dict):
|
||||||
self.main_window.setGeometry(geom["x"], geom["y"], geom["width"], geom["height"])
|
self.main_window.setGeometry(
|
||||||
|
geom["x"], geom["y"], geom["width"], geom["height"]
|
||||||
|
)
|
||||||
|
|
||||||
# Restaurar splitter
|
# Restaurar splitter
|
||||||
sizes = self.settings.get("splitter_sizes")
|
sizes = self.settings.get("splitter_sizes")
|
||||||
if sizes and hasattr(self.main_window, 'main_splitter'):
|
if sizes and hasattr(self.main_window, "main_splitter"):
|
||||||
self.main_window.main_splitter.setSizes(sizes)
|
self.main_window.main_splitter.setSizes(sizes)
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.logger.warning(f"No se pudo restaurar geometría: {e}")
|
self.logger.warning(f"No se pudo restaurar geometría: {e}")
|
||||||
|
|
||||||
def initialize(self):
|
def initialize(self):
|
||||||
"""Inicializa la configuración cargando datos"""
|
"""Inicializa la configuración cargando datos"""
|
||||||
self._load_history()
|
self._load_history()
|
||||||
self._restore_geometry()
|
self._restore_geometry()
|
||||||
|
|
||||||
def save_all(self):
|
def save_all(self):
|
||||||
"""Guarda toda la configuración"""
|
"""Guarda toda la configuración"""
|
||||||
self._save_settings()
|
self._save_settings()
|
||||||
self._save_history()
|
self._save_history()
|
||||||
|
|
||||||
def get_setting(self, key: str, default=None):
|
def get_setting(self, key: str, default=None):
|
||||||
"""Obtiene un valor de configuración"""
|
"""Obtiene un valor de configuración"""
|
||||||
return self.settings.get(key, default)
|
return self.settings.get(key, default)
|
||||||
|
|
||||||
def set_setting(self, key: str, value):
|
def set_setting(self, key: str, value):
|
||||||
"""Establece un valor de configuración"""
|
"""Establece un valor de configuración"""
|
||||||
self.settings[key] = value
|
self.settings[key] = value
|
||||||
|
|
||||||
|
def add_recent_file(self, filepath: str):
|
||||||
|
"""Añade un archivo a la lista de recientes y guarda."""
|
||||||
|
try:
|
||||||
|
recent_files = self.get_setting("recent_files", [])
|
||||||
|
|
||||||
|
# Si el archivo ya está, lo eliminamos para volver a añadirlo al principio
|
||||||
|
if filepath in recent_files:
|
||||||
|
recent_files.remove(filepath)
|
||||||
|
|
||||||
|
# Añadir al principio de la lista
|
||||||
|
recent_files.insert(0, filepath)
|
||||||
|
|
||||||
|
# Limitar la lista a 10 elementos
|
||||||
|
self.set_setting("recent_files", recent_files[:10])
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
self.logger.error(f"Error añadiendo archivo reciente: {e}")
|
||||||
|
|
Loading…
Reference in New Issue