#include "panels/DatasetListPanel.hpp" #include #include #include #include #include #include #include #include #include "Theme.hpp" namespace geopro::app { namespace { QString humanSize(long long b) { if (b < 1024) return QStringLiteral("%1 B").arg(b); const double kb = b / 1024.0; if (kb < 1024.0) return QStringLiteral("%1 KB").arg(kb, 0, 'f', 1); return QStringLiteral("%1 MB").arg(kb / 1024.0, 0, 'f', 1); } // 数据/文件列表卡片委托:标题+元信息双行、悬停/选中圆角高亮 + 选中左 2px 强调竖条(规范§6.2)。 // 特殊行(加载更多 / 占位提示)退回为居中纯文本,不画卡片。 class DatasetCardDelegate : public QStyledItemDelegate { public: using QStyledItemDelegate::QStyledItemDelegate; QSize sizeHint(const QStyleOptionViewItem&, const QModelIndex& idx) const override { const bool special = idx.data(kDsLoadMoreRole).toBool() || !(idx.flags() & Qt::ItemIsSelectable); return QSize(0, special ? 34 : 52); } void paint(QPainter* p, const QStyleOptionViewItem& opt, const QModelIndex& idx) const override { p->save(); p->setRenderHint(QPainter::Antialiasing, true); const QString disp = idx.data(Qt::DisplayRole).toString(); // 「加载更多」:居中强调色文本(hover 时加底)。 if (idx.data(kDsLoadMoreRole).toBool()) { if (opt.state & QStyle::State_MouseOver) { QPainterPath bgp; bgp.addRoundedRect(opt.rect.adjusted(4, 2, -4, -2), 6, 6); p->fillPath(bgp, geopro::app::tokenColor("bg/hover")); } p->setPen(geopro::app::tokenColor("accent/primary")); p->drawText(opt.rect, Qt::AlignCenter, disp); p->restore(); return; } // 占位提示行(不可选):居中淡色文本。 if (!(idx.flags() & Qt::ItemIsSelectable)) { p->setPen(geopro::app::tokenColor("text/disabled")); p->drawText(opt.rect, Qt::AlignCenter, disp); p->restore(); return; } // 卡片 const QRect r = opt.rect.adjusted(4, 2, -4, -2); const bool selected = opt.state & QStyle::State_Selected; const bool hover = opt.state & QStyle::State_MouseOver; if (selected || hover) { QPainterPath path; path.addRoundedRect(r, 6, 6); p->fillPath(path, geopro::app::tokenColor(selected ? "bg/selected" : "bg/hover")); } if (selected) { // 左 2px 强调竖条(规范§6.2) p->fillRect(QRect(r.left(), r.top() + 4, 2, r.height() - 8), geopro::app::tokenColor("accent/primary")); } QString title = disp, meta; const int nl = disp.indexOf(QLatin1Char('\n')); if (nl >= 0) { title = disp.left(nl); meta = disp.mid(nl + 1); } const QRect textR = r.adjusted(14, 6, -12, -6); // 标题 QFont tf = opt.font; tf.setPixelSize(geopro::app::scaledPx(13)); p->setFont(tf); p->setPen(geopro::app::tokenColor("text/primary")); const QRect titleR(textR.left(), textR.top(), textR.width(), textR.height() / 2); p->drawText(titleR, Qt::AlignLeft | Qt::AlignVCenter, p->fontMetrics().elidedText(title, Qt::ElideRight, titleR.width())); // 元信息 if (!meta.isEmpty()) { QFont mf = opt.font; mf.setPixelSize(geopro::app::scaledPx(11)); p->setFont(mf); p->setPen(geopro::app::tokenColor("text/tertiary")); const QRect metaR(textR.left(), textR.center().y() + 1, textR.width(), textR.height() / 2); p->drawText(metaR, Qt::AlignLeft | Qt::AlignVCenter, p->fontMetrics().elidedText(meta, Qt::ElideRight, metaR.width())); } p->restore(); } }; } // namespace void populateDatasetList(QListWidget* list, const std::vector& rows, bool append) { if (!list) return; if (!append) list->clear(); for (const auto& d : rows) { QString text = QString::fromStdString(d.dsName); QString sub = QString::fromStdString(d.createTime); // 名称下先创建时间 if (!d.typeName.empty()) sub += QStringLiteral(" · %1").arg(QString::fromStdString(d.typeName)); // 再跟类型 if (!sub.isEmpty()) text += QStringLiteral("\n%1").arg(sub); auto* item = new QListWidgetItem(text, list); item->setData(kDsIdRole, QString::fromStdString(d.id)); item->setData(kDsDdTypeRole, QString::fromStdString(d.ddCode)); } } void populateFileList(QListWidget* list, const std::vector& rows, bool append) { if (!list) return; if (!append) list->clear(); if (!append && rows.empty()) { auto* hint = new QListWidgetItem(QStringLiteral("(暂无文件)"), list); hint->setFlags(Qt::NoItemFlags); hint->setTextAlignment(Qt::AlignCenter); return; } for (const auto& d : rows) { const QString fname = d.fileName.empty() ? QString::fromStdString(d.dsName) : QString::fromStdString(d.fileName); QString sub = QString::fromStdString(d.createTime); // 名称下先创建时间 sub += QStringLiteral(" · %1").arg(humanSize(d.fileSize)); // 再跟大小 const QString text = fname + QStringLiteral("\n%1").arg(sub); auto* item = new QListWidgetItem(text, list); item->setData(kDsIdRole, QString::fromStdString(d.id)); item->setData(kDsFileUrlRole, QString::fromStdString(d.fileUrl)); } } void applyDatasetCardDelegate(QListWidget* list) { if (!list) return; list->setItemDelegate(new DatasetCardDelegate(list)); list->setMouseTracking(true); // 让委托收到 hover 状态 list->setSpacing(0); // 卡间距由委托内边距控制 QObject::connect(&ThemeManager::instance(), &ThemeManager::changed, list, [list]() { list->viewport()->update(); }); } } // namespace geopro::app