|
|
|
|
@ -48,6 +48,8 @@
|
|
|
|
|
#include <QKeyEvent>
|
|
|
|
|
#include <QMouseEvent>
|
|
|
|
|
#include <QHeaderView>
|
|
|
|
|
#include <QStyleOptionButton>
|
|
|
|
|
#include <QStyleOptionHeader>
|
|
|
|
|
#include <QSplitter>
|
|
|
|
|
|
|
|
|
|
#include <QVBoxLayout>
|
|
|
|
|
@ -216,6 +218,12 @@ public:
|
|
|
|
|
iGuiPlot* plot, QObject* parent, bool statistics = false)
|
|
|
|
|
: QAbstractTableModel(parent), m_results(results), m_plot(plot), m_statistics(statistics) {}
|
|
|
|
|
|
|
|
|
|
~SensitivityResultsModel()
|
|
|
|
|
{
|
|
|
|
|
// 直接销毁 Show 窗口时也恢复原色。
|
|
|
|
|
highlightRun(-1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QList<ZxObjCurve*> runCurves(int row) const
|
|
|
|
|
{
|
|
|
|
|
// 双对数图的一组包含压力与导数,历史压力图只包含压力。
|
|
|
|
|
@ -252,7 +260,20 @@ public:
|
|
|
|
|
QVariant headerData(int section, Qt::Orientation orientation, int role) const override
|
|
|
|
|
{
|
|
|
|
|
// 表格仅保留显示选择、运行编号与冻结参数。
|
|
|
|
|
if(orientation != Qt::Horizontal || role != Qt::DisplayRole) return QVariant();
|
|
|
|
|
if(orientation != Qt::Horizontal) return QVariant();
|
|
|
|
|
if(!m_statistics && section == 0 && role == Qt::CheckStateRole) {
|
|
|
|
|
// 全选状态只统计确实有曲线、允许勾选的运行。
|
|
|
|
|
int total = 0, checked = 0;
|
|
|
|
|
for(int row = 0; row < rowCount(); ++row) {
|
|
|
|
|
const QModelIndex cell = index(row, 0);
|
|
|
|
|
if(!(flags(cell) & Qt::ItemIsUserCheckable)) continue;
|
|
|
|
|
++total;
|
|
|
|
|
if(data(cell, Qt::CheckStateRole).toInt() == Qt::Checked) ++checked;
|
|
|
|
|
}
|
|
|
|
|
if(!total) return QVariant();
|
|
|
|
|
return checked == total ? Qt::Checked : checked == 0 ? Qt::Unchecked : Qt::PartiallyChecked;
|
|
|
|
|
}
|
|
|
|
|
if(role != Qt::DisplayRole) return QVariant();
|
|
|
|
|
if(m_statistics) {
|
|
|
|
|
if(section >= 3 && section - 3 < m_results->m_fitParameters.size()) {
|
|
|
|
|
const nmDataAttribute& parameter = m_results->m_fitParameters[section - 3];
|
|
|
|
|
@ -315,6 +336,7 @@ public:
|
|
|
|
|
if(visible == isRunVisible(index.row())) m_pendingVisibility.remove(index.row());
|
|
|
|
|
else m_pendingVisibility.insert(index.row(), visible);
|
|
|
|
|
emit dataChanged(index, index);
|
|
|
|
|
emit headerDataChanged(Qt::Horizontal, 0, 0);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@ -329,6 +351,7 @@ public:
|
|
|
|
|
else m_pendingVisibility.insert(i, visible);
|
|
|
|
|
}
|
|
|
|
|
emit dataChanged(index(0, 0), index(rowCount() - 1, 0));
|
|
|
|
|
emit headerDataChanged(Qt::Horizontal, 0, 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void applyVisibility()
|
|
|
|
|
@ -346,13 +369,103 @@ public:
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void highlightRun(int row)
|
|
|
|
|
{
|
|
|
|
|
// 绘图窗口已销毁时,残留图元的坐标轴也已失效,不能再修改样式。
|
|
|
|
|
if(m_plot.isNull()) { m_highlightStyles.clear(); return; }
|
|
|
|
|
// 高亮不改曲线数据或可见性,先恢复原色再淡化其他采样与基准曲线。
|
|
|
|
|
for(int i = 0; i < m_highlightStyles.size(); ++i) {
|
|
|
|
|
const HighlightStyle& style = m_highlightStyles[i];
|
|
|
|
|
if(style.curve.isNull()) continue;
|
|
|
|
|
style.curve->setPen(style.pen);
|
|
|
|
|
style.curve->setDot(style.dot);
|
|
|
|
|
}
|
|
|
|
|
m_highlightStyles.clear();
|
|
|
|
|
if(row >= 0 && row < rowCount()) {
|
|
|
|
|
QList<ZxObjCurve*> dimmed;
|
|
|
|
|
for(int other = 0; other < rowCount(); ++other) {
|
|
|
|
|
if(other == row) continue;
|
|
|
|
|
dimmed.append(runCurves(other));
|
|
|
|
|
}
|
|
|
|
|
// 双对数的基准压力、导数和历史图的基准压力共用样式恢复逻辑。
|
|
|
|
|
if(ZxObjCurve* base = m_plot->getCurve(nmWxSensitive::tr("Base model - Pressure"))) dimmed.append(base);
|
|
|
|
|
if(ZxObjCurve* base = m_plot->getCurve(nmWxSensitive::tr("Base model - Derivative"))) dimmed.append(base);
|
|
|
|
|
for(int i = 0; i < dimmed.size(); ++i) {
|
|
|
|
|
HighlightStyle style;
|
|
|
|
|
style.curve = dimmed[i];
|
|
|
|
|
style.pen = dimmed[i]->getPen();
|
|
|
|
|
style.dot = dimmed[i]->getDot();
|
|
|
|
|
m_highlightStyles.append(style);
|
|
|
|
|
dimmed[i]->setColor(QColor(210, 210, 210));
|
|
|
|
|
dimmed[i]->setDotColor(QColor(210, 210, 210));
|
|
|
|
|
}
|
|
|
|
|
// 重合曲线也能看清选中组,压力和导数一同放到上层。
|
|
|
|
|
const QList<ZxObjCurve*> selected = runCurves(row);
|
|
|
|
|
for(int i = 0; i < selected.size(); ++i) m_plot->m_pPlot->bringToFront(selected[i]);
|
|
|
|
|
}
|
|
|
|
|
if(!m_plot.isNull()) m_plot->m_pPlot->update();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
struct HighlightStyle {
|
|
|
|
|
QPointer<ZxObjCurve> curve;
|
|
|
|
|
QPen pen;
|
|
|
|
|
ZxDot dot;
|
|
|
|
|
};
|
|
|
|
|
QVector<HighlightStyle> m_highlightStyles;
|
|
|
|
|
QSharedPointer<nmDataSensitive::BatchResult> m_results;
|
|
|
|
|
QMap<int, bool> m_pendingVisibility;
|
|
|
|
|
QPointer<iGuiPlot> m_plot;
|
|
|
|
|
bool m_statistics;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
class SensitivityShowHeader : public QHeaderView
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
explicit SensitivityShowHeader(QWidget* parent) : QHeaderView(Qt::Horizontal, parent) {}
|
|
|
|
|
protected:
|
|
|
|
|
QSize sectionSizeFromContents(int section) const override
|
|
|
|
|
{
|
|
|
|
|
// Show 列额外留出原生复选框的宽度。
|
|
|
|
|
QSize size = QHeaderView::sectionSizeFromContents(section);
|
|
|
|
|
if(section == 0) size.rwidth() += style()->pixelMetric(QStyle::PM_IndicatorWidth) + 8;
|
|
|
|
|
return size;
|
|
|
|
|
}
|
|
|
|
|
void paintSection(QPainter* painter, const QRect& rect, int section) const override
|
|
|
|
|
{
|
|
|
|
|
// 仅替换第一列表头,其他列沿用原来的标题与样式。
|
|
|
|
|
if(section != 0) { QHeaderView::paintSection(painter, rect, section); return; }
|
|
|
|
|
QStyleOptionHeader header;
|
|
|
|
|
initStyleOption(&header);
|
|
|
|
|
header.rect = rect;
|
|
|
|
|
header.text.clear();
|
|
|
|
|
painter->save();
|
|
|
|
|
style()->drawControl(QStyle::CE_Header, &header, painter, this);
|
|
|
|
|
painter->restore();
|
|
|
|
|
QStyleOptionButton check;
|
|
|
|
|
check.initFrom(this);
|
|
|
|
|
check.rect = rect.adjusted(4, 0, -2, 0);
|
|
|
|
|
check.text = model()->headerData(0, Qt::Horizontal).toString();
|
|
|
|
|
const QVariant state = model()->headerData(0, Qt::Horizontal, Qt::CheckStateRole);
|
|
|
|
|
if(!state.isValid()) check.state &= ~QStyle::State_Enabled;
|
|
|
|
|
check.state |= state.toInt() == Qt::Checked ? QStyle::State_On
|
|
|
|
|
: state.toInt() == Qt::PartiallyChecked ? QStyle::State_NoChange : QStyle::State_Off;
|
|
|
|
|
painter->save();
|
|
|
|
|
style()->drawControl(QStyle::CE_CheckBox, &check, painter, this);
|
|
|
|
|
painter->restore();
|
|
|
|
|
}
|
|
|
|
|
void mousePressEvent(QMouseEvent* event) override
|
|
|
|
|
{
|
|
|
|
|
// 部分选中时点击全选;全选时点击取消,全程沿用待应用选择。
|
|
|
|
|
if(event->button() == Qt::LeftButton && logicalIndexAt(event->pos()) == 0) {
|
|
|
|
|
const QVariant state = model()->headerData(0, Qt::Horizontal, Qt::CheckStateRole);
|
|
|
|
|
if(state.isValid()) static_cast<SensitivityResultsModel*>(model())->setAllVisible(state.toInt() != Qt::Checked);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
QHeaderView::mousePressEvent(event);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
nmWxSensitivityShow::nmWxSensitivityShow(
|
|
|
|
|
const QSharedPointer<nmDataSensitive::BatchResult>& results, iGuiPlot* plot, QWidget* parent)
|
|
|
|
|
: iDlgBase(parent)
|
|
|
|
|
@ -362,9 +475,10 @@ nmWxSensitivityShow::nmWxSensitivityShow(
|
|
|
|
|
setObjectName("nmSensitivityShowDialog");
|
|
|
|
|
resize(700, 380);
|
|
|
|
|
QVBoxLayout* layout = new QVBoxLayout(this);
|
|
|
|
|
QTableView* table = new QTableView(this);
|
|
|
|
|
QTableView* table = m_table = new QTableView(this);
|
|
|
|
|
table->setStyleSheet("QTableView { background-color: white; }");
|
|
|
|
|
m_model = new SensitivityResultsModel(results, plot, this);
|
|
|
|
|
table->setHorizontalHeader(new SensitivityShowHeader(table));
|
|
|
|
|
table->setModel(m_model);
|
|
|
|
|
table->setSelectionBehavior(QAbstractItemView::SelectRows);
|
|
|
|
|
table->setSelectionMode(QAbstractItemView::SingleSelection);
|
|
|
|
|
@ -376,8 +490,10 @@ nmWxSensitivityShow::nmWxSensitivityShow(
|
|
|
|
|
table->horizontalHeader()->setResizeMode(2, QHeaderView::Stretch);
|
|
|
|
|
layout->addWidget(table);
|
|
|
|
|
QHBoxLayout* buttons = new QHBoxLayout();
|
|
|
|
|
QPushButton* showAll = new QPushButton(tr("Show all"), this);
|
|
|
|
|
QPushButton* hideAll = new QPushButton(tr("Hide all"), this);
|
|
|
|
|
m_highlight = new QPushButton(tr("Highlight"), this);
|
|
|
|
|
m_highlight->setCheckable(true);
|
|
|
|
|
m_highlight->setAutoDefault(false);
|
|
|
|
|
m_highlight->setToolTip(tr("Highlight the selected run; click again to restore colors."));
|
|
|
|
|
// 明确按钮顺序,避免系统的标准按钮布局把 Apply 排到最后。
|
|
|
|
|
QPushButton* apply = new QPushButton(tr("Apply"), this);
|
|
|
|
|
QPushButton* ok = new QPushButton(tr("OK"), this);
|
|
|
|
|
@ -385,18 +501,26 @@ nmWxSensitivityShow::nmWxSensitivityShow(
|
|
|
|
|
apply->setAutoDefault(false);
|
|
|
|
|
cancel->setAutoDefault(false);
|
|
|
|
|
ok->setDefault(true);
|
|
|
|
|
buttons->addWidget(showAll);
|
|
|
|
|
buttons->addWidget(hideAll);
|
|
|
|
|
buttons->addWidget(m_highlight);
|
|
|
|
|
buttons->addStretch();
|
|
|
|
|
buttons->addWidget(apply);
|
|
|
|
|
buttons->addWidget(ok);
|
|
|
|
|
buttons->addWidget(cancel);
|
|
|
|
|
layout->addLayout(buttons);
|
|
|
|
|
connect(showAll, SIGNAL(clicked()), this, SLOT(onShowAll()));
|
|
|
|
|
connect(hideAll, SIGNAL(clicked()), this, SLOT(onHideAll()));
|
|
|
|
|
connect(m_highlight, SIGNAL(toggled(bool)), this, SLOT(updateHighlight()));
|
|
|
|
|
connect(table->selectionModel(), SIGNAL(currentRowChanged(QModelIndex,QModelIndex)), this, SLOT(updateHighlight()));
|
|
|
|
|
connect(m_model, SIGNAL(dataChanged(QModelIndex,QModelIndex)), this, SLOT(updateHighlight()));
|
|
|
|
|
connect(apply, SIGNAL(clicked()), this, SLOT(onApply()));
|
|
|
|
|
connect(ok, SIGNAL(clicked()), this, SLOT(onAccept()));
|
|
|
|
|
connect(cancel, SIGNAL(clicked()), this, SLOT(reject()));
|
|
|
|
|
updateHighlight();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void nmWxSensitivityShow::done(int result)
|
|
|
|
|
{
|
|
|
|
|
// 确认、取消及关闭都结束临时高亮,不改变已应用的显示选择。
|
|
|
|
|
m_model->highlightRun(-1);
|
|
|
|
|
iDlgBase::done(result);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void nmWxSensitivityShow::onApply()
|
|
|
|
|
@ -412,16 +536,19 @@ void nmWxSensitivityShow::onAccept()
|
|
|
|
|
accept();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void nmWxSensitivityShow::onShowAll()
|
|
|
|
|
{
|
|
|
|
|
// 只修改待应用的采样组选择。
|
|
|
|
|
m_model->setAllVisible(true);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void nmWxSensitivityShow::onHideAll()
|
|
|
|
|
void nmWxSensitivityShow::updateHighlight()
|
|
|
|
|
{
|
|
|
|
|
// 参考曲线不属于采样组,保持原来的显示方式。
|
|
|
|
|
m_model->setAllVisible(false);
|
|
|
|
|
// 只有当前选中且勾选显示的有效运行可以高亮,切换行时同步跟随。
|
|
|
|
|
const QModelIndex cell = m_model->index(m_table->currentIndex().row(), 0);
|
|
|
|
|
const bool enabled = (m_model->flags(cell) & Qt::ItemIsUserCheckable)
|
|
|
|
|
&& m_model->data(cell, Qt::CheckStateRole).toInt() == Qt::Checked;
|
|
|
|
|
m_highlight->setEnabled(enabled);
|
|
|
|
|
if(!enabled) {
|
|
|
|
|
m_highlight->blockSignals(true);
|
|
|
|
|
m_highlight->setChecked(false);
|
|
|
|
|
m_highlight->blockSignals(false);
|
|
|
|
|
}
|
|
|
|
|
m_model->highlightRun(enabled && m_highlight->isChecked() ? cell.row() : -1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
nmWxSensitivityHistogramOptions::nmWxSensitivityHistogramOptions(
|
|
|
|
|
|