BayTemplate/include/document.h

240 lines
7.6 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#ifndef DOCUMENT_H
#define DOCUMENT_H
#include <QString>
#include <QDateTime>
#include <QMap>
#include <QVariant>
#include <QObject>
#include <QByteArray>
/**
* @brief BayTemplate 文档类
*
* Document 类作为持久化层,位于 Model 层之下,负责:
* 1. 序列化/反序列化:将 DesignerScene 中的图元层次结构保存到 JSON/XML从文件重建场景
* 2. 状态管理:文件名、保存状态(是否修改过)、版本信息、元数据
* 3. 与现有架构的集成:通过组合方式持有 DesignerScene 的引用,提供信号与 CMainWindow 通信
*
* 设计原则:
* - 组合优于继承Document 持有 DesignerScene 的弱引用,不继承 Scene
* - 单向依赖Document 只依赖 DesignerScene 的接口,不依赖 CMainWindow
* - 信号槽通信:通过信号与外部通信修改状态,避免紧耦合
*/
class DesignerScene;
class GraphicsBaseItem;
class GraphicsItemGroup;
class QGraphicsScene;
class QGraphicsItem;
class QJsonObject;
class Document : public QObject
{
Q_OBJECT
public:
explicit Document(QObject *parent = nullptr);
~Document();
// =================================================================
// 场景关联(组合关系)
// =================================================================
/**
* @brief 关联到 DesignerScene
* @param scene 场景对象Document 持有其弱引用
*
* 通过组合方式关联场景,而不是继承。这符合开闭原则,
* Document 可以独立于 Scene 存在,需要序列化时才使用 scene 引用。
*/
void setScene(DesignerScene* scene);
/**
* @brief 获取关联的场景
*/
DesignerScene* scene() const;
// =================================================================
// 文件操作
// =================================================================
/**
* @brief 保存文档到文件(覆盖当前文件)
* @param filename 文件路径,为空则使用当前 filename()
* @return 成功返回 true
*
* 保存流程:
* 1. 如果 filename 为空且 m_filename 不为空,使用 m_filename
* 2. 序列化场景内容到 JSON 格式
* 3. 写入文件
* 4. 更新 lastSavedTime调用 setModified(false)
* 5. 发出 saveStatusChanged 信号
*
* 注意:此方法不会更新 m_filename仅用于覆盖已有文件
*/
bool saveToFile(const QString& filename = QString());
/**
* @brief 另存为Save As
* @param filename 目标文件路径
* @return 成功返回 true
*
* 另存为流程:
* 1. 序列化场景内容到 JSON 格式
* 2. 写入文件
* 3. 更新 m_filename 为目标文件路径
* 4. 更新 lastSavedTime调用 setModified(false)
* 5. 发出 filenameChanged 和 modifiedChanged 信号
*
* 与 saveToFile() 的区别:
* - saveAsToFile() 总是会更新 m_filename
* - saveAsToFile() 适用于"另存为"操作,改变文档的默认保存路径
*/
bool saveAsToFile(const QString& filename);
/**
* @brief 从文件加载文档
* @param filename 文件路径
* @return 成功返回 true
*
* 反序列化流程:
* 1. 读取 JSON 文件
* 2. 清空当前 scene 的内容
* 3. 递归重建图元层次结构
* 4. 更新 m_filename 和 m_modified
*/
bool loadFromFile(const QString& filename);
// =================================================================
// 序列化接口(二进制格式)
// =================================================================
/**
* @brief 序列化为 QByteArray
* @return JSON 格式的字节数组
*/
QByteArray serialize() const;
/**
* @brief 从 QByteArray 反序列化
* @param data JSON 格式的字节数组
* @return 成功返回 true
*/
bool deserialize(const QByteArray& data);
// =================================================================
// 状态管理
// =================================================================
/**
* @brief 文档文件名(可能为空,表示未保存的新文档)
*/
QString filename() const { return m_filename; }
void setFilename(const QString& filename) { m_filename = filename; }
/**
* @brief 文档是否被修改过(需要保存)
*/
bool isModified() const { return m_modified; }
void setModified(bool modified) {
if (m_modified != modified) {
m_modified = modified;
emit modifiedChanged(m_modified);
}
}
/**
* @brief 文档版本(文件格式版本,用于向前/向后兼容)
*/
QString version() const { return m_version; }
/**
* @brief 创建时间
*/
QDateTime created() const { return m_created; }
/**
* @brief 最后修改时间
*/
QDateTime modifiedTime() const { return m_modifiedTime; }
/**
* @brief 最后保存时间
*/
QDateTime lastSavedTime() const { return m_lastSavedTime; }
// =================================================================
// 元数据(可扩展)
// =================================================================
/**
* @brief 设置自定义元数据
* @param key 键名
* @param value 值
*/
void setMetaData(const QString& key, const QVariant& value);
/**
* @brief 获取自定义元数据
*/
QVariant metaData(const QString& key) const;
signals:
/**
* @brief 修改状态改变时发出
* @param modified 新的修改状态
*
* CMainWindow 可连接此信号来更新窗口标题(添加 * 标记)
*/
void modifiedChanged(bool modified);
/**
* @brief 文件名改变时发出(新建、另存为等操作)
* @param filename 新的文件名
*
* CMainWindow 可连接此信号来更新窗口标题
*/
void filenameChanged(const QString& filename);
/**
* @brief 保存/加载操作完成时发出
* @param success 操作是否成功
* @param message 成功或失败的消息
*/
void saveStatusChanged(bool success, const QString& message);
private:
// 内部实现
bool saveInternal(const QString& filename);
bool loadInternal(const QString& filename);
// 图元序列化/反序列化
QJsonObject serializeItem(GraphicsBaseItem* item) const;
void deserializeItem(const QJsonObject& obj, QGraphicsScene* scene, QGraphicsItem* parent);
QString getTypeString(GraphicsBaseItem* item) const;
QJsonObject serializeItemProperties(GraphicsBaseItem* item) const;
// QVariant <-> QJsonValue 转换
QJsonValue toJsonValue(const QVariant& value) const;
QVariant fromJsonValue(const QJsonValue& value) const;
GraphicsBaseItem* deserializeRectItem(const QJsonObject& obj);
GraphicsBaseItem* deserializeBusSectionItem(const QJsonObject& obj);
GraphicsBaseItem* deserializePolygonItem(const QJsonObject& obj);
GraphicsItemGroup* deserializeItemGroup(const QJsonObject& obj, QGraphicsScene* scene, QGraphicsItem* parent);
QString m_filename; // 文档文件名
bool m_modified; // 是否被修改
QString m_version; // 文件格式版本
QDateTime m_created; // 创建时间
QDateTime m_modifiedTime; // 最后修改时间
QDateTime m_lastSavedTime; // 最后保存时间
QMap<QString, QVariant> m_metaData; // 自定义元数据
DesignerScene* m_pScene; // 关联的场景(组合关系,非拥有所有权)
};
#endif // DOCUMENT_H