Загрузка данных
# -*- coding: utf-8 -*-
# project_manager.py
import datetime as dt
import os
import sqlite3
import time
from pathlib import Path
from tkinter import messagebox
from gui.models import Project
from modules.project_database import ProjectDatabase
class ProjectManager:
"""
Класс для управления проектами.
Автоматически загружает список проектов из файлов .db в папке 'project_dbs'.
"""
DB_DIRECTORY = "project_dbs"
DB_EXTENSION = ".db"
def __init__(self):
"""Инициализирует менеджер и загружает существующие проекты."""
self.projects = []
self.projects_dir = self._initialize_projects_directory()
if self.projects_dir:
self._load_existing_projects()
def _initialize_projects_directory(self):
projects_dir = os.path.join(os.getcwd(), self.DB_DIRECTORY)
try:
os.makedirs(projects_dir, exist_ok=True)
print(f"[INFO] Папка для проектов готова: {projects_dir}")
return projects_dir
except Exception as e:
print(f"[ERROR] Не удалось создать/проверить папку 'project_dbs': {e}")
return None
def _load_existing_projects(self):
"""Сканирует папку project_dbs и загружает метаданные проектов."""
# КРИТИЧЕСКИ ВАЖНО: Очищаем список ПЕРЕД циклом, чтобы избежать дублей
self.projects.clear()
if not self.projects_dir or not os.path.exists(self.projects_dir):
print("[INFO] Папка проектов не найдена или пуста.")
return
for filename in sorted(os.listdir(self.projects_dir)):
file_path = os.path.join(self.projects_dir, filename)
# Проверяем, что это именно файл базы данных проекта
if os.path.isfile(file_path) and filename.lower().endswith(self.DB_EXTENSION):
try:
project_code = os.path.splitext(filename)[0]
# Читаем имя прямо из файла БД
conn = sqlite3.connect(file_path)
cursor = conn.cursor()
# Проверяем наличие таблицы на случай битого файла
cursor.execute("SELECT name FROM sqlite_master WHERE type='table' AND name='project_data';")
if not cursor.fetchone():
print(f"[WARN] Файл {filename} пустой (нет таблиц). Пропускаем.")
continue
cursor.execute("SELECT name FROM project_data LIMIT 1")
row = cursor.fetchone()
# Если таблица есть, но данных нет — используем имя файла как название
human_name = row[0] if row and row[0] else project_code.replace("_", " ").title()
# Создаем объект модели Project
project = Project(name=human_name)
project.id = project_code
self.projects.append(project)
print(f"[LOAD] Проект '{human_name}' (Код: {project_code}) загружен.")
except Exception as e:
print(f"[ERROR] Не удалось прочитать {filename}: {e}")
finally:
if 'conn' in locals():
conn.close()
def list_projects(self):
return self.projects
def add_project(self, project_object):
"""
Режим "Вайб + Пауза": ждем пару секунд, чтобы ОС пришла в себя.
"""
try:
raw_id = str(project_object.id).strip().lower()
name = str(project_object.name).strip()
if not raw_id or not name:
return False
project_code = raw_id
db_path = Path(self.DB_DIRECTORY) / f"{project_code}.db"
# --- ШАГ 1: ГЛУБОКИЙ СБРОС СОЕДИНЕНИЙ ---
print("[CLEANUP] Сброс всех соединений...")
for proj in self.projects:
if hasattr(proj, 'connection') and proj.connection is not None:
try:
proj.connection.close()
proj.connection = None
except Exception:
pass
if hasattr(self, 'db_connection') and self.db_connection is not None:
try:
self.db_connection.close()
self.db_connection = None
except Exception:
pass
if hasattr(self, 'connection') and self.connection is not None:
try:
self.connection.close()
self.connection = None
except Exception:
pass
# --- ШАГ 2: ПАУЗА ДЛЯ WINDOWS ---
# Ждем 2 секунды. Антивирус за это время уйдет,
# а удаленные ранее файлы исчезнут из индекса проводника.
print("[WAIT] Делаем паузу для операционной системы (2 сек)...")
time.sleep(2)
# --- ШАГ 3: МЯГКАЯ ПРОВЕРКА СУЩЕСТВОВАНИЯ ---
# Теперь проверяем exists() только ПОСЛЕ паузы
if db_path.exists():
messagebox.showerror(
"Файл уже существует",
("Проект с таким кодом уже создан физически.\n\n"
"Если ты его не видишь в списке:\n"
"1. Проверь папку project_dbs на наличие дублей (например, rrr (1).db).\n"
"2. Убедись, что поле ID уникально."
)
)
return False
# --- ШАГ 4: ЧИСТОЕ СОЗДАНИЕ ---
print("[ACTION] Создаем базу данных...")
conn = sqlite3.connect(db_path)
cursor = conn.cursor()
cursor.execute(
"""
CREATE TABLE IF NOT EXISTS project_data (
id INTEGER PRIMARY KEY AUTOINCREMENT,
project_code TEXT UNIQUE NOT NULL,
created_at TEXT NOT NULL,
name TEXT NOT NULL,
description TEXT DEFAULT '',
date_opened TEXT DEFAULT '',
responsible TEXT DEFAULT ''
)
"""
)
current_time = dt.datetime.now().isoformat()
cursor.execute(
"""
INSERT INTO project_data (
project_code, created_at, name, description, date_opened, responsible
) VALUES (?, ?, ?, ?, ?, ?)
""",
(
project_code,
current_time,
name,
getattr(project_object, "description", ""),
getattr(project_object, "date_opened", ""),
getattr(project_object, "responsible", ""),
),
)
conn.commit()
conn.close()
print("[SUCCESS] База создана.")
except Exception as e:
print(f"[FATAL] Create failed: {e}")
import traceback
traceback.print_exc()
# Чистим мусор при любой ошибке
if db_path.exists():
try:
os.remove(db_path)
except OSError:
pass
messagebox.showerror("Ошибка", f"Не удалось записать данные:\n{e}")
return False
# --- ОБНОВЛЕНИЕ СПИСКА ---
self._load_existing_projects()
self.update_groups_tree()
return True