diff --git a/src/Dyt.qrc b/src/Dyt.qrc
index bea57361..eec9bbef 100644
--- a/src/Dyt.qrc
+++ b/src/Dyt.qrc
@@ -30,7 +30,12 @@
res/default/menu_uisetting.png
res/default/menu_window_manager.png
res/default/menu_window_setting.png
- res/default/Command.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