diff --git a/src/Dyt.qrc b/src/Dyt.qrc index eaa97f2e..3007ee41 100644 --- a/src/Dyt.qrc +++ b/src/Dyt.qrc @@ -32,6 +32,12 @@ res/default/menu_window_setting.png res/default/Command.png res/default/polar.png + res/models/aircraft_carrier.png + res/models/chaff_interference.png + res/models/missile.png + res/models/radar_jamming_station.png + res/models/satellite.png + res/models/warships.png diff --git a/src/res/models/aircraft_carrier.png b/src/res/models/aircraft_carrier.png new file mode 100644 index 00000000..78d1dab2 Binary files /dev/null and b/src/res/models/aircraft_carrier.png differ diff --git a/src/res/models/chaff_interference.png b/src/res/models/chaff_interference.png new file mode 100644 index 00000000..b574b591 Binary files /dev/null and b/src/res/models/chaff_interference.png differ diff --git a/src/res/models/missile.png b/src/res/models/missile.png new file mode 100644 index 00000000..933e3d5b Binary files /dev/null and b/src/res/models/missile.png differ diff --git a/src/res/models/radar_jamming_station.png b/src/res/models/radar_jamming_station.png new file mode 100644 index 00000000..629ba0e1 Binary files /dev/null and b/src/res/models/radar_jamming_station.png differ diff --git a/src/res/models/satellite.png b/src/res/models/satellite.png new file mode 100644 index 00000000..166301c4 Binary files /dev/null and b/src/res/models/satellite.png differ diff --git a/src/res/models/warships.png b/src/res/models/warships.png new file mode 100644 index 00000000..4b42a488 Binary files /dev/null and b/src/res/models/warships.png differ diff --git a/src/translations/Dyt_zh_CN.ts b/src/translations/Dyt_zh_CN.ts index c6837218..eae835fa 100644 --- a/src/translations/Dyt_zh_CN.ts +++ b/src/translations/Dyt_zh_CN.ts @@ -601,57 +601,57 @@ - + 参数名称 - + 描述 - + 数据类型 - + 最大值 - + 最小值 - + 小数点有效位 - + 初始值 - + 数据输入示例 - + 添加 - + 删除 - + 应用 @@ -1599,12 +1599,12 @@ - + attribte - + Main View @@ -1701,7 +1701,7 @@ - + @@ -1709,32 +1709,32 @@ - + stop - + 000.000 - + 00000 - + x1 - + up - + down @@ -1777,22 +1777,32 @@ PresetModelPanel - + + Preset Models + + + + + PresetModelToolBox + + + + Ships - + Satellites - + Missiles - + Jammers @@ -2763,22 +2773,22 @@ SimuRunMenu - + no workspace - + no commands - + Commands - + unnamed diff --git a/src/ui/MainWindow.cpp b/src/ui/MainWindow.cpp index 8dd31391..f5cbf96c 100644 --- a/src/ui/MainWindow.cpp +++ b/src/ui/MainWindow.cpp @@ -5,7 +5,7 @@ #include "PropertyBrowser.h" #include "ModelBrowser.h" -#include "PresetModelPanel.h" +#include "ModelBrowser/PresetModelPanel.h" #include "DockWidget.h" #include "viewer/QtOsgViewWidget.h" diff --git a/src/ui/ModelBrowser/PresetModelConfigParser.cpp b/src/ui/ModelBrowser/PresetModelConfigParser.cpp new file mode 100644 index 00000000..2b02c3c0 --- /dev/null +++ b/src/ui/ModelBrowser/PresetModelConfigParser.cpp @@ -0,0 +1,191 @@ +#include "PresetModelConfigParser.h" +#include "../../xml/tinyxml2.h" +#include "../../common/SpdLogger.h" +#include +#include + +PresetModelConfigParser::PresetModelConfigParser() +{ +} + +PresetModelConfigParser::~PresetModelConfigParser() +{ +} + +bool PresetModelConfigParser::LoadAllConfigs(const QString& configDir) +{ + Clear(); + + QDir dir(configDir); + if (!dir.exists()) { + SetError(QString("Config directory does not exist: %1").arg(configDir)); + LOG_WARN("Preset config directory does not exist: {}", configDir.toStdString()); + return false; + } + + // Get all XML files + QStringList filters; + filters << "*.xml"; + QFileInfoList fileList = dir.entryInfoList(filters, QDir::Files); + + if (fileList.isEmpty()) { + SetError(QString("No XML files found in config directory: %1").arg(configDir)); + LOG_WARN("No XML files found in preset config directory: {}", configDir.toStdString()); + return false; + } + + bool hasSuccess = false; + for (const QFileInfo& fileInfo : fileList) { + if (LoadConfig(fileInfo.absoluteFilePath())) { + hasSuccess = true; + LOG_INFO("Successfully loaded preset config: {}", fileInfo.fileName().toStdString()); + } else { + LOG_WARN("Failed to load preset config: {}", fileInfo.fileName().toStdString()); + } + } + + return hasSuccess; +} + +bool PresetModelConfigParser::LoadConfig(const QString& filePath) +{ + if (!QFileInfo::exists(filePath)) { + SetError(QString("Config file does not exist: %1").arg(filePath)); + return false; + } + + return ParseXmlFile(filePath); +} + +bool PresetModelConfigParser::ParseXmlFile(const QString& filePath) +{ + tinyxml2::XMLDocument doc; + tinyxml2::XMLError error = doc.LoadFile(filePath.toLocal8Bit().constData()); + + if (error != tinyxml2::XML_SUCCESS) { + SetError(QString("Failed to parse XML file: %1, error code: %2").arg(filePath).arg(static_cast(error))); + return false; + } + + const tinyxml2::XMLElement* root = doc.RootElement(); + if (!root) { + SetError(QString("XML file has no root element: %1").arg(filePath)); + return false; + } + + if (strcmp(root->Name(), "modelCategory") != 0) { + SetError(QString("XML file root element is not modelCategory: %1").arg(filePath)); + return false; + } + + ModelCategory category; + + const char* name = root->Attribute("name"); + const char* displayName = root->Attribute("displayName"); + const char* icon = root->Attribute("icon"); + + if (!name) { + SetError(QString("modelCategory missing name attribute: %1").arg(filePath)); + return false; + } + + category.name = QString::fromUtf8(name); + category.displayName = displayName ? QString::fromUtf8(displayName) : category.name; + category.icon = icon ? QString::fromUtf8(icon) : ""; + + // Read model list + const tinyxml2::XMLElement* modelElement = root->FirstChildElement("model"); + while (modelElement) { + ModelInfo model; + + const char* modelName = modelElement->Attribute("name"); + const char* modelDisplayName = modelElement->Attribute("displayName"); + const char* description = modelElement->Attribute("description"); + const char* meshFile = modelElement->Attribute("meshFile"); + const char* enabled = modelElement->Attribute("enabled"); + + if (!modelName) { + LOG_WARN("Model element missing name attribute in file: {}", filePath.toStdString()); + modelElement = modelElement->NextSiblingElement("model"); + continue; + } + + model.name = QString::fromUtf8(modelName); + model.displayName = modelDisplayName ? QString::fromUtf8(modelDisplayName) : model.name; + model.description = description ? QString::fromUtf8(description) : ""; + model.meshFile = meshFile ? QString::fromUtf8(meshFile) : ""; + model.enabled = enabled ? (strcmp(enabled, "true") == 0) : true; + + category.models.append(model); + + modelElement = modelElement->NextSiblingElement("model"); + } + + // Store category data + m_categories[category.name] = category; + + return true; +} + +QStringList PresetModelConfigParser::GetModelNames(const QString& categoryName) const +{ + QStringList names; + + if (m_categories.contains(categoryName)) { + const ModelCategory& category = m_categories[categoryName]; + for (const ModelInfo& model : category.models) { + if (model.enabled) { + names.append(model.name); + } + } + } + + return names; +} + +QStringList PresetModelConfigParser::GetCategoryNames() const +{ + return m_categories.keys(); +} + +ModelCategory PresetModelConfigParser::GetCategory(const QString& categoryName) const +{ + if (m_categories.contains(categoryName)) { + return m_categories[categoryName]; + } + return ModelCategory(); +} + +ModelInfo PresetModelConfigParser::GetModelInfo(const QString& categoryName, const QString& modelName) const +{ + if (m_categories.contains(categoryName)) { + const ModelCategory& category = m_categories[categoryName]; + for (const ModelInfo& model : category.models) { + if (model.name == modelName) { + return model; + } + } + } + return ModelInfo(); +} + +bool PresetModelConfigParser::HasData() const +{ + return !m_categories.isEmpty(); +} + +void PresetModelConfigParser::Clear() +{ + m_categories.clear(); + m_lastError.clear(); +} + +QString PresetModelConfigParser::GetLastError() const +{ + return m_lastError; +} + +void PresetModelConfigParser::SetError(const QString& error) +{ + m_lastError = error; +} \ No newline at end of file diff --git a/src/ui/ModelBrowser/PresetModelConfigParser.h b/src/ui/ModelBrowser/PresetModelConfigParser.h new file mode 100644 index 00000000..ffa556c2 --- /dev/null +++ b/src/ui/ModelBrowser/PresetModelConfigParser.h @@ -0,0 +1,67 @@ +#pragma once + +#include +#include +#include +#include + +struct ModelInfo { + QString name; + QString displayName; + QString description; + QString meshFile; + bool enabled; + + ModelInfo() : enabled(true) {} +}; + +struct ModelCategory { + QString name; + QString displayName; + QString icon; + QVector models; +}; + +class PresetModelConfigParser +{ +public: + PresetModelConfigParser(); + ~PresetModelConfigParser(); + + // Load all preset model configurations + bool LoadAllConfigs(const QString& configDir = "workspace/presets"); + + // Load single configuration file + bool LoadConfig(const QString& filePath); + + // Get model names for specified category + QStringList GetModelNames(const QString& categoryName) const; + + // Get all category names + QStringList GetCategoryNames() const; + + // Get category information + ModelCategory GetCategory(const QString& categoryName) const; + + // Get model information + ModelInfo GetModelInfo(const QString& categoryName, const QString& modelName) const; + + // Check if configuration data exists + bool HasData() const; + + // Clear all data + void Clear(); + + // Get last error message + QString GetLastError() const; + +private: + QMap m_categories; + QString m_lastError; + + // Parse single XML file + bool ParseXmlFile(const QString& filePath); + + // Set error message + void SetError(const QString& error); +}; \ No newline at end of file diff --git a/src/ui/PresetModelPanel.cpp b/src/ui/ModelBrowser/PresetModelPanel.cpp similarity index 59% rename from src/ui/PresetModelPanel.cpp rename to src/ui/ModelBrowser/PresetModelPanel.cpp index 04f415cc..01d8d18a 100644 --- a/src/ui/PresetModelPanel.cpp +++ b/src/ui/ModelBrowser/PresetModelPanel.cpp @@ -1,6 +1,4 @@ -#include "PresetModelPanel.h" -#include "DockTitleBar.h" -#include "DockWidget.h" +#include "ui/ModelBrowser/PresetModelPanel.h" #include #include @@ -15,20 +13,24 @@ #include #include +#include "common/SpdLogger.h" +#include "ui/DockTitleBar.h" +#include "ui/DockWidget.h" + +#include "ui_PresetModelPanel.h" + + PresetModelPanel::PresetModelPanel(QWidget *parent) : QWidget(parent) - , toolBox_(nullptr) - , mainLayout_(nullptr) - , shipList_(nullptr) - , satelliteList_(nullptr) - , missileList_(nullptr) - , jammerList_(nullptr) + , ui(new Ui::PresetModelPanel) { + ui->setupUi(this); InitUI(); } PresetModelPanel::~PresetModelPanel() { + delete ui; } void PresetModelPanel::AttachDock(DockWidget* dockWidget) @@ -47,101 +49,87 @@ void PresetModelPanel::AttachDock(DockWidget* dockWidget) void PresetModelPanel::InitUI() { - mainLayout_ = new QVBoxLayout(this); - mainLayout_->setContentsMargins(0, 0, 0, 0); - mainLayout_->setSpacing(5); - - toolBox_ = new QToolBox(this); - toolBox_->setObjectName("PresetModelToolBox"); - - toolBox_->addItem(CreateShipPage(), QIcon(), tr("Ships")); - toolBox_->addItem(CreateSatellitePage(), QIcon(), tr("Satellites")); - toolBox_->addItem(CreateMissilePage(), QIcon(), tr("Missiles")); - toolBox_->addItem(CreateJammerPage(), QIcon(), tr("Jammers")); - - mainLayout_->addWidget(toolBox_); - - setLayout(mainLayout_); + // Try to load model data from configuration files + if (m_configParser.LoadAllConfigs("workspace/presets")) { + // Successfully loaded from configuration files + LoadModelsFromConfig(); + } else { + // Failed to load configuration files, use hardcoded defaults as fallback + LOG_WARN("Failed to load preset models from config files, using hardcoded defaults. Error: {}", + m_configParser.GetLastError().toStdString()); + LoadDefaultModels(); + } } -QWidget* PresetModelPanel::CreateShipPage() +void PresetModelPanel::LoadModelsFromConfig() { - QWidget* page = new QWidget; - QVBoxLayout* layout = new QVBoxLayout(page); + // Load ship models + QStringList shipModels = m_configParser.GetModelNames("Ship"); + if (!shipModels.isEmpty()) { + PopulateModelList(ui->shipList, "Ship", shipModels); + } + // Load satellite models + QStringList satelliteModels = m_configParser.GetModelNames("Satellite"); + if (!satelliteModels.isEmpty()) { + PopulateModelList(ui->satelliteList, "Satellite", satelliteModels); + } + + // Load missile models + QStringList missileModels = m_configParser.GetModelNames("Missile"); + if (!missileModels.isEmpty()) { + PopulateModelList(ui->missileList, "Missile", missileModels); + } + + // Load jammer models + QStringList jammerModels = m_configParser.GetModelNames("Jammer"); + if (!jammerModels.isEmpty()) { + PopulateModelList(ui->jammerList, "Jammer", jammerModels); + } +} + +void PresetModelPanel::LoadDefaultModels() +{ + // Use hardcoded default models as fallback mechanism QStringList shipModels = { - tr("Destroyer"), - tr("Aircraft Carrier"), - tr("Frigate"), - tr("Submarine") + "Destroyer", + "Aircraft Carrier", + "Frigate", + "Submarine" }; - - shipList_ = CreateModelList(page, "Ship", shipModels); - layout->addWidget(shipList_); - - return page; -} - -QWidget* PresetModelPanel::CreateSatellitePage() -{ - QWidget* page = new QWidget; - QVBoxLayout* layout = new QVBoxLayout(page); + PopulateModelList(ui->shipList, "Ship", shipModels); QStringList satelliteModels = { - tr("Geostationary Satellite"), - tr("Communication Satellite"), - tr("Weather Satellite"), - tr("Navigation Satellite") + "Communication Satellite", + "Weather Satellite", + "GPS Satellite", + "Spy Satellite" }; - - satelliteList_ = CreateModelList(page, "Satellite", satelliteModels); - layout->addWidget(satelliteList_); - - return page; -} - -QWidget* PresetModelPanel::CreateMissilePage() -{ - QWidget* page = new QWidget; - QVBoxLayout* layout = new QVBoxLayout(page); + PopulateModelList(ui->satelliteList, "Satellite", satelliteModels); QStringList missileModels = { - tr("Hypersonic Missile"), - tr("Cruise Missile"), - tr("Ballistic Missile"), - tr("Anti-Ship Missile") + "Cruise Missile", + "Ballistic Missile", + "Anti-Ship Missile", + "Surface-to-Air Missile" }; - - missileList_ = CreateModelList(page, "Missile", missileModels); - layout->addWidget(missileList_); - - return page; -} - -QWidget* PresetModelPanel::CreateJammerPage() -{ - QWidget* page = new QWidget; - QVBoxLayout* layout = new QVBoxLayout(page); + PopulateModelList(ui->missileList, "Missile", missileModels); QStringList jammerModels = { - tr("Passive Jammer"), - tr("Active Jammer"), - tr("Electronic Warfare Pod"), - tr("Decoy System") + "Electronic Jammer", + "Communication Jammer", + "Radar Jammer", + "GPS Jammer" }; - - jammerList_ = CreateModelList(page, "Jammer", jammerModels); - layout->addWidget(jammerList_); - - return page; + PopulateModelList(ui->jammerList, "Jammer", jammerModels); } -QListWidget* PresetModelPanel::CreateModelList(QWidget* parent, const QString& modelType, const QStringList& models) +void PresetModelPanel::PopulateModelList(QListWidget* listWidget, const QString& modelType, const QStringList& models) { - DraggableListWidget* listWidget = new DraggableListWidget(modelType, parent); + if (!listWidget) return; - listWidget->setDragDropMode(QAbstractItemView::DragOnly); - listWidget->setDefaultDropAction(Qt::CopyAction); + // Set the model type as a property for later use + listWidget->setProperty("modelType", modelType); for (const QString& model : models) { QListWidgetItem* item = new QListWidgetItem(model); @@ -161,8 +149,6 @@ QListWidget* PresetModelPanel::CreateModelList(QWidget* parent, const QString& m } connect(listWidget, &QListWidget::itemDoubleClicked, this, &PresetModelPanel::OnModelItemDoubleClicked); - - return listWidget; } void PresetModelPanel::SetupDragAndDrop(QListWidget* listWidget) diff --git a/src/ui/PresetModelPanel.h b/src/ui/ModelBrowser/PresetModelPanel.h similarity index 71% rename from src/ui/PresetModelPanel.h rename to src/ui/ModelBrowser/PresetModelPanel.h index 9e9c25ed..d73543c3 100644 --- a/src/ui/PresetModelPanel.h +++ b/src/ui/ModelBrowser/PresetModelPanel.h @@ -10,6 +10,11 @@ #include #include #include +#include "PresetModelConfigParser.h" + +QT_BEGIN_NAMESPACE +namespace Ui { class PresetModelPanel; } +QT_END_NAMESPACE class DockWidget; @@ -58,52 +63,32 @@ private: void InitUI(); /** - * @brief Create ship category page - * @return Ship page widget - */ - QWidget* CreateShipPage(); - - /** - * @brief Create satellite category page - * @return Satellite page widget - */ - QWidget* CreateSatellitePage(); - - /** - * @brief Create missile category page - * @return Missile page widget - */ - QWidget* CreateMissilePage(); - - /** - * @brief Create jammer category page - * @return Jammer page widget - */ - QWidget* CreateJammerPage(); - - /** - * @brief Create model list items - * @param parent Parent widget + * @brief Populate model list with items + * @param listWidget List widget to populate * @param modelType Model type * @param models Model name list - * @return Configured QListWidget */ - QListWidget* CreateModelList(QWidget* parent, const QString& modelType, const QStringList& models); + void PopulateModelList(QListWidget* listWidget, const QString& modelType, const QStringList& models); /** * @brief Setup drag and drop functionality * @param listWidget List widget to setup drag and drop */ void SetupDragAndDrop(QListWidget* listWidget); + + /** + * @brief Load models from configuration file + */ + void LoadModelsFromConfig(); + + /** + * @brief Load default models when config is unavailable + */ + void LoadDefaultModels(); private: - QToolBox* toolBox_; - QVBoxLayout* mainLayout_; - - QListWidget* shipList_; - QListWidget* satelliteList_; - QListWidget* missileList_; - QListWidget* jammerList_; + Ui::PresetModelPanel *ui; + PresetModelConfigParser m_configParser; }; /** diff --git a/src/ui/ModelBrowser/PresetModelPanel.ui b/src/ui/ModelBrowser/PresetModelPanel.ui new file mode 100644 index 00000000..8df142c3 --- /dev/null +++ b/src/ui/ModelBrowser/PresetModelPanel.ui @@ -0,0 +1,146 @@ + + + PresetModelPanel + + + + 0 + 0 + 300 + 600 + + + + Preset Models + + + + 5 + + + 5 + + + 5 + + + 5 + + + 5 + + + + + PresetModelToolBox + + + 0 + + + + + 0 + 0 + 290 + 540 + + + + Ships + + + + + + QAbstractItemView::DragOnly + + + Qt::CopyAction + + + + + + + + + 0 + 0 + 290 + 540 + + + + Satellites + + + + + + QAbstractItemView::DragOnly + + + Qt::CopyAction + + + + + + + + + 0 + 0 + 290 + 540 + + + + Missiles + + + + + + QAbstractItemView::DragOnly + + + Qt::CopyAction + + + + + + + + + 0 + 0 + 290 + 540 + + + + Jammers + + + + + + QAbstractItemView::DragOnly + + + Qt::CopyAction + + + + + + + + + + + + \ No newline at end of file diff --git a/workspace/presets/jammers.xml b/workspace/presets/jammers.xml new file mode 100644 index 00000000..cd936285 --- /dev/null +++ b/workspace/presets/jammers.xml @@ -0,0 +1,23 @@ + + + + + + + + \ No newline at end of file diff --git a/workspace/presets/missiles.xml b/workspace/presets/missiles.xml new file mode 100644 index 00000000..d38d5838 --- /dev/null +++ b/workspace/presets/missiles.xml @@ -0,0 +1,23 @@ + + + + + + + + \ No newline at end of file diff --git a/workspace/presets/satellites.xml b/workspace/presets/satellites.xml new file mode 100644 index 00000000..07f48118 --- /dev/null +++ b/workspace/presets/satellites.xml @@ -0,0 +1,23 @@ + + + + + + + + \ No newline at end of file diff --git a/workspace/presets/ships.xml b/workspace/presets/ships.xml new file mode 100644 index 00000000..98af9f07 --- /dev/null +++ b/workspace/presets/ships.xml @@ -0,0 +1,23 @@ + + + + + + + + \ No newline at end of file