add panel

This commit is contained in:
brige 2025-10-16 11:29:25 +08:00
parent 5c41cf02cd
commit 962d72bde9
12 changed files with 887 additions and 27 deletions

View File

@ -592,132 +592,132 @@
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../ui/MainWindow.cpp" line="58"/> <location filename="../ui/MainWindow.cpp" line="61"/>
<source>model elements</source> <source>model elements</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../ui/MainWindow.cpp" line="66"/> <location filename="../ui/MainWindow.cpp" line="69"/>
<source>attribte</source> <source>attribte</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../ui/MainWindow.cpp" line="82"/> <location filename="../ui/MainWindow.cpp" line="85"/>
<source>Main View</source> <source>Main View</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../ui/MainWindow.cpp" line="116"/> <location filename="../ui/MainWindow.cpp" line="119"/>
<source>Wave Curve</source> <source>Wave Curve</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../ui/MainWindow.cpp" line="125"/> <location filename="../ui/MainWindow.cpp" line="128"/>
<source>Speed Curve</source> <source>Speed Curve</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../ui/MainWindow.cpp" line="138"/> <location filename="../ui/MainWindow.cpp" line="141"/>
<source>3D Curve</source> <source>3D Curve</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../ui/MainWindow.cpp" line="154"/> <location filename="../ui/MainWindow.cpp" line="157"/>
<source>Target number</source> <source>Target number</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../ui/MainWindow.cpp" line="154"/> <location filename="../ui/MainWindow.cpp" line="157"/>
<source>Signal-to-noise ratio</source> <source>Signal-to-noise ratio</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../ui/MainWindow.cpp" line="155"/> <location filename="../ui/MainWindow.cpp" line="158"/>
<source>Azimuth line of sight</source> <source>Azimuth line of sight</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../ui/MainWindow.cpp" line="155"/> <location filename="../ui/MainWindow.cpp" line="158"/>
<source>Pitch gaze angle</source> <source>Pitch gaze angle</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../ui/MainWindow.cpp" line="156"/> <location filename="../ui/MainWindow.cpp" line="159"/>
<source>azimuth</source> <source>azimuth</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../ui/MainWindow.cpp" line="156"/> <location filename="../ui/MainWindow.cpp" line="159"/>
<source>Pitch angle</source> <source>Pitch angle</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../ui/MainWindow.cpp" line="157"/> <location filename="../ui/MainWindow.cpp" line="160"/>
<source>attribute</source> <source>attribute</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../ui/MainWindow.cpp" line="157"/> <location filename="../ui/MainWindow.cpp" line="160"/>
<source>Doppler</source> <source>Doppler</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../ui/MainWindow.cpp" line="158"/> <location filename="../ui/MainWindow.cpp" line="161"/>
<source>course</source> <source>course</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../ui/MainWindow.cpp" line="158"/> <location filename="../ui/MainWindow.cpp" line="161"/>
<source>Speed</source> <source>Speed</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../ui/MainWindow.cpp" line="159"/> <location filename="../ui/MainWindow.cpp" line="162"/>
<source>longitude</source> <source>longitude</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../ui/MainWindow.cpp" line="159"/> <location filename="../ui/MainWindow.cpp" line="162"/>
<source>latitude</source> <source>latitude</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../ui/MainWindow.cpp" line="160"/> <location filename="../ui/MainWindow.cpp" line="163"/>
<source>distance</source> <source>distance</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../ui/MainWindow.cpp" line="160"/> <location filename="../ui/MainWindow.cpp" line="163"/>
<source>velocity</source> <source>velocity</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../ui/MainWindow.cpp" line="161"/> <location filename="../ui/MainWindow.cpp" line="164"/>
<source>Radial dimensions</source> <source>Radial dimensions</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../ui/MainWindow.cpp" line="161"/> <location filename="../ui/MainWindow.cpp" line="164"/>
<source>Target RCS</source> <source>Target RCS</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../ui/MainWindow.cpp" line="167"/> <location filename="../ui/MainWindow.cpp" line="170"/>
<source>Report Table</source> <source>Report Table</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../ui/MainWindow.cpp" line="180"/> <location filename="../ui/MainWindow.cpp" line="183"/>
<source>Signal Indicator Lamp</source> <source>Signal Indicator Lamp</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../ui/MainWindow.cpp" line="191"/> <location filename="../ui/MainWindow.cpp" line="194"/>
<source>ParamSetting</source> <source>ParamSetting</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../ui/MainWindow.cpp" line="200"/> <location filename="../ui/MainWindow.cpp" line="203"/>
<source>bat File</source> <source>bat File</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>

