189 lines
6.1 KiB
C++
189 lines
6.1 KiB
C++
#include "panels/chart/TablePager.hpp"
|
||
|
||
#include <algorithm>
|
||
|
||
#include <QComboBox>
|
||
#include <QHBoxLayout>
|
||
#include <QIntValidator>
|
||
#include <QLabel>
|
||
#include <QLineEdit>
|
||
#include <QSignalBlocker>
|
||
#include <QToolButton>
|
||
|
||
namespace geopro::app {
|
||
|
||
namespace {
|
||
// 每页条数选项(实测原版 vxe-pager 下拉:50/100/500/1000,默认 50)。
|
||
const int kPageSizes[] = {50, 100, 500, 1000};
|
||
constexpr int kPagerCount = 7; // 页码窗口(>此值用 … 折叠,对齐 vxe 默认)
|
||
constexpr int kJumpStep = 5; // 点击 … 的跳页步长
|
||
|
||
// 分页器样式:常态不设字色(跟随主题/全局样式表);边框用半透明灰(两主题通用);
|
||
// hover/选中页用强调蓝 #409EFF(与 DataTableView 开关同色)。
|
||
const char* kPagerQss = R"(
|
||
QToolButton {
|
||
border: 1px solid rgba(128,128,128,0.35);
|
||
border-radius: 3px;
|
||
padding: 1px 6px;
|
||
min-width: 16px;
|
||
min-height: 20px;
|
||
background: transparent;
|
||
}
|
||
QToolButton:hover:enabled { color: #409EFF; border-color: #409EFF; }
|
||
QToolButton[active="true"] { color: #409EFF; border-color: #409EFF; font-weight: bold; }
|
||
QToolButton:disabled { color: rgba(128,128,128,0.55); }
|
||
)";
|
||
} // namespace
|
||
|
||
TablePager::TablePager(QWidget* parent) : QWidget(parent) {
|
||
setStyleSheet(QString::fromUtf8(kPagerQss));
|
||
|
||
auto* lay = new QHBoxLayout(this);
|
||
lay->setContentsMargins(8, 6, 8, 6);
|
||
lay->setSpacing(6);
|
||
lay->addStretch(1); // 右对齐
|
||
|
||
prevBtn_ = new QToolButton(this);
|
||
prevBtn_->setText(QStringLiteral("‹"));
|
||
prevBtn_->setCursor(Qt::PointingHandCursor);
|
||
connect(prevBtn_, &QToolButton::clicked, this,
|
||
[this] { emit pageRequested(pageNo_ - 1, pageSize_); });
|
||
lay->addWidget(prevBtn_);
|
||
|
||
numHost_ = new QWidget(this);
|
||
numLay_ = new QHBoxLayout(numHost_);
|
||
numLay_->setContentsMargins(0, 0, 0, 0);
|
||
numLay_->setSpacing(6);
|
||
lay->addWidget(numHost_);
|
||
|
||
nextBtn_ = new QToolButton(this);
|
||
nextBtn_->setText(QStringLiteral("›"));
|
||
nextBtn_->setCursor(Qt::PointingHandCursor);
|
||
connect(nextBtn_, &QToolButton::clicked, this,
|
||
[this] { emit pageRequested(pageNo_ + 1, pageSize_); });
|
||
lay->addWidget(nextBtn_);
|
||
|
||
auto* gotoLabel = new QLabel(QStringLiteral("前往"), this);
|
||
lay->addWidget(gotoLabel);
|
||
|
||
jumpEdit_ = new QLineEdit(this);
|
||
jumpEdit_->setFixedWidth(40);
|
||
jumpEdit_->setAlignment(Qt::AlignCenter);
|
||
jumpValidator_ = new QIntValidator(1, 1, jumpEdit_);
|
||
jumpEdit_->setValidator(jumpValidator_);
|
||
connect(jumpEdit_, &QLineEdit::returnPressed, this, [this] {
|
||
bool ok = false;
|
||
int p = jumpEdit_->text().toInt(&ok);
|
||
const int pc = pageCount();
|
||
if (!ok) {
|
||
jumpEdit_->setText(QString::number(pageNo_));
|
||
return;
|
||
}
|
||
p = std::min(std::max(1, p), std::max(1, pc));
|
||
if (p == pageNo_) {
|
||
jumpEdit_->setText(QString::number(pageNo_));
|
||
return;
|
||
}
|
||
emit pageRequested(p, pageSize_);
|
||
});
|
||
lay->addWidget(jumpEdit_);
|
||
|
||
lay->addWidget(new QLabel(QStringLiteral("页"), this));
|
||
|
||
sizeCombo_ = new QComboBox(this);
|
||
for (int s : kPageSizes)
|
||
sizeCombo_->addItem(QStringLiteral("%1条/页").arg(s), s);
|
||
connect(sizeCombo_, &QComboBox::activated, this, [this](int i) {
|
||
emit pageRequested(1, sizeCombo_->itemData(i).toInt()); // 改每页条数 → 回第 1 页
|
||
});
|
||
lay->addWidget(sizeCombo_);
|
||
|
||
totalLabel_ = new QLabel(this);
|
||
lay->addWidget(totalLabel_);
|
||
|
||
setState(0, 1, pageSize_);
|
||
}
|
||
|
||
int TablePager::pageCount() const {
|
||
if (pageSize_ <= 0) return 1;
|
||
return std::max(1, (total_ + pageSize_ - 1) / pageSize_);
|
||
}
|
||
|
||
void TablePager::setState(int total, int pageNo, int pageSize) {
|
||
total_ = std::max(0, total);
|
||
if (pageSize > 0) pageSize_ = pageSize;
|
||
const int pc = pageCount();
|
||
pageNo_ = std::min(std::max(1, pageNo), pc);
|
||
|
||
prevBtn_->setEnabled(pageNo_ > 1);
|
||
nextBtn_->setEnabled(pageNo_ < pc);
|
||
|
||
jumpValidator_->setTop(pc);
|
||
{
|
||
QSignalBlocker b(jumpEdit_);
|
||
jumpEdit_->setText(QString::number(pageNo_));
|
||
}
|
||
{
|
||
QSignalBlocker b(sizeCombo_);
|
||
int idx = sizeCombo_->findData(pageSize_);
|
||
if (idx < 0) { // 非预设条数(兜底):补一项再选中
|
||
sizeCombo_->addItem(QStringLiteral("%1条/页").arg(pageSize_), pageSize_);
|
||
idx = sizeCombo_->findData(pageSize_);
|
||
}
|
||
sizeCombo_->setCurrentIndex(idx);
|
||
}
|
||
totalLabel_->setText(QStringLiteral("共 %1 条记录").arg(total_));
|
||
|
||
rebuildNumbers();
|
||
}
|
||
|
||
void TablePager::rebuildNumbers() {
|
||
// 清空旧页码按钮。
|
||
while (QLayoutItem* it = numLay_->takeAt(0)) {
|
||
if (QWidget* w = it->widget()) w->deleteLater();
|
||
delete it;
|
||
}
|
||
|
||
const int pc = pageCount();
|
||
auto addNum = [this](int p, bool active) {
|
||
auto* b = new QToolButton(numHost_);
|
||
b->setText(QString::number(p));
|
||
b->setCursor(Qt::PointingHandCursor);
|
||
b->setProperty("active", active);
|
||
b->setEnabled(!active); // 当前页不可再点
|
||
connect(b, &QToolButton::clicked, this, [this, p] { emit pageRequested(p, pageSize_); });
|
||
numLay_->addWidget(b);
|
||
};
|
||
auto addDots = [this](int target) {
|
||
auto* b = new QToolButton(numHost_);
|
||
b->setText(QStringLiteral("..."));
|
||
b->setCursor(Qt::PointingHandCursor);
|
||
connect(b, &QToolButton::clicked, this,
|
||
[this, target] { emit pageRequested(target, pageSize_); });
|
||
numLay_->addWidget(b);
|
||
};
|
||
|
||
if (pc <= kPagerCount) {
|
||
for (int p = 1; p <= pc; ++p) addNum(p, p == pageNo_);
|
||
return;
|
||
}
|
||
// 折叠窗口:首页 [ … ] 中段(当前±2) [ … ] 末页。
|
||
addNum(1, pageNo_ == 1);
|
||
int left = pageNo_ - 2;
|
||
int right = pageNo_ + 2;
|
||
if (left < 2) {
|
||
left = 2;
|
||
right = 5;
|
||
}
|
||
if (right > pc - 1) {
|
||
right = pc - 1;
|
||
left = pc - 4;
|
||
}
|
||
if (left > 2) addDots(std::max(1, pageNo_ - kJumpStep));
|
||
for (int p = left; p <= right; ++p) addNum(p, p == pageNo_);
|
||
if (right < pc - 1) addDots(std::min(pc, pageNo_ + kJumpStep));
|
||
addNum(pc, pageNo_ == pc);
|
||
}
|
||
|
||
} // namespace geopro::app
|