Фазы 2-3: мульти-окна (WindowController, per-window FileStore), файловое дерево (FileStore+FileTreePanel, иконки/раскрытие/ПКМ/+drag&drop/подтверждения), NameDialog/ConfirmDialog; тест filestore (13/13)

This commit is contained in:
Flora (opencode)
2026-08-17 01:02:05 +03:00
parent ed633ae036
commit c740c9a756
12 changed files with 1305 additions and 76 deletions
+88
View File
@@ -0,0 +1,88 @@
#include "app/WindowController.h"
#include <QDir>
#include <QQmlComponent>
#include <QQmlContext>
#include "core/FileStore.h"
WindowController::WindowController(QQmlApplicationEngine *engine,
const QString &mainWindowUrl,
QObject *parent)
: QObject(parent)
, m_engine(engine)
, m_mainWindowUrl(mainWindowUrl)
{
}
int WindowController::windowCount() const
{
return m_windows.size();
}
QStringList WindowController::openVaults() const
{
QStringList list;
for (const Window &w : m_windows)
if (!w.vault.isEmpty())
list.append(w.vault);
return list;
}
int WindowController::indexOfVault(const QString &vaultPath) const
{
for (int i = 0; i < m_windows.size(); ++i)
if (m_windows[i].vault == vaultPath)
return i;
return -1;
}
QObject *WindowController::openWindow(const QString &vaultPath)
{
if (!m_engine)
return nullptr;
if (!m_component) {
m_component = new QQmlComponent(m_engine, QUrl(m_mainWindowUrl), this);
if (m_component->isError()) {
qWarning("WindowController: %s", qPrintable(m_component->errorString()));
return nullptr;
}
}
QQmlContext *ctx = new QQmlContext(m_engine->rootContext(), this);
FileStore *store = new FileStore(ctx);
ctx->setContextProperty("fileStore", store);
QObject *obj = m_component->create(ctx);
if (!obj) {
qWarning("WindowController: create failed: %s",
qPrintable(m_component->errorString()));
return nullptr;
}
m_windows.append({vaultPath, obj, store});
connect(obj, &QObject::destroyed, this, [this, obj]() {
for (int i = 0; i < m_windows.size(); ++i) {
if (m_windows[i].object == obj) {
const QString vault = m_windows[i].vault;
m_windows.removeAt(i);
emit windowsChanged();
if (!vault.isEmpty())
emit windowClosed(vault);
break;
}
}
});
obj->setProperty("windowVault", vaultPath);
// Закрытие окна уничтожает QML-объект (чтобы последнее окно завершало приложение).
obj->setProperty("destroyOnWindowClose", true);
if (!vaultPath.isEmpty() && QDir(vaultPath).exists())
store->openVault(vaultPath);
emit windowsChanged();
if (!vaultPath.isEmpty())
emit windowOpened(vaultPath);
return obj;
}
+46
View File
@@ -0,0 +1,46 @@
#pragma once
#include <QObject>
#include <QQmlApplicationEngine>
#include <QPointer>
#include <QList>
class FileStore;
// Создание окон приложения (мульти-хранилища: новое хранилище — новое окно).
class WindowController : public QObject
{
Q_OBJECT
Q_PROPERTY(int windowCount READ windowCount NOTIFY windowsChanged)
Q_PROPERTY(QStringList openVaults READ openVaults NOTIFY windowsChanged)
public:
WindowController(QQmlApplicationEngine *engine, const QString &mainWindowUrl,
QObject *parent = nullptr);
int windowCount() const;
QStringList openVaults() const;
// Открывает окно с заданным хранилищем. Возвращает nullptr при ошибке.
Q_INVOKABLE QObject *openWindow(const QString &vaultPath);
Q_INVOKABLE int indexOfVault(const QString &vaultPath) const;
signals:
void windowsChanged();
void windowOpened(const QString &vaultPath);
void windowClosed(const QString &vaultPath);
private:
struct Window {
QString vault;
QPointer<QObject> object;
FileStore *fileStore = nullptr;
};
QQmlApplicationEngine *m_engine;
QString m_mainWindowUrl;
QList<Window> m_windows;
QQmlComponent *m_component = nullptr;
};