working
This commit is contained in:
parent
f7e794774d
commit
09d181eba8
37 changed files with 1898 additions and 5 deletions
|
|
@ -0,0 +1,642 @@
|
|||
"""
|
||||
MainWindow - главное окно приложения на PySide6
|
||||
"""
|
||||
import sys
|
||||
import subprocess
|
||||
import platform
|
||||
from pathlib import Path
|
||||
from datetime import datetime
|
||||
from typing import Optional
|
||||
|
||||
from PySide6.QtWidgets import (
|
||||
QMainWindow, QWidget, QVBoxLayout, QHBoxLayout, QGridLayout,
|
||||
QLabel, QLineEdit, QComboBox, QPushButton, QMenuBar, QMenu,
|
||||
QMessageBox, QFileDialog, QInputDialog, QFrame, QApplication
|
||||
)
|
||||
from PySide6.QtCore import Qt, QTimer, Signal
|
||||
from PySide6.QtGui import QFont, QIcon, QAction
|
||||
|
||||
from services.config_service import ConfigService
|
||||
from services.session_service import SessionService
|
||||
from services.watch_service import WatchService
|
||||
from services.file_service import FileService
|
||||
|
||||
|
||||
class MainWindow(QMainWindow):
|
||||
"""Главное окно приложения"""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
|
||||
# Сервисы
|
||||
self.config_service = ConfigService()
|
||||
self.session_service = SessionService()
|
||||
self.watch_service = WatchService()
|
||||
|
||||
# Переменные состояния
|
||||
self.running = False
|
||||
self.file_count = 0
|
||||
self._blink_timer = None
|
||||
self._new_object_blink_timer = None
|
||||
|
||||
# Настройка окна
|
||||
self.setWindowTitle("Astro Session Watcher v0.3.0")
|
||||
self.setMinimumSize(700, 500)
|
||||
self.resize(800, 550)
|
||||
|
||||
self.center_window()
|
||||
self._create_menu_bar()
|
||||
self._create_main_content()
|
||||
self._load_saved_settings()
|
||||
self._setup_hotkeys()
|
||||
self._update_file_count_display()
|
||||
|
||||
self.setAttribute(Qt.WA_DeleteOnClose)
|
||||
|
||||
def center_window(self):
|
||||
screen = QApplication.primaryScreen().availableGeometry()
|
||||
self.setGeometry(
|
||||
(screen.width() - self.width()) // 2,
|
||||
(screen.height() - self.height()) // 2,
|
||||
self.width(),
|
||||
self.height()
|
||||
)
|
||||
|
||||
def _create_menu_bar(self):
|
||||
menubar = self.menuBar()
|
||||
|
||||
# Меню Файл
|
||||
file_menu = menubar.addMenu("Файл")
|
||||
|
||||
select_folder_action = QAction("Выбрать папку...", self)
|
||||
select_folder_action.setShortcut("Ctrl+O")
|
||||
select_folder_action.triggered.connect(self.select_folder)
|
||||
file_menu.addAction(select_folder_action)
|
||||
|
||||
file_menu.addSeparator()
|
||||
|
||||
equipment_action = QAction("Оборудование...", self)
|
||||
equipment_action.setShortcut("Ctrl+E")
|
||||
equipment_action.triggered.connect(self.open_equipment_dialog)
|
||||
file_menu.addAction(equipment_action)
|
||||
|
||||
celestial_action = QAction("Небесные тела...", self)
|
||||
celestial_action.setShortcut("Ctrl+B")
|
||||
celestial_action.triggered.connect(self.open_celestial_dialog)
|
||||
file_menu.addAction(celestial_action)
|
||||
|
||||
file_menu.addSeparator()
|
||||
|
||||
exit_action = QAction("Выход", self)
|
||||
exit_action.setShortcut("Ctrl+Q")
|
||||
exit_action.triggered.connect(self.close)
|
||||
file_menu.addAction(exit_action)
|
||||
|
||||
# Меню Сессия
|
||||
session_menu = menubar.addMenu("Сессия")
|
||||
|
||||
start_action = QAction("Начать наблюдение", self)
|
||||
start_action.setShortcut("Ctrl+S")
|
||||
start_action.triggered.connect(self.start)
|
||||
session_menu.addAction(start_action)
|
||||
|
||||
stop_action = QAction("Остановить наблюдение", self)
|
||||
stop_action.setShortcut("Ctrl+X")
|
||||
stop_action.triggered.connect(self.stop)
|
||||
session_menu.addAction(stop_action)
|
||||
|
||||
session_menu.addSeparator()
|
||||
|
||||
open_folder_action = QAction("Открыть папку сессии", self)
|
||||
open_folder_action.setShortcut("Ctrl+F")
|
||||
open_folder_action.triggered.connect(self.open_session_folder)
|
||||
session_menu.addAction(open_folder_action)
|
||||
|
||||
session_menu.addSeparator()
|
||||
|
||||
new_object_action = QAction("Новая цель...", self)
|
||||
new_object_action.setShortcut("Ctrl+Shift+N")
|
||||
new_object_action.triggered.connect(self.set_new_object)
|
||||
session_menu.addAction(new_object_action)
|
||||
|
||||
# Меню Помощь
|
||||
help_menu = menubar.addMenu("Помощь")
|
||||
|
||||
instructions_action = QAction("Инструкция", self)
|
||||
instructions_action.setShortcut("F2")
|
||||
instructions_action.triggered.connect(self.show_instructions)
|
||||
help_menu.addAction(instructions_action)
|
||||
|
||||
help_menu.addSeparator()
|
||||
|
||||
about_action = QAction("О программе", self)
|
||||
about_action.setShortcut("F1")
|
||||
about_action.triggered.connect(self.show_info)
|
||||
help_menu.addAction(about_action)
|
||||
|
||||
def _create_main_content(self):
|
||||
central_widget = QWidget()
|
||||
self.setCentralWidget(central_widget)
|
||||
|
||||
main_layout = QVBoxLayout(central_widget)
|
||||
main_layout.setContentsMargins(20, 20, 20, 20)
|
||||
main_layout.setSpacing(15)
|
||||
|
||||
grid_layout = QGridLayout()
|
||||
grid_layout.setVerticalSpacing(12)
|
||||
grid_layout.setHorizontalSpacing(15)
|
||||
|
||||
# Row 0: Папка
|
||||
folder_label = QLabel("Папка:")
|
||||
folder_label.setFont(QFont("", 10, QFont.Bold))
|
||||
grid_layout.addWidget(folder_label, 0, 0, Qt.AlignRight | Qt.AlignVCenter)
|
||||
|
||||
folder_widget = QWidget()
|
||||
folder_layout = QHBoxLayout(folder_widget)
|
||||
folder_layout.setContentsMargins(0, 0, 0, 0)
|
||||
folder_layout.setSpacing(10)
|
||||
|
||||
self.folder_entry = QLineEdit()
|
||||
self.folder_entry.setPlaceholderText("Выберите папку для отслеживания")
|
||||
folder_layout.addWidget(self.folder_entry)
|
||||
|
||||
self.folder_button = QPushButton("Обзор...")
|
||||
self.folder_button.setFixedWidth(80)
|
||||
self.folder_button.clicked.connect(self.select_folder)
|
||||
folder_layout.addWidget(self.folder_button)
|
||||
|
||||
grid_layout.addWidget(folder_widget, 0, 1)
|
||||
|
||||
# Row 1: Оборудование
|
||||
equipment_label = QLabel("Оборудование:")
|
||||
equipment_label.setFont(QFont("", 10, QFont.Bold))
|
||||
grid_layout.addWidget(equipment_label, 1, 0, Qt.AlignRight | Qt.AlignVCenter)
|
||||
|
||||
equipment_widget = QWidget()
|
||||
equipment_layout = QHBoxLayout(equipment_widget)
|
||||
equipment_layout.setContentsMargins(0, 0, 0, 0)
|
||||
equipment_layout.setSpacing(10)
|
||||
|
||||
self.camera_combo = QComboBox()
|
||||
self.camera_combo.setEditable(False)
|
||||
equipment_layout.addWidget(self.camera_combo)
|
||||
|
||||
self.lens_combo = QComboBox()
|
||||
self.lens_combo.setEditable(False)
|
||||
equipment_layout.addWidget(self.lens_combo)
|
||||
|
||||
grid_layout.addWidget(equipment_widget, 1, 1)
|
||||
|
||||
# Row 2: Цель
|
||||
target_label = QLabel("Цель:")
|
||||
target_label.setFont(QFont("", 10, QFont.Bold))
|
||||
grid_layout.addWidget(target_label, 2, 0, Qt.AlignRight | Qt.AlignVCenter)
|
||||
|
||||
target_widget = QWidget()
|
||||
target_layout = QHBoxLayout(target_widget)
|
||||
target_layout.setContentsMargins(0, 0, 0, 0)
|
||||
target_layout.setSpacing(10)
|
||||
|
||||
self.object_combo = QComboBox()
|
||||
self.object_combo.setEditable(True)
|
||||
self.object_combo.setInsertPolicy(QComboBox.NoInsert)
|
||||
# Настройка плейсхолдера
|
||||
self.object_combo.lineEdit().setPlaceholderText("Введите название цели")
|
||||
# Автодополнение при вводе
|
||||
self.object_combo.lineEdit().textChanged.connect(self._on_object_text_changed)
|
||||
target_layout.addWidget(self.object_combo)
|
||||
|
||||
self.new_object_button = QPushButton("Новая цель")
|
||||
self.new_object_button.setFixedWidth(100)
|
||||
self.new_object_button.setEnabled(False)
|
||||
self.new_object_button.clicked.connect(self.set_new_object)
|
||||
target_layout.addWidget(self.new_object_button)
|
||||
|
||||
grid_layout.addWidget(target_widget, 2, 1)
|
||||
|
||||
# Row 3: Статистика
|
||||
stats_label = QLabel("Статистика:")
|
||||
stats_label.setFont(QFont("", 10, QFont.Bold))
|
||||
grid_layout.addWidget(stats_label, 3, 0, Qt.AlignRight | Qt.AlignVCenter)
|
||||
|
||||
self.file_count_label = QLabel("Файлов получено: 0")
|
||||
self.file_count_label.setFont(QFont("", 11))
|
||||
grid_layout.addWidget(self.file_count_label, 3, 1, Qt.AlignLeft)
|
||||
|
||||
# Row 4: Статус
|
||||
status_label = QLabel("Статус:")
|
||||
status_label.setFont(QFont("", 10, QFont.Bold))
|
||||
grid_layout.addWidget(status_label, 4, 0, Qt.AlignRight | Qt.AlignVCenter)
|
||||
|
||||
self.status_label = QLabel("IDLE")
|
||||
self.status_label.setFont(QFont("", 12, QFont.Bold))
|
||||
self.status_label.setStyleSheet("color: #666666;")
|
||||
grid_layout.addWidget(self.status_label, 4, 1, Qt.AlignLeft)
|
||||
|
||||
main_layout.addLayout(grid_layout)
|
||||
|
||||
separator = QFrame()
|
||||
separator.setFrameShape(QFrame.HLine)
|
||||
separator.setStyleSheet("background-color: #333333; max-height: 1px;")
|
||||
main_layout.addWidget(separator)
|
||||
|
||||
buttons_layout = QHBoxLayout()
|
||||
buttons_layout.setSpacing(15)
|
||||
buttons_layout.setAlignment(Qt.AlignCenter)
|
||||
|
||||
self.start_button = QPushButton("▶ Начать отслеживание")
|
||||
self.start_button.setFixedSize(180, 35)
|
||||
self.start_button.setStyleSheet("""
|
||||
QPushButton {
|
||||
background-color: #4CAF50;
|
||||
color: white;
|
||||
font-weight: bold;
|
||||
border-radius: 4px;
|
||||
}
|
||||
QPushButton:hover {
|
||||
background-color: #45a049;
|
||||
}
|
||||
""")
|
||||
self.start_button.clicked.connect(self.start)
|
||||
buttons_layout.addWidget(self.start_button)
|
||||
|
||||
self.stop_button = QPushButton("■ Остановить")
|
||||
self.stop_button.setFixedSize(180, 35)
|
||||
self.stop_button.setEnabled(False)
|
||||
self.stop_button.setStyleSheet("""
|
||||
QPushButton {
|
||||
background-color: #f44336;
|
||||
color: white;
|
||||
font-weight: bold;
|
||||
border-radius: 4px;
|
||||
}
|
||||
QPushButton:hover {
|
||||
background-color: #d32f2f;
|
||||
}
|
||||
""")
|
||||
self.stop_button.clicked.connect(self.stop)
|
||||
buttons_layout.addWidget(self.stop_button)
|
||||
|
||||
main_layout.addLayout(buttons_layout)
|
||||
|
||||
footer_layout = QHBoxLayout()
|
||||
|
||||
version_label = QLabel("v0.3.0-alpha")
|
||||
version_label.setStyleSheet("color: #666666; font-size: 11px;")
|
||||
footer_layout.addWidget(version_label)
|
||||
|
||||
footer_layout.addStretch()
|
||||
|
||||
copyright_label = QLabel("Made by Vic Sergeev 2026")
|
||||
copyright_label.setStyleSheet("color: #666666; font-size: 11px;")
|
||||
footer_layout.addWidget(copyright_label)
|
||||
|
||||
main_layout.addLayout(footer_layout)
|
||||
|
||||
def _on_object_text_changed(self, text):
|
||||
"""Автодополнение при вводе названия цели"""
|
||||
if not text:
|
||||
return
|
||||
|
||||
# Поиск совпадений в списке небесных тел
|
||||
celestial_bodies = self.config_service.get_celestial_bodies()
|
||||
matches = [body for body in celestial_bodies if body.lower().startswith(text.lower())]
|
||||
|
||||
if matches and matches[0] != text:
|
||||
# Временно отключаем сигнал, чтобы избежать рекурсии
|
||||
self.object_combo.lineEdit().blockSignals(True)
|
||||
self.object_combo.lineEdit().setText(matches[0])
|
||||
self.object_combo.lineEdit().setSelection(len(text), len(matches[0]))
|
||||
self.object_combo.lineEdit().blockSignals(False)
|
||||
|
||||
def _load_saved_settings(self):
|
||||
cameras = self.config_service.get_cameras()
|
||||
lenses = self.config_service.get_lenses()
|
||||
celestial_bodies = self.config_service.get_celestial_bodies()
|
||||
|
||||
if cameras:
|
||||
self.camera_combo.addItems(cameras)
|
||||
last_camera = self.config_service.get_last_camera()
|
||||
if last_camera and last_camera in cameras:
|
||||
self.camera_combo.setCurrentText(last_camera)
|
||||
|
||||
if lenses:
|
||||
self.lens_combo.addItems(lenses)
|
||||
last_lens = self.config_service.get_last_lens()
|
||||
if last_lens and last_lens in lenses:
|
||||
self.lens_combo.setCurrentText(last_lens)
|
||||
|
||||
if celestial_bodies:
|
||||
self.object_combo.addItems(celestial_bodies)
|
||||
|
||||
last_folder = self.config_service.get_last_watch_folder()
|
||||
if last_folder:
|
||||
self.folder_entry.setText(last_folder)
|
||||
|
||||
def _setup_hotkeys(self):
|
||||
pass
|
||||
|
||||
def _set_running_state(self, state: bool):
|
||||
self.running = state
|
||||
|
||||
if state:
|
||||
self.start_button.setEnabled(False)
|
||||
self.stop_button.setEnabled(True)
|
||||
self.new_object_button.setEnabled(True)
|
||||
self.status_label.setText("● ON AIR")
|
||||
self.status_label.setStyleSheet("color: #ff0000; font-weight: bold;")
|
||||
self._start_blinking()
|
||||
self._start_new_object_blinking()
|
||||
else:
|
||||
self.start_button.setEnabled(True)
|
||||
self.stop_button.setEnabled(False)
|
||||
self.new_object_button.setEnabled(False)
|
||||
self.status_label.setText("IDLE")
|
||||
self.status_label.setStyleSheet("color: #666666; font-weight: bold;")
|
||||
self._stop_blinking()
|
||||
self._stop_new_object_blinking()
|
||||
|
||||
def _start_blinking(self):
|
||||
self._blink_timer = QTimer()
|
||||
self._blink_timer.timeout.connect(self._do_blink)
|
||||
self._blink_timer.start(500)
|
||||
|
||||
def _do_blink(self):
|
||||
if not self.running:
|
||||
return
|
||||
current_style = self.status_label.styleSheet()
|
||||
if "color: #ff0000" in current_style:
|
||||
self.status_label.setStyleSheet("color: #ffffff; font-weight: bold;")
|
||||
else:
|
||||
self.status_label.setStyleSheet("color: #ff0000; font-weight: bold;")
|
||||
|
||||
def _stop_blinking(self):
|
||||
if self._blink_timer:
|
||||
self._blink_timer.stop()
|
||||
self._blink_timer = None
|
||||
self.status_label.setStyleSheet("color: #666666; font-weight: bold;")
|
||||
|
||||
def _start_new_object_blinking(self):
|
||||
self._new_object_blink_timer = QTimer()
|
||||
self._new_object_blink_timer.timeout.connect(self._do_new_object_blink)
|
||||
self._new_object_blink_timer.start(500)
|
||||
|
||||
def _do_new_object_blink(self):
|
||||
if not self.running:
|
||||
return
|
||||
current_style = self.new_object_button.styleSheet()
|
||||
if "border: 2px solid red" in current_style:
|
||||
self.new_object_button.setStyleSheet("")
|
||||
else:
|
||||
self.new_object_button.setStyleSheet("border: 2px solid red; border-radius: 4px;")
|
||||
|
||||
def _stop_new_object_blinking(self):
|
||||
if self._new_object_blink_timer:
|
||||
self._new_object_blink_timer.stop()
|
||||
self._new_object_blink_timer = None
|
||||
self.new_object_button.setStyleSheet("")
|
||||
|
||||
def _update_file_count_display(self):
|
||||
if self.running and self.session_service.get_current_object():
|
||||
current_obj = self.session_service.get_current_object()
|
||||
self.file_count = current_obj.photo_count
|
||||
self.file_count_label.setText(f"Файлов получено: {self.file_count}")
|
||||
QTimer.singleShot(1000, self._update_file_count_display)
|
||||
|
||||
def _on_file_received(self, file_path: Path):
|
||||
"""Обработчик получения нового файла"""
|
||||
print(f"Обнаружен файл: {file_path}")
|
||||
if self.session_service.handle_file(file_path):
|
||||
self.file_count += 1
|
||||
self.file_count_label.setText(f"Файлов получено: {self.file_count}")
|
||||
print(f"Файл обработан: {file_path.name}")
|
||||
else:
|
||||
print(f"Не удалось обработать файл: {file_path}")
|
||||
|
||||
def select_folder(self):
|
||||
folder = QFileDialog.getExistingDirectory(self, "Выберите папку для отслеживания")
|
||||
if folder:
|
||||
self.folder_entry.setText(folder)
|
||||
self.config_service.set_last_watch_folder(folder)
|
||||
|
||||
def start(self):
|
||||
watch_folder = self.folder_entry.text()
|
||||
object_name = self.object_combo.currentText()
|
||||
|
||||
if not watch_folder:
|
||||
QMessageBox.critical(self, "Ошибка", "Папка для отслеживания не выбрана")
|
||||
return
|
||||
|
||||
if not object_name:
|
||||
QMessageBox.critical(self, "Ошибка", "Цель не указана")
|
||||
return
|
||||
|
||||
# Проверка, существует ли объект в списке небесных тел
|
||||
celestial_bodies = self.config_service.get_celestial_bodies()
|
||||
if object_name not in celestial_bodies:
|
||||
reply = QMessageBox.question(self, "Новый объект",
|
||||
f"Объект '{object_name}' не найден в списке.\nДобавить его в список?",
|
||||
QMessageBox.Yes | QMessageBox.No)
|
||||
if reply == QMessageBox.Yes:
|
||||
self.config_service.add_celestial_body(object_name)
|
||||
self.object_combo.addItem(object_name)
|
||||
else:
|
||||
return
|
||||
|
||||
camera = self.camera_combo.currentText()
|
||||
lens = self.lens_combo.currentText()
|
||||
|
||||
if not camera or not lens:
|
||||
reply = QMessageBox.question(self, "Предупреждение",
|
||||
"Камера или объектив не выбраны. Продолжить?",
|
||||
QMessageBox.Yes | QMessageBox.No)
|
||||
if reply == QMessageBox.No:
|
||||
return
|
||||
|
||||
try:
|
||||
watch_path = Path(watch_folder)
|
||||
|
||||
# Очищаем папку наблюдения от старых файлов
|
||||
FileService.clear_watch_folder(watch_path)
|
||||
|
||||
camera_val = camera if camera else "Unknown"
|
||||
lens_val = lens if lens else "Unknown"
|
||||
|
||||
self.session_service.start_session(watch_path, object_name, camera_val, lens_val)
|
||||
|
||||
self.config_service.set_last_camera(camera_val)
|
||||
self.config_service.set_last_lens(lens_val)
|
||||
|
||||
# Запускаем отслеживание
|
||||
success = self.watch_service.start(watch_path, self._on_file_received)
|
||||
if not success:
|
||||
QMessageBox.critical(self, "Ошибка", "Не удалось запустить отслеживание папки")
|
||||
return
|
||||
|
||||
self._set_running_state(True)
|
||||
|
||||
print(f"Отслеживание начато! Папка наблюдения: {watch_path}")
|
||||
print(f"Папка сессии: {self.session_service.get_current_session().session_folder}")
|
||||
|
||||
except Exception as e:
|
||||
QMessageBox.critical(self, "Ошибка", f"Не удалось начать сессию: {e}")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
|
||||
def stop(self):
|
||||
if not self.running:
|
||||
return
|
||||
|
||||
try:
|
||||
watch_folder = Path(self.folder_entry.text())
|
||||
|
||||
print(f"Остановка сессии. Перемещаем файлы из {watch_folder}")
|
||||
|
||||
# Перемещаем все оставшиеся файлы
|
||||
moved_count = self.watch_service.move_all_existing_files(watch_folder, self._on_file_received)
|
||||
print(f"Перемещено файлов: {moved_count}")
|
||||
|
||||
# Останавливаем отслеживание
|
||||
self.watch_service.stop()
|
||||
|
||||
# Завершаем сессию
|
||||
session = self.session_service.finish_session()
|
||||
|
||||
self._set_running_state(False)
|
||||
|
||||
# Показываем диалог завершения
|
||||
self._show_session_end_dialog(session)
|
||||
|
||||
except Exception as e:
|
||||
QMessageBox.critical(self, "Ошибка", f"Ошибка при завершении сессии: {e}")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
|
||||
def set_new_object(self):
|
||||
if not self.running:
|
||||
QMessageBox.critical(self, "Ошибка", "Сессия не активна")
|
||||
return
|
||||
|
||||
# Перемещаем все накопленные файлы в папку текущего объекта
|
||||
watch_folder = Path(self.folder_entry.text())
|
||||
moved_count = self.watch_service.move_all_existing_files(watch_folder, self._on_file_received)
|
||||
|
||||
if moved_count > 0:
|
||||
print(f"Перемещено файлов перед сменой объекта: {moved_count}")
|
||||
|
||||
new_object, ok = QInputDialog.getText(self, "Новый объект", "Введите название объекта:")
|
||||
|
||||
if ok and new_object and new_object.strip():
|
||||
new_name = new_object.strip()
|
||||
|
||||
# Проверка, существует ли объект в списке
|
||||
celestial_bodies = self.config_service.get_celestial_bodies()
|
||||
if new_name not in celestial_bodies:
|
||||
reply = QMessageBox.question(self, "Новый объект",
|
||||
f"Объект '{new_name}' не найден в списке.\nДобавить его в список?",
|
||||
QMessageBox.Yes | QMessageBox.No)
|
||||
if reply == QMessageBox.Yes:
|
||||
self.config_service.add_celestial_body(new_name)
|
||||
self.object_combo.addItem(new_name)
|
||||
else:
|
||||
return
|
||||
|
||||
self.session_service.create_new_object(new_name)
|
||||
self.object_combo.setCurrentText(new_name)
|
||||
QMessageBox.information(self, "Успех", f"Объект изменён на: {new_name}")
|
||||
|
||||
def open_equipment_dialog(self):
|
||||
from ui.dialogs.equipment_dialog import EquipmentDialog
|
||||
dialog = EquipmentDialog(self, self.config_service)
|
||||
dialog.exec()
|
||||
|
||||
self.camera_combo.clear()
|
||||
self.lens_combo.clear()
|
||||
self.camera_combo.addItems(self.config_service.get_cameras())
|
||||
self.lens_combo.addItems(self.config_service.get_lenses())
|
||||
|
||||
def open_celestial_dialog(self):
|
||||
from ui.dialogs.celestial_dialog import CelestialDialog
|
||||
dialog = CelestialDialog(self, self.config_service)
|
||||
dialog.exec()
|
||||
|
||||
self.object_combo.clear()
|
||||
self.object_combo.addItems(self.config_service.get_celestial_bodies())
|
||||
|
||||
def open_session_folder(self):
|
||||
if self.running and self.session_service.get_current_session():
|
||||
folder = self.session_service.get_current_session().session_folder
|
||||
if folder and folder.exists():
|
||||
try:
|
||||
if platform.system() == "Windows":
|
||||
subprocess.Popen(['explorer', str(folder)])
|
||||
elif platform.system() == "Darwin":
|
||||
subprocess.Popen(['open', str(folder)])
|
||||
else:
|
||||
subprocess.Popen(['xdg-open', str(folder)])
|
||||
except Exception as e:
|
||||
QMessageBox.critical(self, "Ошибка", f"Не удалось открыть папку: {e}")
|
||||
else:
|
||||
QMessageBox.critical(self, "Ошибка", "Папка сессии не найдена")
|
||||
else:
|
||||
QMessageBox.information(self, "Информация", "Нет активной сессии")
|
||||
|
||||
def show_instructions(self):
|
||||
from ui.dialogs.instructions_dialog import InstructionsDialog
|
||||
dialog = InstructionsDialog(self)
|
||||
dialog.exec()
|
||||
|
||||
def show_info(self):
|
||||
QMessageBox.about(self, "О программе",
|
||||
"Astro Session Watcher\nВерсия: 0.3.0-alpha\n\n"
|
||||
"Приложение для автоматической сортировки астрофотографий\n\n"
|
||||
"Особенности:\n"
|
||||
"• Автоматическое отслеживание новых файлов\n"
|
||||
"• Сортировка по объектам съёмки\n"
|
||||
"• Ведение детальных логов\n"
|
||||
"• Сохранение истории оборудования\n\n"
|
||||
"Разработчик: Vic Sergeev\n2026")
|
||||
|
||||
def _show_session_end_dialog(self, session):
|
||||
current_object = session.get_current_object()
|
||||
object_name = current_object.name if current_object else "Unknown"
|
||||
photo_count = current_object.photo_count if current_object else 0
|
||||
session_folder = session.session_folder
|
||||
|
||||
msg_box = QMessageBox(self)
|
||||
msg_box.setWindowTitle("Сессия завершена")
|
||||
msg_box.setIcon(QMessageBox.Information)
|
||||
msg_box.setText(f"Наблюдение остановлено\n\nСессия для объекта '{object_name}' завершена.\nПолучено файлов: {photo_count}")
|
||||
msg_box.setInformativeText(f"Папка с данными:\n{session_folder}")
|
||||
|
||||
open_folder_btn = msg_box.addButton("📁 Открыть папку", QMessageBox.AcceptRole)
|
||||
close_btn = msg_box.addButton("Закрыть", QMessageBox.RejectRole)
|
||||
|
||||
msg_box.exec()
|
||||
if msg_box.clickedButton() == open_folder_btn:
|
||||
if session_folder and session_folder.exists():
|
||||
try:
|
||||
if platform.system() == "Windows":
|
||||
subprocess.Popen(['explorer', str(session_folder)])
|
||||
elif platform.system() == "Darwin":
|
||||
subprocess.Popen(['open', str(session_folder)])
|
||||
else:
|
||||
subprocess.Popen(['xdg-open', str(session_folder)])
|
||||
except Exception as e:
|
||||
QMessageBox.critical(self, "Ошибка", f"Не удалось открыть папку: {e}")
|
||||
|
||||
def closeEvent(self, event):
|
||||
if self.running:
|
||||
reply = QMessageBox.question(self, "Выход",
|
||||
"Сессия активна. Остановить сессию и выйти?",
|
||||
QMessageBox.Yes | QMessageBox.No)
|
||||
if reply == QMessageBox.Yes:
|
||||
try:
|
||||
self.stop()
|
||||
except:
|
||||
pass
|
||||
event.accept()
|
||||
else:
|
||||
event.ignore()
|
||||
else:
|
||||
event.accept()
|
||||
Loading…
Add table
Add a link
Reference in a new issue