You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
nmWTAI-Platform/Src/nmNum/nmSubWxs/nmParameterField.cpp

538 lines
15 KiB
C++

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

#include "nmParameterField.h"
#include "iParaItemCtrl.h"
#include "iParameter.h"
#include "iSysParaHelper.h"
#include "mModuleDefines.h"
#include <QComboBox>
#include <QCoreApplication>
#include <QGridLayout>
#include <QLabel>
#include <QLineEdit>
#include <QPalette>
#include <QSizePolicy>
namespace
{
/* Qt 4.8的lupdate需要显式标记间接翻译字符串。 */
static const char* const s_pFieldTranslationMarkers[] =
{
QT_TRANSLATE_NOOP("nmParameterField", "The parameter layout is unavailable."),
QT_TRANSLATE_NOOP("nmParameterField", "Parameter definition not found: %1"),
QT_TRANSLATE_NOOP("nmParameterField", "Failed to bind the unit for parameter: %1")
};
QString fieldText(const char* pText)
{
Q_UNUSED(s_pFieldTranslationMarkers);
return QCoreApplication::translate("nmParameterField", pText);
}
QString validationToolTip(const QString& sText, bool bValid)
{
if (bValid)
{
return sText;
}
// 无效提示使用富文本着色业务文本必须先转义以免被当作HTML解析。
QString sEscaped = sText;
sEscaped.replace("&", "&amp;");
sEscaped.replace("<", "&lt;");
sEscaped.replace(">", "&gt;");
sEscaped.replace("\"", "&quot;");
sEscaped.replace("\n", "<br/>");
return "<span style=\"color:red;\">" + sEscaped + "</span>";
}
}
nmParameterFieldInfo::nmParameterFieldInfo()
: m_eEditorType(NM_PARAMETER_EDITOR_NUMBER),
m_bUnitEnabled(true)
{
}
nmParameterField::nmParameterField(
const nmParameterFieldInfo& oFieldInfo,
nmIParameterUnitService* pUnitService,
QObject* pParent)
: QObject(pParent),
m_oFieldInfo(oFieldInfo),
m_pUnitService(pUnitService),
m_pParameter(nullptr),
m_pLabel(nullptr),
m_pLineEdit(nullptr),
m_pValueComboBox(nullptr),
m_pUnitComboBox(nullptr),
m_pUnitLabel(nullptr),
m_clrNormalText(),
m_sExternalValidationError(),
m_bVisible(true)
{
}
nmParameterField::~nmParameterField()
{
m_pUnitService = nullptr;
m_pParameter = nullptr;
m_pLabel = nullptr;
m_pLineEdit = nullptr;
m_pValueComboBox = nullptr;
m_pUnitComboBox = nullptr;
m_pUnitLabel = nullptr;
}
bool nmParameterField::initialize(QGridLayout* pLayout,
int nRow,
int nColumnOffset,
QString& sError)
{
if (pLayout == nullptr)
{
sError = fieldText("The parameter layout is unavailable.");
return false;
}
// 第一步文本和枚举字段不依赖XML数值定义。
if (isText())
{
createTextEditor(pLayout, nRow, nColumnOffset);
sError.clear();
return true;
}
if (isEnum())
{
createEnumEditor(pLayout, nRow, nColumnOffset);
sError.clear();
return true;
}
// 第二步数值字段取得NM系列的基础参数定义。
m_pParameter = _paraHelper->getPara(
m_oFieldInfo.m_sBaseParameterId, s_Nm_Serie);
if (m_pParameter == nullptr)
{
sError = fieldText("Parameter definition not found: %1")
.arg(m_oFieldInfo.m_sBaseParameterId);
return false;
}
// 第三步:创建标签、输入框和单位列。
return createNumericEditor(pLayout, nRow, nColumnOffset, sError);
}
QString nmParameterField::parameterId() const
{
return m_oFieldInfo.m_sParameterId;
}
QString nmParameterField::baseParameterId() const
{
return m_oFieldInfo.m_sBaseParameterId;
}
bool nmParameterField::isEnum() const
{
return m_oFieldInfo.m_eEditorType == NM_PARAMETER_EDITOR_ENUM;
}
bool nmParameterField::isText() const
{
return m_oFieldInfo.m_eEditorType == NM_PARAMETER_EDITOR_TEXT;
}
void nmParameterField::setValueRightAligned(bool bRightAligned)
{
if (m_pLineEdit != nullptr)
{
m_pLineEdit->setAlignment(
(bRightAligned ? Qt::AlignRight : Qt::AlignLeft) |
Qt::AlignVCenter);
}
}
int nmParameterField::editorMinimumWidth()
{
return 140;
}
int nmParameterField::unitMinimumWidth()
{
return 86;
}
int nmParameterField::editorHeight()
{
return 25;
}
bool nmParameterField::createNumericEditor(
QGridLayout* pLayout,
int nRow,
int nColumnOffset,
QString& sError)
{
// 第一步:创建统一尺寸的标签和值输入框,保证各业务面板列对齐。
QWidget* pParentWidget = pLayout->parentWidget();
m_pLabel = new QLabel(m_pParameter->m_sAlias, pParentWidget);
m_pLabel->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
m_pLabel->setWordWrap(false);
m_pLabel->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
m_pLineEdit = new QLineEdit(pParentWidget);
m_clrNormalText = m_pLineEdit->palette().color(QPalette::Text);
m_pLineEdit->setAlignment(Qt::AlignLeft | Qt::AlignVCenter);
m_pLineEdit->setFixedHeight(editorHeight());
m_pLineEdit->setMinimumWidth(editorMinimumWidth());
m_pLineEdit->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
pLayout->addWidget(m_pLabel, nRow, nColumnOffset);
pLayout->addWidget(m_pLineEdit, nRow, nColumnOffset + 1);
// 第二步:有单位字段交给窗口服务绑定;无单位字段保留占位列。
if (m_oFieldInfo.m_bUnitEnabled &&
!m_pParameter->m_sUnit.isEmpty())
{
m_pUnitComboBox = new QComboBox(pParentWidget);
m_pUnitComboBox->setFixedHeight(editorHeight());
m_pUnitComboBox->setMinimumWidth(unitMinimumWidth());
m_pUnitComboBox->setSizePolicy(QSizePolicy::Expanding,
QSizePolicy::Fixed);
pLayout->addWidget(m_pUnitComboBox, nRow, nColumnOffset + 2);
if (m_pUnitService == nullptr ||
!m_pUnitService->bindUnitField(
m_pLineEdit,
m_pUnitComboBox,
m_oFieldInfo.m_sBaseParameterId))
{
sError = fieldText(
"Failed to bind the unit for parameter: %1")
.arg(m_oFieldInfo.m_sBaseParameterId);
return false;
}
}
else
{
m_pUnitLabel = new QLabel(pParentWidget);
m_pUnitLabel->setMinimumWidth(unitMinimumWidth());
m_pUnitLabel->setSizePolicy(QSizePolicy::Expanding,
QSizePolicy::Fixed);
pLayout->addWidget(m_pUnitLabel, nRow, nColumnOffset + 2);
}
updateValidationAppearance(true);
sError.clear();
return true;
}
void nmParameterField::createTextEditor(QGridLayout* pLayout,
int nRow,
int nColumnOffset)
{
QWidget* pParentWidget = pLayout->parentWidget();
m_pLabel = new QLabel(m_oFieldInfo.m_sLabel, pParentWidget);
m_pLabel->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
m_pLabel->setWordWrap(false);
m_pLineEdit = new QLineEdit(pParentWidget);
m_clrNormalText = m_pLineEdit->palette().color(QPalette::Text);
m_pLineEdit->setFixedHeight(editorHeight());
m_pLineEdit->setMinimumWidth(editorMinimumWidth());
m_pLineEdit->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
m_pUnitLabel = new QLabel(pParentWidget);
m_pUnitLabel->setMinimumWidth(unitMinimumWidth());
m_pUnitLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
pLayout->addWidget(m_pLabel, nRow, nColumnOffset);
pLayout->addWidget(m_pLineEdit, nRow, nColumnOffset + 1);
pLayout->addWidget(m_pUnitLabel, nRow, nColumnOffset + 2);
}
void nmParameterField::createEnumEditor(QGridLayout* pLayout,
int nRow,
int nColumnOffset)
{
QWidget* pParentWidget = pLayout->parentWidget();
m_pLabel = new QLabel(m_oFieldInfo.m_sLabel, pParentWidget);
m_pLabel->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
m_pLabel->setWordWrap(false);
m_pValueComboBox = new QComboBox(pParentWidget);
m_pValueComboBox->setFixedHeight(editorHeight());
m_pValueComboBox->setMinimumWidth(editorMinimumWidth());
m_pValueComboBox->setSizePolicy(QSizePolicy::Expanding,
QSizePolicy::Fixed);
for (int nIndex = 0;
nIndex < m_oFieldInfo.m_listOptions.size();
++nIndex)
{
const nmParameterEnumOption& oOption =
m_oFieldInfo.m_listOptions[nIndex];
m_pValueComboBox->addItem(oOption.m_sText, oOption.m_sCode);
}
m_pUnitLabel = new QLabel(pParentWidget);
m_pUnitLabel->setMinimumWidth(unitMinimumWidth());
m_pUnitLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
pLayout->addWidget(m_pLabel, nRow, nColumnOffset);
pLayout->addWidget(m_pValueComboBox, nRow, nColumnOffset + 1);
pLayout->addWidget(m_pUnitLabel, nRow, nColumnOffset + 2);
}
void nmParameterField::setBaseValue(const QVariant& oValue)
{
if (m_pLineEdit == nullptr || !oValue.isValid())
{
return;
}
// 程序回填仍走控件标准写值接口,由所属页面的刷新标记屏蔽业务提交。
if (isText())
{
m_pLineEdit->setText(oValue.toString());
}
else if (m_pUnitComboBox != nullptr && m_pUnitService != nullptr)
{
m_pUnitService->setUnitBaseValue(
m_pLineEdit, oValue.toDouble());
}
else
{
m_pLineEdit->setText(formatBaseValue(oValue.toDouble()));
}
validate();
}
QVariant nmParameterField::baseValue(bool& bValid)
{
bValid = validate();
if (!bValid || m_pLineEdit == nullptr)
{
return QVariant();
}
// 单位字段始终向业务层返回基准单位值,界面显示单位不进入数据模型。
if (isText())
{
return QVariant(m_pLineEdit->text().trimmed());
}
if (m_pUnitComboBox != nullptr && m_pUnitService != nullptr)
{
return QVariant(m_pUnitService->unitBaseValue(m_pLineEdit));
}
bool bNumberOk = false;
double dValue = m_pLineEdit->text().trimmed().toDouble(&bNumberOk);
return bNumberOk ? QVariant(dValue) : QVariant();
}
void nmParameterField::setEnumCode(const QString& sCode)
{
if (m_pValueComboBox == nullptr)
{
return;
}
int nIndex = m_pValueComboBox->findData(sCode);
m_pValueComboBox->setCurrentIndex(nIndex >= 0 ? nIndex : 0);
}
QString nmParameterField::enumCode() const
{
if (m_pValueComboBox == nullptr ||
m_pValueComboBox->currentIndex() < 0)
{
return QString();
}
return m_pValueComboBox->itemData(
m_pValueComboBox->currentIndex()).toString();
}
void nmParameterField::setExternalValidationError(const QString& sError)
{
m_sExternalValidationError = sError;
validate();
}
bool nmParameterField::validate()
{
if (!m_bVisible || isEnum())
{
return true;
}
if (m_pLineEdit == nullptr)
{
return false;
}
// 第一步:按编辑器类型执行本地格式、范围和整数约束校验。
bool bValid = false;
if (isText())
{
bValid = true;
}
else if (m_pParameter == nullptr)
{
bValid = false;
}
else if (m_pUnitComboBox != nullptr && m_pUnitService != nullptr)
{
bValid = m_pUnitService->isUnitInputValid(m_pLineEdit);
}
else
{
bool bNumberOk = false;
double dValue = m_pLineEdit->text().trimmed()
.toDouble(&bNumberOk);
bValid = bNumberOk && dValue == dValue &&
dValue >= m_pParameter->m_dMin &&
dValue <= m_pParameter->m_dMax;
if (bValid &&
m_oFieldInfo.m_eEditorType == NM_PARAMETER_EDITOR_INTEGER)
{
bValid = dValue == static_cast<int>(dValue);
}
}
// 第二步:叠加面板提供的跨字段业务规则,例如射孔区间关系。
bValid = bValid && m_sExternalValidationError.isEmpty();
updateValidationAppearance(bValid);
return bValid;
}
void nmParameterField::setFieldVisible(bool bVisible)
{
m_bVisible = bVisible;
if (m_pLabel != nullptr)
{
m_pLabel->setVisible(bVisible);
}
if (m_pLineEdit != nullptr)
{
m_pLineEdit->setVisible(bVisible);
}
if (m_pValueComboBox != nullptr)
{
m_pValueComboBox->setVisible(bVisible);
}
if (m_pUnitComboBox != nullptr)
{
m_pUnitComboBox->setVisible(bVisible);
}
if (m_pUnitLabel != nullptr)
{
m_pUnitLabel->setVisible(bVisible);
}
}
bool nmParameterField::isFieldVisible() const
{
return m_bVisible;
}
QLineEdit* nmParameterField::valueEditor() const
{
return m_pLineEdit;
}
QComboBox* nmParameterField::enumEditor() const
{
return m_pValueComboBox;
}
QString nmParameterField::formatBaseValue(double dValue) const
{
if (m_pParameter == nullptr)
{
return QString::number(dValue, 'g', 15);
}
if (m_oFieldInfo.m_eEditorType == NM_PARAMETER_EDITOR_INTEGER ||
m_pParameter->m_nDigit == 0)
{
return QString::number(dValue, 'f', 0);
}
if (m_pParameter->m_bScientific)
{
return QString::number(dValue, 'e', m_pParameter->m_nDigit);
}
// 普通小数去除无意义尾零,避免界面出现与有效精度无关的冗长数字。
QString sValue = QString::number(
dValue, 'f', m_pParameter->m_nDigit);
while (sValue.contains('.') && sValue.endsWith('0'))
{
sValue.chop(1);
}
if (sValue.endsWith('.'))
{
sValue.chop(1);
}
return sValue;
}
void nmParameterField::updateValidationAppearance(bool bValid)
{
if (m_pLineEdit == nullptr)
{
return;
}
// 第一步:只调整文字颜色,不覆盖应用主题提供的输入框背景和边框。
QPalette oPalette = m_pLineEdit->palette();
oPalette.setColor(QPalette::Text,
bValid ? m_clrNormalText : QColor(Qt::red));
m_pLineEdit->setPalette(oPalette);
// 第二步:组合参数名称、当前单位范围和跨字段错误作为统一帮助信息。
QString sHelp = m_oFieldInfo.m_sLabel;
if (m_pParameter != nullptr)
{
QString sCurrentUnit;
iUnitGroup* pUnitGroup = nullptr;
if (m_pUnitComboBox != nullptr && m_pUnitService != nullptr)
{
sCurrentUnit = m_pUnitService->currentUnit(m_pLineEdit);
pUnitGroup = m_pUnitService->unitGroup(m_pLineEdit);
}
QString sRange = iParaItemCtrl::getScaleStrOf(
m_pParameter, sCurrentUnit, pUnitGroup);
sHelp = m_pParameter->m_sAlias;
if (!m_pParameter->m_sName.isEmpty())
{
if (!sHelp.isEmpty())
{
sHelp += "[" + m_pParameter->m_sName + "]";
}
else
{
sHelp = m_pParameter->m_sName;
}
}
if (!sRange.isEmpty())
{
if (!sHelp.isEmpty())
{
sHelp += "\n";
}
sHelp += sRange;
}
}
if (!m_sExternalValidationError.isEmpty())
{
if (!sHelp.isEmpty())
{
sHelp += "\n";
}
sHelp += m_sExternalValidationError;
}
m_pLineEdit->setToolTip(validationToolTip(sHelp, bValid));
m_pLineEdit->setWhatsThis(sHelp);
if (m_pLabel != nullptr)
{
m_pLabel->setWhatsThis(sHelp);
}
}