|
|
|
|
@ -22,8 +22,12 @@
|
|
|
|
|
#include <QDialog>
|
|
|
|
|
#include <QDialogButtonBox>
|
|
|
|
|
#include <QApplication>
|
|
|
|
|
#include <QStyle>
|
|
|
|
|
#include <QTableWidget>
|
|
|
|
|
#include <QAbstractScrollArea>
|
|
|
|
|
#include <QScrollBar>
|
|
|
|
|
#include <QWheelEvent>
|
|
|
|
|
#include <QKeyEvent>
|
|
|
|
|
#include <QMouseEvent>
|
|
|
|
|
#include <QHeaderView>
|
|
|
|
|
#include <QSplitter>
|
|
|
|
|
|
|
|
|
|
@ -50,6 +54,7 @@
|
|
|
|
|
|
|
|
|
|
#include <math.h>
|
|
|
|
|
#include <float.h>
|
|
|
|
|
#include <limits.h>
|
|
|
|
|
|
|
|
|
|
namespace
|
|
|
|
|
{
|
|
|
|
|
@ -208,11 +213,258 @@ public:
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// 表格仅承载可见行,完整组合编号使用六十四位整数,滚动过程中按编号取数。
|
|
|
|
|
class SensitivityRunsView : public QAbstractScrollArea
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
SensitivityRunsView(const nmDataSensitive& data, const QIcon& arrow, QWidget* parent)
|
|
|
|
|
: QAbstractScrollArea(parent), m_data(data), m_arrow(arrow),
|
|
|
|
|
m_table(nullptr),
|
|
|
|
|
m_total(data.getTotalModelCount()), m_first(0), m_selected(0),
|
|
|
|
|
m_visibleRows(1), m_updating(false), m_wheelDelta(0)
|
|
|
|
|
{
|
|
|
|
|
// 使用现有表格控件绘制表头、行选中和单元格,滚动条控制完整列表。
|
|
|
|
|
setFrameShape(QFrame::StyledPanel);
|
|
|
|
|
setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
|
|
|
|
m_table = new QTableWidget(viewport());
|
|
|
|
|
m_table->setFrameShape(QFrame::NoFrame);
|
|
|
|
|
m_table->setColumnCount(3);
|
|
|
|
|
m_table->setHorizontalHeaderLabels(QStringList() << "" << "#" << nmWxSensitive::tr("Description"));
|
|
|
|
|
m_table->verticalHeader()->setVisible(false);
|
|
|
|
|
m_table->verticalHeader()->setDefaultSectionSize(24);
|
|
|
|
|
m_table->horizontalHeader()->setResizeMode(0, QHeaderView::Fixed);
|
|
|
|
|
m_table->horizontalHeader()->setResizeMode(1, QHeaderView::Fixed);
|
|
|
|
|
m_table->horizontalHeader()->setResizeMode(2, QHeaderView::Interactive);
|
|
|
|
|
m_table->horizontalHeader()->setStretchLastSection(true);
|
|
|
|
|
m_table->horizontalHeader()->setHighlightSections(false);
|
|
|
|
|
m_table->horizontalHeader()->setDefaultAlignment(Qt::AlignLeft | Qt::AlignVCenter);
|
|
|
|
|
m_table->setColumnWidth(0, 20);
|
|
|
|
|
m_table->setColumnWidth(1, m_table->fontMetrics().width(QString::number(m_total)) + 16);
|
|
|
|
|
m_table->setEditTriggers(QAbstractItemView::NoEditTriggers);
|
|
|
|
|
m_table->setSelectionBehavior(QAbstractItemView::SelectRows);
|
|
|
|
|
m_table->setSelectionMode(QAbstractItemView::SingleSelection);
|
|
|
|
|
m_table->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
|
|
|
|
m_table->setWordWrap(false);
|
|
|
|
|
m_table->setStyleSheet("QTableWidget { background-color: white; }");
|
|
|
|
|
int descriptionWidth = 0;
|
|
|
|
|
for (int i = 0; i < m_data.getVariableCount(); ++i) {
|
|
|
|
|
nmDataSensitive::VariableSampling& variable = m_data.getVariable(i);
|
|
|
|
|
if (!variable.getEnabled()) continue;
|
|
|
|
|
m_indices.append(i);
|
|
|
|
|
int width = 0;
|
|
|
|
|
const QVector<double> samples = variable.samplingValues();
|
|
|
|
|
for (int row = 0; row < samples.size(); ++row)
|
|
|
|
|
width = qMax(width, m_table->fontMetrics().width(parameterDescription(i, samples[row])));
|
|
|
|
|
if (m_data.getCalculationType() == nmDataSensitive::CALC_DETERMINISTIC)
|
|
|
|
|
descriptionWidth = qMax(descriptionWidth, width);
|
|
|
|
|
else descriptionWidth += width + m_table->fontMetrics().width(" + ");
|
|
|
|
|
}
|
|
|
|
|
// 长组合可横向滚动并通过提示查看完整文本,保持各行高度一致。
|
|
|
|
|
m_table->setColumnWidth(2, qMax(200, descriptionWidth + 16));
|
|
|
|
|
QVBoxLayout* layout = new QVBoxLayout(viewport());
|
|
|
|
|
layout->setContentsMargins(0, 0, 0, 0);
|
|
|
|
|
layout->addWidget(m_table);
|
|
|
|
|
m_table->installEventFilter(this);
|
|
|
|
|
m_table->viewport()->installEventFilter(this);
|
|
|
|
|
verticalScrollBar()->installEventFilter(this);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void scrollAction(int action)
|
|
|
|
|
{
|
|
|
|
|
// 超大列表的滚动条位置按比例映射,单步、整屏移动仍保持精确行号。
|
|
|
|
|
switch (action) {
|
|
|
|
|
case QAbstractSlider::SliderSingleStepAdd: scrollRows(1); break;
|
|
|
|
|
case QAbstractSlider::SliderSingleStepSub: scrollRows(-1); break;
|
|
|
|
|
case QAbstractSlider::SliderPageStepAdd: scrollRows(m_visibleRows); break;
|
|
|
|
|
case QAbstractSlider::SliderPageStepSub: scrollRows(-m_visibleRows); break;
|
|
|
|
|
case QAbstractSlider::SliderToMinimum: m_first = 0; refreshRows(); break;
|
|
|
|
|
case QAbstractSlider::SliderToMaximum: m_first = maximumFirst(); refreshRows(); break;
|
|
|
|
|
case QAbstractSlider::SliderMove:
|
|
|
|
|
m_first = firstFromPosition(verticalScrollBar()->sliderPosition());
|
|
|
|
|
refreshRows();
|
|
|
|
|
break;
|
|
|
|
|
default: break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected:
|
|
|
|
|
void resizeEvent(QResizeEvent* event) override
|
|
|
|
|
{
|
|
|
|
|
// 窗口变化时仅调整可见行数量,绝不按总次数分配表格项。
|
|
|
|
|
QAbstractScrollArea::resizeEvent(event);
|
|
|
|
|
refreshRows();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void scrollContentsBy(int, int) override
|
|
|
|
|
{
|
|
|
|
|
// 处理拖动滚动条或系统直接改变位置的情况。
|
|
|
|
|
if (m_updating) return;
|
|
|
|
|
m_first = firstFromPosition(verticalScrollBar()->value());
|
|
|
|
|
refreshRows();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool eventFilter(QObject* object, QEvent* event) override
|
|
|
|
|
{
|
|
|
|
|
// 滚轮、键盘和鼠标均操作完整运行列表,而不是可见行缓存。
|
|
|
|
|
if (event->type() == QEvent::Wheel) {
|
|
|
|
|
QWheelEvent* wheel = static_cast<QWheelEvent*>(event);
|
|
|
|
|
if (wheel->orientation() == Qt::Vertical) {
|
|
|
|
|
m_wheelDelta += wheel->delta();
|
|
|
|
|
const int steps = m_wheelDelta / 120;
|
|
|
|
|
m_wheelDelta %= 120;
|
|
|
|
|
scrollRows(-qint64(steps) * QApplication::wheelScrollLines());
|
|
|
|
|
wheel->accept();
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
} else if (event->type() == QEvent::KeyPress) {
|
|
|
|
|
QKeyEvent* key = static_cast<QKeyEvent*>(event);
|
|
|
|
|
qint64 movement = 0;
|
|
|
|
|
switch (key->key()) {
|
|
|
|
|
case Qt::Key_Up: movement = -1; break;
|
|
|
|
|
case Qt::Key_Down: movement = 1; break;
|
|
|
|
|
case Qt::Key_PageUp: movement = -m_visibleRows; break;
|
|
|
|
|
case Qt::Key_PageDown: movement = m_visibleRows; break;
|
|
|
|
|
case Qt::Key_Home: m_selected = 0; break;
|
|
|
|
|
case Qt::Key_End: m_selected = m_total - 1; break;
|
|
|
|
|
default: return QAbstractScrollArea::eventFilter(object, event);
|
|
|
|
|
}
|
|
|
|
|
if (movement < 0) m_selected -= qMin(m_selected, quint64(-movement));
|
|
|
|
|
else if (movement > 0) m_selected += qMin(m_total - 1 - m_selected, quint64(movement));
|
|
|
|
|
if (m_selected < m_first) m_first = m_selected;
|
|
|
|
|
else if (m_selected - m_first >= quint64(m_visibleRows))
|
|
|
|
|
m_first = m_selected - m_visibleRows + 1;
|
|
|
|
|
refreshRows();
|
|
|
|
|
key->accept();
|
|
|
|
|
return true;
|
|
|
|
|
} else if (object == m_table->viewport() &&
|
|
|
|
|
(event->type() == QEvent::MouseButtonPress || event->type() == QEvent::MouseButtonRelease)) {
|
|
|
|
|
QMouseEvent* mouse = static_cast<QMouseEvent*>(event);
|
|
|
|
|
const int row = m_table->rowAt(mouse->pos().y());
|
|
|
|
|
if (mouse->button() == Qt::LeftButton && row >= 0) {
|
|
|
|
|
m_selected = m_first + row;
|
|
|
|
|
refreshRows();
|
|
|
|
|
}
|
|
|
|
|
} else if (object == m_table->viewport() && event->type() == QEvent::Resize) {
|
|
|
|
|
refreshRows();
|
|
|
|
|
}
|
|
|
|
|
return QAbstractScrollArea::eventFilter(object, event);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
quint64 maximumFirst() const
|
|
|
|
|
{
|
|
|
|
|
return m_total > quint64(m_visibleRows) ? m_total - m_visibleRows : 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
quint64 firstFromPosition(int position) const
|
|
|
|
|
{
|
|
|
|
|
// 两端准确对应首尾,中间位置不把六十四位总数截断为 int。
|
|
|
|
|
const int maximum = verticalScrollBar()->maximum();
|
|
|
|
|
if (position <= 0 || maximum == 0) return 0;
|
|
|
|
|
if (position >= maximum) return maximumFirst();
|
|
|
|
|
return qMin(maximumFirst(), quint64((long double)position * maximumFirst() / maximum));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void scrollRows(qint64 movement)
|
|
|
|
|
{
|
|
|
|
|
// 用差值限制移动距离,避免无符号行号在首尾发生溢出。
|
|
|
|
|
if (movement < 0) m_first -= qMin(m_first, quint64(-movement));
|
|
|
|
|
else m_first += qMin(maximumFirst() - m_first, quint64(movement));
|
|
|
|
|
refreshRows();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QString parameterDescription(int index, double value)
|
|
|
|
|
{
|
|
|
|
|
// 描述沿用采样表的三位有效数字和当前显示单位。
|
|
|
|
|
nmDataSensitive::VariableSampling& variable = m_data.getVariable(index);
|
|
|
|
|
const QString unit = variable.getModelValue().getUnit();
|
|
|
|
|
convertSamplingValue(variable.getVarName(), value, samplingBaseUnit(variable.getVarName()), unit, value);
|
|
|
|
|
return variable.getVarName() + " = " + formatSamplingValue(value, 3)
|
|
|
|
|
+ (unit.isEmpty() ? QString() : " " + unit);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void refreshRows()
|
|
|
|
|
{
|
|
|
|
|
if (m_updating || !m_table || !viewport()->layout()) return;
|
|
|
|
|
// 始终只生成视口内的行,所有组合共用一根连续滚动条。
|
|
|
|
|
m_updating = true;
|
|
|
|
|
viewport()->layout()->activate();
|
|
|
|
|
m_visibleRows = qMax(1, m_table->viewport()->height() / 24);
|
|
|
|
|
setVerticalScrollBarPolicy(m_total > quint64(m_visibleRows)
|
|
|
|
|
? Qt::ScrollBarAlwaysOn : Qt::ScrollBarAlwaysOff);
|
|
|
|
|
m_first = qMin(m_first, maximumFirst());
|
|
|
|
|
QScrollBar* bar = verticalScrollBar();
|
|
|
|
|
const quint64 last = maximumFirst();
|
|
|
|
|
const int maximum = int(qMin(last, quint64(INT_MAX)));
|
|
|
|
|
const bool blocked = bar->blockSignals(true);
|
|
|
|
|
bar->setRange(0, maximum);
|
|
|
|
|
bar->setSingleStep(1);
|
|
|
|
|
bar->setPageStep(last ? qMax(1, int((long double)m_visibleRows * maximum / last)) : m_visibleRows);
|
|
|
|
|
int position = last ? int((long double)m_first * maximum / last) : 0;
|
|
|
|
|
// 比例舍入后仍保留首尾箭头的可用状态。
|
|
|
|
|
if (last > quint64(INT_MAX) && m_first > 0 && m_first < last)
|
|
|
|
|
position = qBound(1, position, maximum - 1);
|
|
|
|
|
bar->setValue(position);
|
|
|
|
|
bar->blockSignals(blocked);
|
|
|
|
|
const int rows = int(qMin(quint64(m_visibleRows), m_total - m_first));
|
|
|
|
|
m_table->setRowCount(rows);
|
|
|
|
|
for (int row = 0; row < rows; ++row) {
|
|
|
|
|
const quint64 run = m_first + row;
|
|
|
|
|
QVector<double> values;
|
|
|
|
|
if (!m_data.getRunValues(run, values)) break;
|
|
|
|
|
int changingIndex = -1;
|
|
|
|
|
if (m_data.getCalculationType() == nmDataSensitive::CALC_DETERMINISTIC) {
|
|
|
|
|
quint64 remaining = run;
|
|
|
|
|
for (int i = 0; i < m_indices.size(); ++i) {
|
|
|
|
|
const quint64 count = m_data.getVariable(m_indices[i]).getNumber();
|
|
|
|
|
if (remaining < count) { changingIndex = m_indices[i]; break; }
|
|
|
|
|
remaining -= count;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
QStringList descriptions;
|
|
|
|
|
for (int i = 0; i < m_indices.size(); ++i) {
|
|
|
|
|
const int index = m_indices[i];
|
|
|
|
|
if (changingIndex < 0 || index == changingIndex)
|
|
|
|
|
descriptions << parameterDescription(index, values[index]);
|
|
|
|
|
}
|
|
|
|
|
QTableWidgetItem* arrow = new QTableWidgetItem();
|
|
|
|
|
arrow->setIcon(run == m_selected ? m_arrow : QIcon());
|
|
|
|
|
m_table->setItem(row, 0, arrow);
|
|
|
|
|
QTableWidgetItem* number = new QTableWidgetItem(QString::number(run + 1));
|
|
|
|
|
number->setTextAlignment(Qt::AlignRight | Qt::AlignVCenter);
|
|
|
|
|
m_table->setItem(row, 1, number);
|
|
|
|
|
QTableWidgetItem* description = new QTableWidgetItem(descriptions.join(" + "));
|
|
|
|
|
description->setToolTip(description->text());
|
|
|
|
|
m_table->setItem(row, 2, description);
|
|
|
|
|
}
|
|
|
|
|
if (m_selected >= m_first && m_selected - m_first < quint64(rows)) {
|
|
|
|
|
m_table->setCurrentCell(int(m_selected - m_first), 1);
|
|
|
|
|
m_table->selectRow(int(m_selected - m_first));
|
|
|
|
|
} else {
|
|
|
|
|
m_table->setCurrentIndex(QModelIndex());
|
|
|
|
|
m_table->clearSelection();
|
|
|
|
|
}
|
|
|
|
|
m_updating = false;
|
|
|
|
|
// 横向滚动条显隐可能改变视口高度,补齐最终可见行数量。
|
|
|
|
|
if (m_visibleRows != qMax(1, m_table->viewport()->height() / 24)) refreshRows();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
nmDataSensitive m_data;
|
|
|
|
|
QIcon m_arrow;
|
|
|
|
|
QTableWidget* m_table;
|
|
|
|
|
QList<int> m_indices;
|
|
|
|
|
quint64 m_total;
|
|
|
|
|
quint64 m_first;
|
|
|
|
|
quint64 m_selected;
|
|
|
|
|
int m_visibleRows;
|
|
|
|
|
bool m_updating;
|
|
|
|
|
int m_wheelDelta;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
nmWxSensitive::nmWxSensitive(QWidget *parent, nmDataAnalyzeManager* manager)
|
|
|
|
|
: iDlgBase(parent), m_selectedValueIndex(0), m_loading(true),
|
|
|
|
|
m_pDataManager(manager ? manager : nmDataAnalyzeManager::getCurrentInstance()),
|
|
|
|
|
m_previewTable(nullptr), m_previewPageEdit(nullptr), m_previewPageLabel(nullptr),
|
|
|
|
|
m_previewPage(0)
|
|
|
|
|
m_previewView(nullptr)
|
|
|
|
|
{
|
|
|
|
|
// 显式绑定所属分析窗口,后续切换窗口不会改变配置保存目标。
|
|
|
|
|
if (m_pDataManager) m_sensitiveData = m_pDataManager->getSensitiveDataCopy();
|
|
|
|
|
@ -1170,104 +1422,30 @@ void nmWxSensitive::onTreeItemClicked(QTreeWidgetItem* item, int column)
|
|
|
|
|
void nmWxSensitive::onPreviewClicked()
|
|
|
|
|
{
|
|
|
|
|
if (!saveDataFromUI()) return;
|
|
|
|
|
// 按页解码编号,组合数再大也只创建当前页的五十行。
|
|
|
|
|
// Saphir 风格的连续运行列表,组合数再大也不显示分页控件。
|
|
|
|
|
QDialog dialog(this);
|
|
|
|
|
dialog.setWindowTitle(tr("Sensitivity runs"));
|
|
|
|
|
dialog.resize(850, 500);
|
|
|
|
|
dialog.setWindowTitle(tr("Sensitivity Runs"));
|
|
|
|
|
dialog.setWindowFlags(dialog.windowFlags() & ~Qt::WindowContextHelpButtonHint);
|
|
|
|
|
dialog.setMinimumSize(420, 360);
|
|
|
|
|
dialog.resize(470, 650);
|
|
|
|
|
QVBoxLayout* layout = new QVBoxLayout(&dialog);
|
|
|
|
|
m_previewTable = new QTableWidget(&dialog);
|
|
|
|
|
m_previewTable->setEditTriggers(QAbstractItemView::NoEditTriggers);
|
|
|
|
|
layout->addWidget(m_previewTable);
|
|
|
|
|
QHBoxLayout* navigation = new QHBoxLayout();
|
|
|
|
|
QPushButton* previous = new QPushButton(&dialog);
|
|
|
|
|
previous->setIcon(style()->standardIcon(QStyle::SP_ArrowLeft));
|
|
|
|
|
previous->setToolTip(tr("Previous page"));
|
|
|
|
|
QPushButton* next = new QPushButton(&dialog);
|
|
|
|
|
next->setIcon(style()->standardIcon(QStyle::SP_ArrowRight));
|
|
|
|
|
next->setToolTip(tr("Next page"));
|
|
|
|
|
m_previewPageEdit = new QLineEdit(&dialog);
|
|
|
|
|
m_previewPageEdit->setFixedWidth(180);
|
|
|
|
|
m_previewPageLabel = new QLabel(&dialog);
|
|
|
|
|
navigation->addWidget(previous);
|
|
|
|
|
navigation->addWidget(m_previewPageEdit);
|
|
|
|
|
navigation->addWidget(m_previewPageLabel);
|
|
|
|
|
navigation->addWidget(next);
|
|
|
|
|
navigation->addStretch();
|
|
|
|
|
layout->addLayout(navigation);
|
|
|
|
|
layout->setContentsMargins(16, 16, 16, 12);
|
|
|
|
|
layout->setSpacing(8);
|
|
|
|
|
m_previewView = new SensitivityRunsView(m_sensitiveData, createTriangleIcon(), &dialog);
|
|
|
|
|
layout->addWidget(m_previewView);
|
|
|
|
|
QDialogButtonBox* buttons = new QDialogButtonBox(QDialogButtonBox::Close, Qt::Horizontal, &dialog);
|
|
|
|
|
buttons->setCenterButtons(true);
|
|
|
|
|
buttons->button(QDialogButtonBox::Close)->setMinimumWidth(110);
|
|
|
|
|
layout->addWidget(buttons);
|
|
|
|
|
connect(buttons, SIGNAL(rejected()), &dialog, SLOT(reject()));
|
|
|
|
|
connect(previous, SIGNAL(clicked()), this, SLOT(onPreviewPrevious()));
|
|
|
|
|
connect(next, SIGNAL(clicked()), this, SLOT(onPreviewNext()));
|
|
|
|
|
connect(m_previewPageEdit, SIGNAL(returnPressed()), this, SLOT(onPreviewJump()));
|
|
|
|
|
m_previewPage = 0;
|
|
|
|
|
refreshPreviewPage();
|
|
|
|
|
connect(m_previewView->verticalScrollBar(), SIGNAL(actionTriggered(int)),
|
|
|
|
|
this, SLOT(onPreviewScrollAction(int)));
|
|
|
|
|
dialog.exec();
|
|
|
|
|
m_previewTable = nullptr;
|
|
|
|
|
m_previewPageEdit = nullptr;
|
|
|
|
|
m_previewPageLabel = nullptr;
|
|
|
|
|
m_previewView = nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void nmWxSensitive::refreshPreviewPage()
|
|
|
|
|
void nmWxSensitive::onPreviewScrollAction(int action)
|
|
|
|
|
{
|
|
|
|
|
// 参数列与计算数据共用 getRunValues,单变量运行的其他参数显示基准值。
|
|
|
|
|
if (!m_previewTable) return;
|
|
|
|
|
QStringList headers;
|
|
|
|
|
headers << tr("Run");
|
|
|
|
|
QList<int> selected;
|
|
|
|
|
for (int i = 0; i < m_sensitiveData.getVariableCount(); ++i) {
|
|
|
|
|
nmDataSensitive::VariableSampling& variable = m_sensitiveData.getVariable(i);
|
|
|
|
|
if (!variable.getEnabled()) continue;
|
|
|
|
|
selected.append(i);
|
|
|
|
|
const QString unit = variable.getModelValue().getUnit();
|
|
|
|
|
headers << variable.getVarName() + (unit.isEmpty() ? QString() : " (" + unit + ")");
|
|
|
|
|
}
|
|
|
|
|
m_previewTable->clear();
|
|
|
|
|
m_previewTable->setColumnCount(headers.size());
|
|
|
|
|
m_previewTable->setHorizontalHeaderLabels(headers);
|
|
|
|
|
const quint64 total = m_sensitiveData.getTotalModelCount();
|
|
|
|
|
const quint64 first = m_previewPage * 50;
|
|
|
|
|
const int rows = int(qMin(quint64(50), total - first));
|
|
|
|
|
m_previewTable->setRowCount(rows);
|
|
|
|
|
for (int row = 0; row < rows; ++row) {
|
|
|
|
|
QVector<double> values;
|
|
|
|
|
if (!m_sensitiveData.getRunValues(first + row, values)) break;
|
|
|
|
|
m_previewTable->setItem(row, 0, new QTableWidgetItem(QString::number(first + row + 1)));
|
|
|
|
|
for (int column = 0; column < selected.size(); ++column) {
|
|
|
|
|
const int index = selected[column];
|
|
|
|
|
nmDataSensitive::VariableSampling& variable = m_sensitiveData.getVariable(index);
|
|
|
|
|
double display = values[index];
|
|
|
|
|
convertSamplingValue(variable.getVarName(), display, samplingBaseUnit(variable.getVarName()),
|
|
|
|
|
variable.getModelValue().getUnit(), display);
|
|
|
|
|
QTableWidgetItem* item = new QTableWidgetItem(formatSamplingValue(display, 3));
|
|
|
|
|
item->setToolTip(formatSamplingValue(display, 6));
|
|
|
|
|
item->setTextAlignment(Qt::AlignRight | Qt::AlignVCenter);
|
|
|
|
|
m_previewTable->setItem(row, column + 1, item);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
m_previewTable->resizeColumnsToContents();
|
|
|
|
|
m_previewPageEdit->setText(QString::number(m_previewPage + 1));
|
|
|
|
|
m_previewPageLabel->setText(tr("/ %1 pages; %2 runs").arg((total - 1) / 50 + 1).arg(total));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void nmWxSensitive::onPreviewPrevious()
|
|
|
|
|
{
|
|
|
|
|
if (m_previewPage > 0) --m_previewPage;
|
|
|
|
|
refreshPreviewPage();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void nmWxSensitive::onPreviewNext()
|
|
|
|
|
{
|
|
|
|
|
if ((m_previewPage + 1) * 50 < m_sensitiveData.getTotalModelCount()) ++m_previewPage;
|
|
|
|
|
refreshPreviewPage();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void nmWxSensitive::onPreviewJump()
|
|
|
|
|
{
|
|
|
|
|
// 允许直接跳转到大批量组合中的指定页,页码使用六十四位整数。
|
|
|
|
|
bool ok = false;
|
|
|
|
|
const quint64 page = m_previewPageEdit->text().trimmed().toULongLong(&ok);
|
|
|
|
|
const quint64 pages = (m_sensitiveData.getTotalModelCount() - 1) / 50 + 1;
|
|
|
|
|
if (ok && page > 0 && page <= pages) m_previewPage = page - 1;
|
|
|
|
|
refreshPreviewPage();
|
|
|
|
|
// 将原生滚动条的单步、整屏和拖动操作转交连续列表。
|
|
|
|
|
if (m_previewView) m_previewView->scrollAction(action);
|
|
|
|
|
}
|
|
|
|
|
|