95 lines
4.0 KiB
C++
95 lines
4.0 KiB
C++
#include "panels/DatasetDetailPage.hpp"
|
||
|
||
#include <QButtonGroup>
|
||
#include <QVBoxLayout>
|
||
|
||
#include "Glyphs.hpp"
|
||
#include "PanelHeader.hpp"
|
||
#include "panels/LoadingOverlay.hpp"
|
||
#include "panels/chart/DataTableView.hpp"
|
||
#include "panels/chart/DetailViewFactory.hpp"
|
||
#include "panels/chart/IDetailView.hpp"
|
||
|
||
namespace geopro::app {
|
||
|
||
DatasetDetailPage::DatasetDetailPage(QWidget* parent) : QWidget(parent) {
|
||
auto* lay = new QVBoxLayout(this);
|
||
lay->setContentsMargins(0, 0, 0, 0);
|
||
lay->setSpacing(0);
|
||
}
|
||
|
||
void DatasetDetailPage::build(const QString& dsId, const QString& ddCode, const QString& dsName,
|
||
const std::vector<geopro::controller::TabSpec>& tabs) {
|
||
Q_ASSERT(views_.empty()); // build() 仅一次:views_ 为已 release 的裸指针,二次构建会泄漏旧视图
|
||
if (!views_.empty()) return;
|
||
dsId_ = dsId;
|
||
ddCode_ = ddCode;
|
||
dsName_ = dsName;
|
||
tabs_ = tabs;
|
||
views_.assign(tabs.size(), nullptr);
|
||
loaded_.assign(tabs.size(), false);
|
||
requested_.assign(tabs.size(), false);
|
||
overlays_.clear();
|
||
|
||
// 按 TabSpec 经工厂造视图,并组装为带表头页签的面板。
|
||
QVector<PanelTab> panelTabs;
|
||
for (size_t i = 0; i < tabs.size(); ++i) {
|
||
const auto& spec = tabs[i];
|
||
auto view = makeDetailView(spec.kind, this); // 抛出由调用栈兜底(GuardedApplication)
|
||
IDetailView* raw = view.release(); // QWidget 由 this/QwtPlot 父子树接管生命周期
|
||
views_[i] = raw;
|
||
// lazy 页签:建覆盖该视图的加载遮罩(父为视图 widget,随其尺寸覆盖图区)。
|
||
if (spec.lazy) overlays_[static_cast<int>(i)] = new LoadingOverlay(raw->widget());
|
||
// 分页型页签:把表格视图的分页请求冒泡为页信号(携带 dsId/ddCode/tabIndex + 页参数)。
|
||
if (spec.paginated) {
|
||
if (auto* table = qobject_cast<DataTableView*>(raw->widget())) {
|
||
const int idx = static_cast<int>(i);
|
||
connect(table, &DataTableView::pageRequested, this,
|
||
[this, idx](int pageNo, int pageSize) {
|
||
emit tabPageNeeded(dsId_, ddCode_, idx, pageNo, pageSize);
|
||
});
|
||
}
|
||
}
|
||
panelTabs.append({Glyph::Detail, spec.title, raw->widget(), false});
|
||
}
|
||
const QVector<HeaderAction> actions = {
|
||
{Glyph::Download, QStringLiteral("导出")},
|
||
};
|
||
|
||
auto tabbedPanel = buildTabbedPanel(panelTabs, actions);
|
||
layout()->addWidget(tabbedPanel.container);
|
||
|
||
// lazy 页签首次激活 → 发 tabNeeded 请求懒加载(数据慢,故不随开页同步拉)。
|
||
if (tabbedPanel.tabGroup) {
|
||
connect(tabbedPanel.tabGroup, &QButtonGroup::idClicked, this, [this](int idx) {
|
||
if (idx < 0 || idx >= static_cast<int>(tabs_.size())) return;
|
||
if (!tabs_[static_cast<size_t>(idx)].lazy) return;
|
||
if (requested_[static_cast<size_t>(idx)] || loaded_[static_cast<size_t>(idx)]) return;
|
||
if (dsId_.isEmpty()) return;
|
||
requested_[static_cast<size_t>(idx)] = true;
|
||
emit tabNeeded(dsId_, ddCode_, idx);
|
||
});
|
||
}
|
||
}
|
||
|
||
void DatasetDetailPage::setTabPayload(int tabIndex, const QVariant& payload) {
|
||
if (tabIndex < 0 || tabIndex >= static_cast<int>(views_.size())) return;
|
||
if (auto* v = views_[static_cast<size_t>(tabIndex)]) v->setPayload(payload);
|
||
loaded_[static_cast<size_t>(tabIndex)] = true;
|
||
requested_[static_cast<size_t>(tabIndex)] = true; // 已加载,切回不再重复请求
|
||
setTabLoading(tabIndex, false); // 数据到达,隐藏遮罩
|
||
}
|
||
|
||
void DatasetDetailPage::setTabLoading(int tabIndex, bool on) {
|
||
auto it = overlays_.find(tabIndex);
|
||
if (it == overlays_.end()) return; // 非 lazy 页签无遮罩
|
||
if (on) it.value()->showOver(); else it.value()->hide();
|
||
}
|
||
|
||
void DatasetDetailPage::clearAllLoadingOverlays() {
|
||
for (auto* overlay : overlays_)
|
||
if (overlay) overlay->hide();
|
||
}
|
||
|
||
} // namespace geopro::app
|