191 lines
No EOL
8.3 KiB
Python
191 lines
No EOL
8.3 KiB
Python
"""
|
||
Главный контроллер приложения - связывает модель и представление
|
||
"""
|
||
|
||
from PySide6.QtCore import QObject, Signal
|
||
from datetime import datetime
|
||
from pathlib import Path
|
||
import numpy as np
|
||
|
||
from models.api_model import HelioviewerAPI
|
||
from models.image_model import ImageModel
|
||
from views.main_window import MainWindow
|
||
from utils.image_processor import ImageProcessor
|
||
from utils.metadata_parser import MetadataParser
|
||
|
||
|
||
class AppController(QObject):
|
||
"""Главный контроллер приложения"""
|
||
|
||
def __init__(self):
|
||
super().__init__()
|
||
self.image_model = ImageModel()
|
||
self.api = HelioviewerAPI()
|
||
self.main_window = None
|
||
self.timelapse_controller = None
|
||
|
||
# Подключаем сигналы модели
|
||
self.image_model.layer_added.connect(self.on_layer_added)
|
||
self.image_model.layer_removed.connect(self.on_layer_removed)
|
||
self.image_model.layer_visibility_changed.connect(self.on_layer_visibility_changed)
|
||
self.image_model.layer_opacity_changed.connect(self.on_layer_opacity_changed)
|
||
self.image_model.layer_selected.connect(self.on_layer_selected)
|
||
|
||
# Папка для сохранения по умолчанию
|
||
self.download_folder = Path.home() / "SolarImages"
|
||
self.download_folder.mkdir(exist_ok=True)
|
||
|
||
def show_main_window(self):
|
||
"""Показывает главное окно"""
|
||
self.main_window = MainWindow(self)
|
||
self.main_window.show()
|
||
|
||
# Подключаем сигналы от панели управления
|
||
control_panel = self.main_window.get_control_panel()
|
||
control_panel.load_image_requested.connect(self.load_image_from_api)
|
||
|
||
def load_image_from_api(self, source_id: int, date: datetime):
|
||
"""Загружает изображение из API"""
|
||
self.main_window.update_status(f"Загрузка изображения: {date.strftime('%Y-%m-%d %H:%M')} UTC")
|
||
|
||
# Скачиваем изображение
|
||
filepath = self.api.download_image(source_id, date, self.download_folder)
|
||
|
||
if filepath:
|
||
# Загружаем данные изображения
|
||
img_data = ImageProcessor.load_jp2(str(filepath))
|
||
|
||
if img_data is not None:
|
||
# Извлекаем метаданные
|
||
metadata = MetadataParser.extract_metadata(str(filepath))
|
||
|
||
# Получаем информацию о спектре
|
||
source_info = self.api.SOURCES.get(source_id, {})
|
||
wavelength = source_info.get("wavelength", "Unknown")
|
||
|
||
# Добавляем слой в модель
|
||
layer_id = self.image_model.add_layer(
|
||
filepath, source_id, date, wavelength, img_data, metadata
|
||
)
|
||
|
||
self.main_window.update_status(f"✓ Загружено: {filepath.name}")
|
||
else:
|
||
self.main_window.update_status("✗ Ошибка обработки изображения")
|
||
else:
|
||
self.main_window.update_status("✗ Ошибка загрузки изображения")
|
||
|
||
def on_layer_added(self, layer):
|
||
"""Обработчик добавления слоя"""
|
||
self.main_window.update_layer_list(self.image_model.get_all_layers())
|
||
self.main_window.canvas.set_image(layer.id, layer.image_data)
|
||
|
||
def on_layer_removed(self, layer_id):
|
||
"""Обработчик удаления слоя"""
|
||
self.main_window.layer_widget.remove_layer(layer_id)
|
||
self.main_window.canvas.remove_layer(layer_id)
|
||
|
||
if not self.image_model.get_all_layers():
|
||
self.main_window.metadata_viewer.clear()
|
||
|
||
def on_layer_visibility_changed(self, layer_id, visible):
|
||
"""Обработчик изменения видимости слоя"""
|
||
self.main_window.canvas.set_layer_visibility(layer_id, visible)
|
||
|
||
def on_layer_opacity_changed(self, layer_id, opacity):
|
||
"""Обработчик изменения прозрачности слоя"""
|
||
self.main_window.canvas.set_layer_opacity(layer_id, opacity)
|
||
|
||
def on_layer_selected(self, layer_id):
|
||
"""Обработчик выбора слоя"""
|
||
for layer in self.image_model.get_all_layers():
|
||
if layer.id == layer_id:
|
||
if layer.metadata:
|
||
self.main_window.metadata_viewer.display_metadata(layer.metadata)
|
||
break
|
||
|
||
def set_layer_visibility(self, layer_id, visible):
|
||
self.image_model.set_layer_visibility(layer_id, visible)
|
||
|
||
def set_layer_opacity(self, layer_id, opacity):
|
||
self.image_model.set_layer_opacity(layer_id, opacity)
|
||
|
||
def clear_all_layers(self):
|
||
self.image_model.clear()
|
||
self.main_window.canvas.clear_all_layers()
|
||
self.main_window.metadata_viewer.clear()
|
||
|
||
# Добавьте эти методы в класс AppController:
|
||
|
||
def create_timelapse(self, source_id: int, start_date: datetime,
|
||
end_date: datetime, output_path: Path,
|
||
fps: int = 10, output_format: str = "mp4"):
|
||
"""Создает таймлапс"""
|
||
from controllers.timelapse_controller import TimelapseController
|
||
self.timelapse_controller = TimelapseController()
|
||
|
||
# Подключаем сигналы
|
||
self.timelapse_controller.progress_updated.connect(self.on_timelapse_progress)
|
||
self.timelapse_controller.log_message.connect(self.on_timelapse_log)
|
||
self.timelapse_controller.finished.connect(self.on_timelapse_finished)
|
||
|
||
# Запускаем
|
||
self.timelapse_controller.create_timelapse(
|
||
source_id, start_date, end_date, output_path, fps, output_format
|
||
)
|
||
|
||
def cancel_timelapse(self):
|
||
"""Отменяет создание таймлапса"""
|
||
if hasattr(self, 'timelapse_controller'):
|
||
self.timelapse_controller.cancel()
|
||
|
||
def on_timelapse_progress(self, current, total, message):
|
||
"""Прогресс таймлапса"""
|
||
if self.main_window:
|
||
self.main_window.update_status(f"Таймлапс: {message}")
|
||
|
||
def on_timelapse_log(self, message):
|
||
"""Лог таймлапса"""
|
||
print(f"[Timelapse] {message}")
|
||
|
||
def on_timelapse_finished(self, success, message):
|
||
"""Завершение таймлапса"""
|
||
if self.main_window:
|
||
if success:
|
||
self.main_window.update_status(f"✅ Таймлапс создан")
|
||
from PySide6.QtWidgets import QMessageBox
|
||
QMessageBox.information(self.main_window, "Готово", f"Таймлапс сохранен:\n{message}")
|
||
else:
|
||
self.main_window.update_status(f"❌ Ошибка: {message}")
|
||
|
||
# Добавьте метод:
|
||
def create_timelapse(self, source_id, start_date, end_date, output_path, fps=10, output_format="mp4"):
|
||
"""Создает таймлапс"""
|
||
print(f"[DEBUG] AppController.create_timelapse вызван")
|
||
from controllers.timelapse_controller import TimelapseController
|
||
|
||
self.timelapse_controller = TimelapseController()
|
||
|
||
# Подключаем сигналы
|
||
self.timelapse_controller.progress_updated.connect(self.on_timelapse_progress)
|
||
self.timelapse_controller.log_message.connect(self.on_timelapse_log)
|
||
self.timelapse_controller.finished.connect(self.on_timelapse_finished)
|
||
|
||
# Запускаем
|
||
self.timelapse_controller.create_timelapse(
|
||
source_id, start_date, end_date, output_path, fps, output_format
|
||
)
|
||
print(f"[DEBUG] TimelapseController создан и запущен")
|
||
|
||
def on_timelapse_log(self, message):
|
||
"""Лог таймлапса"""
|
||
print(f"[TIMELAPSE] {message}")
|
||
if self.main_window:
|
||
self.main_window.update_status(f"Таймлапс: {message}")
|
||
|
||
def create_timelapse(self, source_id, start_date, end_date, output_path, fps=10, output_format="mp4"):
|
||
"""Создает таймлапс - заглушка, реальный вызов из диалога"""
|
||
# Реальная реализация в диалоге
|
||
pass
|
||
|
||
def cancel_timelapse(self):
|
||
pass |