#include "workspace/WorkSpaceXMLWrite.h" #include "workspace/WorkSpace.h" #include "entities/EntitiesManager.h" #include "entities/Entity.h" #include "workspace/Timestep.h" #include "workspace/LampStatus.h" #include "common/SpdLogger.h" #include "utils/StringUtils.h" #include "workspace/WorkSpaceManager.h" #include "workspace/FileEntry.h" #include WorkSpaceXMLWrite::WorkSpaceXMLWrite(WorkSpace* workspace, QObject* parent) noexcept : QObject(parent) , workSpace_(workspace) {} bool WorkSpaceXMLWrite::Save(const QString& path) { LOG_INFO("save path: {}", path.toLocal8Bit().constData()); if (nullptr == workSpace_) { LOG_WARN("worksapce is nullptr"); return false; } tinyxml2::XMLDocument doc; doc.LinkEndChild(doc.NewDeclaration("xml version=\"1.0\" encoding=\"UTF-8\"")); tinyxml2::XMLElement* scene = doc.NewElement("scene"); if (!SaveScene(scene)) { return false; } doc.LinkEndChild(scene); SaveTimeStep(scene); SaveChart(scene, &doc); SaveLamp(scene); SaveCommond(scene); SaveFiles(scene, &doc); tinyxml2::XMLElement* entitiesXml = scene->InsertNewChildElement("entities"); std::vector& entities = workSpace_->GetEntities(); for (auto entity : entities) { entity->UnSerialize(entitiesXml); } tinyxml2::XMLError xmlError = doc.SaveFile(path.toLocal8Bit().constData(), false); if (tinyxml2::XML_SUCCESS != xmlError) { LOG_WARN("worksapce is nullptr"); return false; } return true; } bool WorkSpaceXMLWrite::SaveScene(tinyxml2::XMLElement* scene) { const QString name = workSpace_->GetName(); scene->SetAttribute("name", name.toStdString().c_str()); scene->SetAttribute("describe", workSpace_->GetDescribe().toStdString().c_str()); scene->SetAttribute("uuid", workSpace_->GetUUid().toStdString().c_str()); scene->SetAttribute("viewpoint", StringUtils::ViewpointToString(workSpace_->GetHomeViewpoint()).c_str()); scene->SetAttribute("commondPath", ""); return true; } // Removed: SaveTimeStep — timestep is no longer file-based // 新增:保存 Timestep 的手动范围与步长倍率 bool WorkSpaceXMLWrite::SaveTimeStep(tinyxml2::XMLElement* scene) { if (nullptr == workSpace_) { return false; } auto* t = workSpace_->GetTimestep(); if (!t) { // 若尚未创建,确保存在一个默认实例,以保证文件的一致性 workSpace_->EnsureTimestep(); t = workSpace_->GetTimestep(); } if (!t) { return false; } double start = 0.0, end = 0.0, step = 1.0; t->GetRange(start, end, step); tinyxml2::XMLElement* timestep = scene->InsertNewChildElement("timestep"); timestep->SetAttribute("manual", t->HasManualRange() ? 1 : 0); timestep->SetAttribute("start", start); timestep->SetAttribute("end", end); timestep->SetAttribute("step", step); return true; } bool WorkSpaceXMLWrite::SaveLamp(tinyxml2::XMLElement* scene) { LampStatus *pLampStatus = workSpace_->GetLampStatus(); if (pLampStatus) { const QString lampPath = pLampStatus->GetPath(); if (!lampPath.isEmpty()) { tinyxml2::XMLElement* lamp = scene->InsertNewChildElement("lamp"); lamp->SetAttribute("path", lampPath.toStdString().c_str()); return true; } } return false; } bool WorkSpaceXMLWrite::SaveCommond(tinyxml2::XMLElement* scene) { const QString commondPath = workSpace_->GetCommondFilePath(); if (!commondPath.isEmpty()) { tinyxml2::XMLElement* commond = scene->InsertNewChildElement("commond"); // Extract just the filename from the full path for storage QFileInfo fileInfo(commondPath); commond->SetAttribute("path", fileInfo.fileName().toStdString().c_str()); } return true; } bool WorkSpaceXMLWrite::SaveEntities(tinyxml2::XMLElement* scene, tinyxml2::XMLDocument* doc) { tinyxml2::XMLElement* entitics = doc->NewElement("entities"); scene->LinkEndChild(entitics); return true; } bool WorkSpaceXMLWrite::SaveChart(tinyxml2::XMLElement* scene, tinyxml2::XMLDocument* doc) { // charts section retained for compatibility, but deprecated entries (Wave, Report, RD, SimMatlab) are no longer saved tinyxml2::XMLElement* charts = doc->NewElement("charts"); scene->LinkEndChild(charts); return true; } bool WorkSpaceXMLWrite::SaveFiles(tinyxml2::XMLElement* scene, tinyxml2::XMLDocument* doc) { // Persist multi-file entries per type as counts tinyxml2::XMLElement* files = doc->NewElement("files"); scene->LinkEndChild(files); for (const auto& kv : workSpace_->files_) { const FileEntryType type = kv.first; const auto& vec = kv.second; tinyxml2::XMLElement* typeElem = doc->NewElement("type"); typeElem->SetAttribute("name", FileEntryTypeToString(type)); typeElem->SetAttribute("count", static_cast(vec.size())); files->LinkEndChild(typeElem); // Call SaveFiles method for each FileEntry to save detailed data for (const auto& fileEntry : vec) { if (fileEntry) { fileEntry->SaveFiles(typeElem, doc); } } } return true; }