View File

@ -27,6 +27,9 @@
#include "Matlab/MatlabObject.h" #include "Matlab/MatlabObject.h"
// 曲线面板管理器
#include "Panel/DataPanelManager.h"
#include "ui_MainWindow.h" #include "ui_MainWindow.h"
#include "viewer/OsgWidget.h" #include "viewer/OsgWidget.h"
#include "DockTitleBar.h" #include "DockTitleBar.h"
@ -211,6 +214,13 @@ void MainWindow::InitUI() {
// InitDockLayout(); // InitDockLayout();
// 初始化数据面板管理器
dataPanelManager_ = new DataPanelManager(this, this);
// 连接工作空间变化信号
connect(&WorkSpaceManager::Get(), &WorkSpaceManager::WorkSpaceChanged,
dataPanelManager_, &DataPanelManager::OnWorkspaceChanged);
// Restore previous UI layout if available // Restore previous UI layout if available
UiLayoutManager::Restore(this, 1); UiLayoutManager::Restore(this, 1);
@ -228,6 +238,13 @@ void MainWindow::InitUI() {
void MainWindow::UninitUI() { void MainWindow::UninitUI() {
// Save layout state before tearing down widgets // Save layout state before tearing down widgets
UiLayoutManager::Save(this, 1); UiLayoutManager::Save(this, 1);
// 清理数据面板管理器
if (dataPanelManager_) {
delete dataPanelManager_;
dataPanelManager_ = nullptr;
}
if (qtOsgViewWidget_) { if (qtOsgViewWidget_) {
qtOsgViewWidget_->Uninitialize(); qtOsgViewWidget_->Uninitialize();
delete qtOsgViewWidget_; delete qtOsgViewWidget_;

View File

@ -8,6 +8,8 @@ namespace Ui {
class MainWindow; class MainWindow;
} }
class DataPanelManager;
class MainWindow : public QMainWindow { class MainWindow : public QMainWindow {
Q_OBJECT Q_OBJECT
@ -35,6 +37,14 @@ public:
return surfaceDlg_; return surfaceDlg_;
} }
/**
* @brief
* @return
*/
DataPanelManager* GetDataPanelManager() const {
return dataPanelManager_;
}
void slotShowUISetting(); void slotShowUISetting();
public slots: public slots:
@ -62,6 +72,9 @@ private:
class CodeEdtUI* matlabFileDlg_{ nullptr }; class CodeEdtUI* matlabFileDlg_{ nullptr };
class AddParamSetting* addParamDlg_{ nullptr }; class AddParamSetting* addParamDlg_{ nullptr };
// 数据面板管理器
DataPanelManager* dataPanelManager_{ nullptr };
QMap<QString, QDockWidget*> m_mapDockWidget; QMap<QString, QDockWidget*> m_mapDockWidget;
}; };

View File

@ -0,0 +1,48 @@
#include "ui/Panel/CurvePanel.h"
#include "ui/DockWidget.h"
#include "common/SpdLogger.h"
#include <QVBoxLayout>
#include <QLabel>
#include <QFileInfo>
CurvePanel::CurvePanel(int index, const QString& filePath, QWidget* parent)
: DataPanel(index, FileEntryType::Curve, filePath, parent)
{
LOG_INFO("Created CurvePanel {} for file: {}", index, filePath.toStdString());
}
CurvePanel::~CurvePanel()
{
LOG_INFO("Destroyed CurvePanel {}", GetIndex());
}
void CurvePanel::RefreshPanel()
{
// Implement curve-specific refresh logic here
// For now, just call the base class implementation
DataPanel::RefreshPanel();
LOG_INFO("Refreshed CurvePanel {}", GetIndex());
}
void CurvePanel::InitUI()
{
// Create basic layout
QVBoxLayout* layout = new QVBoxLayout(this);
// Add placeholder label showing panel information
QLabel* infoLabel = new QLabel(QString("Curve Panel %1\nFile: %2\n\nCurve Drawing Area\nPlease inherit this class to implement specific drawing functionality")
.arg(GetIndex())
.arg(QFileInfo(GetFilePath()).fileName()));
infoLabel->setAlignment(Qt::AlignCenter);
infoLabel->setStyleSheet("QLabel { color: #666; font-size: 12px; padding: 20px; }");
layout->addWidget(infoLabel);
setLayout(layout);
}
QString CurvePanel::GetTypeDisplayName() const
{
return "Curve";
}

55
src/ui/Panel/CurvePanel.h Normal file
View File

@ -0,0 +1,55 @@
#pragma once
#include "DataPanel.h"
/**
* @file CurvePanel.h
* @brief Curve Panel Class
* Specialized panel for curve data visualization and manipulation
*/
/**
* @brief Curve panel class
* Specialized panel for curve data, inherits from DataPanel
*/
class CurvePanel : public DataPanel
{
Q_OBJECT
public:
/**
* @brief Constructor
* @param index Panel index
* @param filePath Associated file path
* @param parent Parent widget
*/
explicit CurvePanel(int index, const QString& filePath, QWidget* parent = nullptr);
/**
* @brief Destructor
*/
virtual ~CurvePanel();
/**
* @brief Get file type
* @return File type (always Curve for this class)
*/
FileEntryType GetFileType() const override { return FileEntryType::Curve; }
/**
* @brief Refresh panel content
*/
void RefreshPanel() override;
protected:
/**
* @brief Initialize UI for curve-specific layout
*/
void InitUI() override;
/**
* @brief Get type display name
* @return Display name for curve type
*/
QString GetTypeDisplayName() const override;
};

View File

@ -0,0 +1,75 @@
#include "ui/Panel/DataPanel.h"
#include "ui/DockWidget.h"
#include "common/SpdLogger.h"
#include <QVBoxLayout>
#include <QLabel>
#include <QFileInfo>
#include <QCloseEvent>
DataPanel::DataPanel(int index, FileEntryType fileType, const QString& filePath, QWidget* parent)
: QWidget(parent)
, index_(index)
, fileType_(fileType)
, filePath_(filePath)
, title_()
, dockWidget_(nullptr)
{
title_ = GenerateTitle();
InitUI();
LOG_INFO("Created DataPanel {} for {} file: {}", index_, FileEntryTypeToString(fileType_), filePath_.toStdString());
}
DataPanel::~DataPanel()
{
LOG_INFO("Destroyed DataPanel {} ({})", index_, FileEntryTypeToString(fileType_));
}
void DataPanel::closeEvent(QCloseEvent* event)
{
emit PanelClosed();
event->accept();
}
void DataPanel::InitUI()
{
// Create basic layout
QVBoxLayout* layout = new QVBoxLayout(this);
// Add placeholder label showing panel information
QString typeDisplayName = GetTypeDisplayName();
QLabel* infoLabel = new QLabel(QString("Panel %1 (%2)\nFile: %3\n\n%4 Data Area\nPlease inherit this class to implement specific functionality")
.arg(index_)
.arg(typeDisplayName)
.arg(QFileInfo(filePath_).fileName())
.arg(typeDisplayName));
infoLabel->setAlignment(Qt::AlignCenter);
infoLabel->setStyleSheet("QLabel { color: #666; font-size: 12px; padding: 20px; }");
layout->addWidget(infoLabel);
setLayout(layout);
}
QString DataPanel::GenerateTitle()
{
QFileInfo fileInfo(filePath_);
QString typeDisplayName = GetTypeDisplayName();
return QString("%1 Panel %2 - %3").arg(typeDisplayName).arg(index_).arg(fileInfo.baseName());
}
QString DataPanel::GetTypeDisplayName() const
{
switch (fileType_) {
case FileEntryType::Curve:
return "Curve";
case FileEntryType::Surface:
return "Surface";
case FileEntryType::Table:
return "Table";
case FileEntryType::Light:
return "Light";
default:
return "Unknown";
}
}

115
src/ui/Panel/DataPanel.h Normal file
View File

@ -0,0 +1,115 @@
#pragma once
#include <QWidget>
#include <QString>
#include "workspace/FileEntry.h"
class DockWidget;
/**
* @file DataPanel.h
* @brief Data Panel Base Class
* Provides panel framework structure for different data types, specific functionality implemented by derived classes
*/
/**
* @brief Data panel base class
* Provides panel framework structure for different data types, specific functionality implemented by derived classes
*/
class DataPanel : public QWidget
{
Q_OBJECT
public:
/**
* @brief Constructor
* @param index Panel index
* @param fileType File type
* @param filePath Associated file path
* @param parent Parent widget
*/
explicit DataPanel(int index, FileEntryType fileType, const QString& filePath, QWidget* parent = nullptr);
/**
* @brief Destructor
*/
virtual ~DataPanel();
/**
* @brief Get panel index
* @return Panel index
*/
int GetIndex() const { return index_; }
/**
* @brief Get file type (virtual function, implemented by derived classes)
* @return File type
*/
virtual FileEntryType GetFileType() const { return fileType_; }
/**
* @brief Get file path
* @return File path
*/
QString GetFilePath() const { return filePath_; }
/**
* @brief Get panel title
* @return Panel title
*/
QString GetTitle() const { return title_; }
/**
* @brief Set dock widget reference
* @param dockWidget Dock widget pointer
*/
void SetDockWidget(DockWidget* dockWidget) { dockWidget_ = dockWidget; }
/**
* @brief Get dock widget reference
* @return Dock widget pointer
*/
DockWidget* GetDockWidget() const { return dockWidget_; }
/**
* @brief Refresh panel content (virtual function, implemented by derived classes)
*/
virtual void RefreshPanel() {}
signals:
/**
* @brief Panel close signal
*/
void PanelClosed();
protected:
/**
* @brief Close event handler
* @param event Close event
*/
void closeEvent(QCloseEvent* event) override;
/**
* @brief Initialize UI (virtual function, derived classes implement specific layout)
*/
virtual void InitUI();
/**
* @brief Generate panel title
* @return Generated title
*/
virtual QString GenerateTitle();
/**
* @brief Get type display name (virtual function, implemented by derived classes)
* @return Display name for the file type
*/
virtual QString GetTypeDisplayName() const;
private:
int index_; // Panel index
FileEntryType fileType_; // File type
QString filePath_; // Associated file path
QString title_; // Panel title
DockWidget* dockWidget_; // Dock widget reference
};

View File

@ -0,0 +1,67 @@
#include "DataPanelFactory.h"
#include "DataPanel.h"
#include "CurvePanel.h"
#include "common/SpdLogger.h"
// Forward declarations for future panel types
// #include "SurfacePanel.h"
// #include "TablePanel.h"
// #include "LightPanel.h"
DataPanel* DataPanelFactory::CreatePanel(int index, FileEntryType fileType, const QString& filePath, QWidget* parent)
{
switch (fileType) {
case FileEntryType::Curve:
// For now, create CurvePanel which should inherit from DataPanel
// TODO: Update CurvePanel to inherit from DataPanel
return new CurvePanel(index, filePath, parent);
case FileEntryType::Surface:
// TODO: Implement SurfacePanel
LOG_WARN("SurfacePanel not implemented yet, creating base DataPanel");
return new DataPanel(index, fileType, filePath, parent);
case FileEntryType::Table:
// TODO: Implement TablePanel
LOG_WARN("TablePanel not implemented yet, creating base DataPanel");
return new DataPanel(index, fileType, filePath, parent);
case FileEntryType::Light:
// TODO: Implement LightPanel
LOG_WARN("LightPanel not implemented yet, creating base DataPanel");
return new DataPanel(index, fileType, filePath, parent);
default:
LOG_ERROR("Unsupported file type: {}", static_cast<int>(fileType));
return nullptr;
}
}
bool DataPanelFactory::IsTypeSupported(FileEntryType fileType)
{
switch (fileType) {
case FileEntryType::Curve:
case FileEntryType::Surface:
case FileEntryType::Table:
case FileEntryType::Light:
return true;
default:
return false;
}
}
QString DataPanelFactory::GetTypeDisplayName(FileEntryType fileType)
{
switch (fileType) {
case FileEntryType::Curve:
return "Curve";
case FileEntryType::Surface:
return "Surface";
case FileEntryType::Table:
return "Table";
case FileEntryType::Light:
return "Light";
default:
return "Unknown";
}
}

View File

@ -0,0 +1,49 @@
#pragma once
#include <memory>
#include "workspace/FileEntry.h"
class DataPanel;
class QWidget;
/**
* @file DataPanelFactory.h
* @brief Data Panel Factory
* Creates appropriate panel instances based on file type
*/
/**
* @brief Data panel factory class
* Creates appropriate panel instances based on file type using factory pattern
*/
class DataPanelFactory
{
public:
/**
* @brief Create panel based on file type
* @param index Panel index
* @param fileType File type
* @param filePath File path
* @param parent Parent widget
* @return Created panel pointer (caller takes ownership)
*/
static DataPanel* CreatePanel(int index, FileEntryType fileType, const QString& filePath, QWidget* parent = nullptr);
/**
* @brief Check if file type is supported
* @param fileType File type to check
* @return True if supported, false otherwise
*/
static bool IsTypeSupported(FileEntryType fileType);
/**
* @brief Get display name for file type
* @param fileType File type
* @return Display name
*/
static QString GetTypeDisplayName(FileEntryType fileType);
private:
// Private constructor to prevent instantiation
DataPanelFactory() = default;
};

View File

@ -0,0 +1,296 @@
#include "DataPanelManager.h"
#include "DataPanel.h"
#include "DataPanelFactory.h"
#include "ui/DockWidget.h"
#include "ui/DockTitleBar.h"
#include "ui/MainWindow.h"
#include "workspace/FileEntry.h"
#include "common/SpdLogger.h"
#include <QFileInfo>
#include <QDir>
const QString DataPanelManager::PANEL_OBJECT_NAME_PREFIX = "DataPanel_";
DataPanelManager::DataPanelManager(MainWindow* mainWindow, QObject* parent)
: QObject(parent)
, mainWindow_(mainWindow)
, currentWorkspace_(nullptr)
{
LOG_INFO("DataPanelManager initialized");
}
DataPanelManager::~DataPanelManager()
{
ClearAllPanels();
LOG_INFO("DataPanelManager destroyed");
}
void DataPanelManager::SetWorkspace(WorkSpace* workspace)
{
if (currentWorkspace_ == workspace) {
return;
}
// Disconnect old workspace signal connections
if (currentWorkspace_) {
disconnect(currentWorkspace_, nullptr, this, nullptr);
}
currentWorkspace_ = workspace;
// Connect new workspace signals
if (currentWorkspace_) {
connect(currentWorkspace_, &WorkSpace::FilesChanged, this, &DataPanelManager::OnFilesChanged);
}
// Update all panel types
if (currentWorkspace_) {
UpdatePanelsForType(FileEntryType::Curve);
UpdatePanelsForType(FileEntryType::Surface);
UpdatePanelsForType(FileEntryType::Table);
UpdatePanelsForType(FileEntryType::Light);
} else {
ClearAllPanels();
}
}
int DataPanelManager::GetActivePanelCount(FileEntryType fileType) const
{
if (static_cast<int>(fileType) == -1) {
// Return total count
return dataPanels_.size();
}
// Count panels of specific type
int count = 0;
for (auto it = dataPanels_.begin(); it != dataPanels_.end(); ++it) {
if (it.value()->GetFileType() == fileType) {
count++;
}
}
return count;
}
QList<DataPanel*> DataPanelManager::GetPanelsOfType(FileEntryType fileType) const
{
QList<DataPanel*> panels;
for (auto it = dataPanels_.begin(); it != dataPanels_.end(); ++it) {
if (it.value()->GetFileType() == fileType) {
panels.append(it.value());
}
}
return panels;
}
void DataPanelManager::OnWorkspaceChanged(WorkSpace* workspace)
{
SetWorkspace(workspace);
}
void DataPanelManager::OnFilesChanged(FileEntryType type)
{
// Only respond to supported file types
if (!DataPanelFactory::IsTypeSupported(type)) {
return;
}
UpdatePanelsForType(type);
}
void DataPanelManager::OnPanelClosed()
{
DataPanel* panel = qobject_cast<DataPanel*>(sender());
if (panel) {
RemovePanel(panel);
}
}
void DataPanelManager::UpdatePanelsForType(FileEntryType fileType)
{
if (!currentWorkspace_) {
ClearPanelsOfType(fileType);
return;
}
// Get files of specified type from current workspace
std::vector<FileEntry> files = currentWorkspace_->GetFileEntries(fileType);
// Limit to maximum panels per type
const int maxPanels = qMin(static_cast<int>(files.size()), GetMaxPanelCount());
// Find panels to remove (excess panels of this type)
QStringList keysToRemove;
for (auto it = dataPanels_.begin(); it != dataPanels_.end(); ++it) {
DataPanel* panel = it.value();
if (panel->GetFileType() == fileType && panel->GetIndex() >= maxPanels) {
keysToRemove.append(it.key());
}
}
// Remove excess panels
for (const QString& key : keysToRemove) {
RemovePanel(dataPanels_[key]);
}
// Create or update panels
for (int i = 0; i < maxPanels; ++i) {
const FileEntry& fileEntry = files[i];
QString filePath = currentWorkspace_->GetFileEntryAbsPath(fileEntry.type, i);
QString panelKey = QString("%1_%2").arg(FileEntryTypeToString(fileType)).arg(i);
if (dataPanels_.contains(panelKey)) {
// Check if file path has changed
DataPanel* existingPanel = dataPanels_[panelKey];
if (existingPanel->GetFilePath() != filePath) {
// File path changed, recreate panel
RemovePanel(existingPanel);
CreateDataPanel(fileType, filePath);
} else {
// File path unchanged, refresh data
existingPanel->RefreshPanel();
}
} else {
// Create new panel
CreateDataPanel(fileType, filePath);
}
}
}
DataPanel* DataPanelManager::CreateDataPanel(FileEntryType fileType, const QString& filePath)
{
if (GetActivePanelCount(fileType) >= GetMaxPanelCount()) {
LOG_WARN("Cannot create more {} panels, maximum count reached: {}",
FileEntryTypeToString(fileType), GetMaxPanelCount());
return nullptr;
}
// Find next available index for this file type
int index = FindNextAvailableIndex(fileType);
QString panelKey = QString("%1_%2").arg(FileEntryTypeToString(fileType)).arg(index);
// Create dock widget
DockWidget* dockWidget = new DockWidget(mainWindow_);
dockWidget->setObjectName(GeneratePanelObjectName(fileType, index));
// Set title bar
DockTitleBar* titleBar = new DockTitleBar(dockWidget);
dockWidget->SetDockWidgetTitleBar(titleBar);
// Connect signals
connect(dockWidget, &DockWidget::dockLocationChanged, this, [this](Qt::DockWidgetArea area) {
// Handle dock location changes if needed
});
// Add to main window
mainWindow_->addDockWidget(Qt::RightDockWidgetArea, dockWidget);
// Create panel using factory
DataPanel* panel = DataPanelFactory::CreatePanel(index, fileType, filePath, dockWidget);
if (!panel) {
LOG_ERROR("Failed to create panel for type: {}", FileEntryTypeToString(fileType));
dockWidget->deleteLater();
return nullptr;
}
dockWidget->setWidget(panel);
// Set panel's dock widget reference
panel->SetDockWidget(dockWidget);
// Connect panel signals
connect(panel, &DataPanel::PanelClosed, this, &DataPanelManager::OnPanelClosed);
// Save references
dataPanels_[panelKey] = panel;
dockWidgets_[panelKey] = dockWidget;
LOG_INFO("Created {} panel {} for file: {}",
FileEntryTypeToString(fileType), index, filePath.toStdString());
return panel;
}
void DataPanelManager::RemovePanel(DataPanel* panel)
{
if (!panel) {
return;
}
// Find panel key
QString panelKey;
for (auto it = dataPanels_.begin(); it != dataPanels_.end(); ++it) {
if (it.value() == panel) {
panelKey = it.key();
break;
}
}
if (panelKey.isEmpty()) {
return;
}
// Remove dock widget
if (dockWidgets_.contains(panelKey)) {
DockWidget* dockWidget = dockWidgets_[panelKey];
mainWindow_->removeDockWidget(dockWidget);
dockWidget->deleteLater();
}
// Remove from mappings
dataPanels_.remove(panelKey);
dockWidgets_.remove(panelKey);
// Delete panel
panel->deleteLater();
LOG_INFO("Removed {} panel {}",
FileEntryTypeToString(panel->GetFileType()), panel->GetIndex());
}
void DataPanelManager::ClearAllPanels()
{
// Get copy of all keys
QStringList keys = dataPanels_.keys();
// Remove panels one by one
for (const QString& key : keys) {
RemovePanel(dataPanels_[key]);
}
LOG_INFO("Cleared all data panels");
}
void DataPanelManager::ClearPanelsOfType(FileEntryType fileType)
{
QStringList keysToRemove;
for (auto it = dataPanels_.begin(); it != dataPanels_.end(); ++it) {
if (it.value()->GetFileType() == fileType) {
keysToRemove.append(it.key());
}
}
for (const QString& key : keysToRemove) {
RemovePanel(dataPanels_[key]);
}
LOG_INFO("Cleared all {} panels", FileEntryTypeToString(fileType));
}
QString DataPanelManager::GeneratePanelObjectName(FileEntryType fileType, int index) const
{
return QString("%1%2_%3").arg(PANEL_OBJECT_NAME_PREFIX)
.arg(FileEntryTypeToString(fileType))
.arg(index);
}
int DataPanelManager::FindNextAvailableIndex(FileEntryType fileType) const
{
int index = 0;
QString baseKey = QString("%1_").arg(FileEntryTypeToString(fileType));
while (dataPanels_.contains(baseKey + QString::number(index))) {
index++;
}
return index;
}

View File

@ -0,0 +1,125 @@
#pragma once
#include <QObject>
#include <QMap>
#include <memory>
#include "workspace/WorkSpace.h"
#include "workspace/FileEntry.h"
class DockWidget;
class DataPanel;
class MainWindow;
/**
* @file DataPanelManager.h
* @brief Data Panel Manager
* Manages data panels created based on workspace files, supports multiple file types
*/
class DataPanelManager : public QObject
{
Q_OBJECT
public:
explicit DataPanelManager(MainWindow* mainWindow, QObject* parent = nullptr);
~DataPanelManager();
/**
* @brief Set current workspace
* @param workspace Workspace pointer
*/
void SetWorkspace(WorkSpace* workspace);
/**
* @brief Get current active panel count for specific type
* @param fileType File type (if not specified, returns total count)
* @return Panel count
*/
int GetActivePanelCount(FileEntryType fileType = static_cast<FileEntryType>(-1)) const;
/**
* @brief Get maximum panel count per type
* @return Maximum panel count
*/
int GetMaxPanelCount() const { return 9; }
/**
* @brief Get panels of specific type
* @param fileType File type
* @return List of panels for the specified type
*/
QList<DataPanel*> GetPanelsOfType(FileEntryType fileType) const;
public slots:
/**
* @brief Handle workspace changes
* @param workspace New workspace
*/
void OnWorkspaceChanged(WorkSpace* workspace);
/**
* @brief Handle file changes
* @param type File type
*/
void OnFilesChanged(FileEntryType type);
/**
* @brief Handle panel close event
*/
void OnPanelClosed();
private:
/**
* @brief Update panels for specific file type
* @param fileType File type to update
*/
void UpdatePanelsForType(FileEntryType fileType);
/**
* @brief Create new data panel
* @param fileType File type
* @param filePath File path
* @return Created panel pointer
*/
DataPanel* CreateDataPanel(FileEntryType fileType, const QString& filePath);
/**
* @brief Remove panel
* @param panel Panel pointer
*/
void RemovePanel(DataPanel* panel);
/**
* @brief Clear all panels
*/
void ClearAllPanels();
/**
* @brief Clear panels of specific type
* @param fileType File type
*/
void ClearPanelsOfType(FileEntryType fileType);
/**
* @brief Generate panel object name
* @param fileType File type
* @param index Panel index
* @return Object name
*/
QString GeneratePanelObjectName(FileEntryType fileType, int index) const;
/**
* @brief Find next available index for file type
* @param fileType File type
* @return Next available index
*/
int FindNextAvailableIndex(FileEntryType fileType) const;
private:
MainWindow* mainWindow_; // Main window pointer
WorkSpace* currentWorkspace_; // Current workspace
QMap<QString, DataPanel*> dataPanels_; // Panel mapping (key -> panel)
QMap<QString, DockWidget*> dockWidgets_; // Dock widget mapping (key -> dock widget)
static const QString PANEL_OBJECT_NAME_PREFIX; // Panel object name prefix
};

View File

@ -190,7 +190,7 @@ void WorkSpaceManager::OnFrame() {
QString WorkSpaceManager::GetDefaultWorkSpaceName() { QString WorkSpaceManager::GetDefaultWorkSpaceName() {
#if _DEBUG #if _DEBUG
const QString iniFile = QString("%1workspace/config.ini").arg(QString(CONFIG_PATH)).arg(skin); const QString iniFile = QString("%1workspace/config.ini").arg(QString(CONFIG_PATH));
#else #else
const QString appDirPath = QApplication::applicationDirPath(); const QString appDirPath = QApplication::applicationDirPath();
const QString iniFile = QString("%1/config/workspace/config.ini").arg(appDirPath); const QString iniFile = QString("%1/config/workspace/config.ini").arg(appDirPath);