QBinaryTranslate/TranslateUI/ExtractRuleView.cpp

462 lines
16 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "ExtractRuleView.h"
#include "TranslateBasic.h"
#include "extract_basic.h"
#include "WrapConfigs.h"
#include <QGridLayout>
#include <QLabel>
#include <QComboBox>
#include <QJsonDocument>
#include <QPushButton>
#include <QSplitter>
#include <QGroupBox>
#include <QTabWidget>
#include <QTextCodec>
#include <QMenu>
#include <QHeaderView>
using namespace unit_configurations;
using namespace size_provider;
using namespace extract;
ExtractRuleView::ExtractRuleView(std::shared_ptr<TranslateBasic> base,
std::shared_ptr<extract::AsRuleSet> inst_r, QWidget* p /*= nullptr*/)
: QWidget(p), _current_rule(inst_r), _basic_bind(base),
_member_units(new QTableView(this)),
_member_model(new QStandardItemModel(this)),
_configs_stack(new QStackedWidget(this))
{
this->_current_fields_cache = std::make_shared<FieldManagerLayer>("", nullptr);
auto layout = new QVBoxLayout(this);
auto split = new QSplitter(Qt::Horizontal, this);
layout->addWidget(split);
split->addWidget(_member_units);
split->addWidget(_configs_stack);
_configs_stack->addWidget(new configurations::EmptyConfiguration(this));
auto single_configs = new SingleBasedConfiguration(base, this);
_configs_stack->addWidget(single_configs);
auto list_configs = new ListBasedConfiguration(base, this);
_configs_stack->addWidget(list_configs);
auto union_configs = new UnionBasedConfiguration(base, this);
_configs_stack->addWidget(union_configs);
connect(single_configs, &SingleBasedConfiguration::reloadRequest, this, &ExtractRuleView::reload);
connect(list_configs, &ListBasedConfiguration::reloadRequest, this, &ExtractRuleView::reload);
connect(union_configs, &UnionBasedConfiguration::reloadRequest, this, &ExtractRuleView::reload);
connect(_member_units, &QTableView::clicked, [=](const QModelIndex& target) {
if (!target.isValid())
return;
auto unit = _current_rule->operator[](target.row());
if (unit->baseType() == SingleBasedUnit::topic()) {
_configs_stack->setCurrentIndex(1);
single_configs->currentAccept(unit, target);
}
else if (unit->baseType() == ListBasedUnit::topic()) {
_configs_stack->setCurrentIndex(2);
FieldManagerLayer::__Private::fields_map.clear();
_current_fields_cache = std::make_shared<FieldManagerLayer>("{self}");
this->_current_rule->registSubField(_current_fields_cache);
auto current_field = this->_current_rule->operator[](target.row());
_current_fields_cache->bindCurrent(current_field->name());
list_configs->currentAccept(unit, target, _current_fields_cache);
}
else if (unit->baseType() == UnionBasedUnit::topic()) {
_configs_stack->setCurrentIndex(3);
union_configs->currentAccept(unit, target);
}
else {
_configs_stack->setCurrentIndex(0);
}
});
_member_units->setModel(_member_model);
connect(_member_model, &QStandardItemModel::itemChanged, this, &ExtractRuleView::dataChanged);
_member_units->setItemDelegateForColumn(2, new UnitSelectDelegate(_basic_bind));
_member_model->setHorizontalHeaderLabels(QStringList() << "FieldName" << "OffsetSpan" << "UnitType");
_member_units->setContextMenuPolicy(Qt::CustomContextMenu);
connect(_member_units, &QTableView::customContextMenuRequested, [=](const QPoint& pt) {
QMenu m;
m.addAction("Append Unit", this, &ExtractRuleView::appendUnit);
m.exec(_member_units->mapToGlobal(pt));
});
}
void ExtractRuleView::reload()
{
auto cnt = _member_model->rowCount();
_member_model->removeRows(0, cnt);
auto list = _current_rule->fieldNames();
for (auto key : list) {
auto field_mbr = _current_rule->operator[](key);
QList<QStandardItem*> row;
row << new QStandardItem(field_mbr->name());
row << new QStandardItem(QString("%1 bytes").arg(field_mbr->offsetSpan()));
row.last()->setEditable(false);
row << new QStandardItem(field_mbr->baseType());
_member_model->appendRow(row);
}
_member_units->resizeColumnsToContents();
}
#include <QMessageBox>
#include <QInputDialog>
void ExtractRuleView::appendUnit()
{
auto name_u = QInputDialog::getText(this, "FieldName Enter", "Name");
if (name_u == "")
return;
if (this->_current_rule->fieldNames().contains(name_u)) {
QMessageBox::critical(this, "DataValidate", "Field can't repeat");
return;
}
auto unit_template = _basic_bind->defaultExtractUnitType()->newDefault();
auto new_unit = std::dynamic_pointer_cast<SingleBasedUnit>(unit_template);
new_unit->setName(name_u);
auto delt_key = _basic_bind->customDelegateAlias().first();
auto delt_o = _basic_bind->operator[](delt_key);
QJsonObject content;
delt_o->saveTo(content);
auto delt_u = delt_o->newDefault();
delt_u->loadFrom(_basic_bind, content);
new_unit->setDelegate(std::dynamic_pointer_cast<ExtractDelegate>(delt_u));
this->_current_rule->append(new_unit);
reload();
}
void ExtractRuleView::dataChanged(QStandardItem* item)
{
auto current_unit = this->_current_rule->operator[](item->row());
switch (item->column()) {
case 0: {
auto fields_names = this->_current_rule->fieldNames();
if (fields_names.contains(item->text())) {
QMessageBox::critical(this, "DataValidate", "Field can't repeat");
}
else {
current_unit->setName(item->text());
}
reload();
}break;
case 2: {
// <20><>ȡTemplate<74><65><EFBFBD><EFBFBD>
auto unit_template = this->_basic_bind->extractUnitTypeMap()[item->text()];
// <20><><EFBFBD><EFBFBD><EFBFBD>µ<EFBFBD>Ԫ<EFBFBD><D4AA><EFBFBD><EFBFBD>
auto unit_ins = std::dynamic_pointer_cast<ExtractUnit>(unit_template->newDefault());
unit_ins->setName(current_unit->name());
// <20><EFBFBD><E6BBBB><EFBFBD>е<EFBFBD>Ԫ<EFBFBD><D4AA><EFBFBD><EFBFBD>
this->_current_rule->replace(item->row(), unit_ins);
// <20><><EFBFBD><EFBFBD><EFBFBD>ݽ⹹<DDBD><E2B9B9><EFBFBD><EFBFBD>
if (unit_ins->baseType() == SingleBasedUnit::topic()) {
auto single_ins = std::dynamic_pointer_cast<SingleBasedUnit>(unit_ins);
auto delt_name = _basic_bind->customDelegateAlias().first();
auto delt_base = _basic_bind->operator[](delt_name);
QJsonObject object;
delt_base->saveTo(object);
auto delt_conv = std::dynamic_pointer_cast<ExtractDelegate>(delt_base->newDefault());
delt_conv->loadFrom(_basic_bind, object);
single_ins->setDelegate(std::dynamic_pointer_cast<ExtractDelegate>(delt_conv));
}
// <20>б<EFBFBD><D0B1><EFBFBD><EFBFBD>ݽ⹹<DDBD><E2B9B9><EFBFBD><EFBFBD>
if (unit_ins->baseType() == ListBasedUnit::topic()) {
auto list_ins = std::dynamic_pointer_cast<ListBasedUnit>(unit_ins);
auto delt_name = _basic_bind->customDelegateAlias().first();
auto delt_base = _basic_bind->operator[](delt_name);
QJsonObject object;
delt_base->saveTo(object);
auto delt_elm = std::dynamic_pointer_cast<ExtractDelegate>(delt_base->newDefault());
delt_elm->loadFrom(_basic_bind, object);
list_ins->setDelegate(delt_elm);
auto size_o = _basic_bind->defaultSizeProviderType();
QJsonObject mobject;
size_o->saveTo(mobject);
auto size_copy = std::dynamic_pointer_cast<SizeProvider>(size_o->newDefault());
size_copy->loadFrom(_basic_bind, mobject);
list_ins->setSizeProvider(size_copy);
}
}break;
default:
break;
}
}
void ExtractRuleView::showEvent(QShowEvent* e)
{
QWidget::showEvent(e);
reload();
}
ListBasedConfiguration::ListBasedConfiguration(
std::shared_ptr<TranslateBasic> core, QWidget* p /*= nullptr*/)
:QWidget(p), _bind_core(core),
_offset_enter(new QSpinBox(this)),
_delegate_sync(new QPushButton("Sync", this)),
_delegate_select(new QComboBox(this)),
_size_layout_select(new QComboBox(this)),
_configs_stack(new QStackedWidget(this)),
_content_display(new QTextBrowser(this)),
_const_number_input(new QSpinBox(this)),
_prev_field_refer(new QComboBox(this))
{
auto layout = new QGridLayout(this);
layout->addWidget(new QLabel("OffsetSpan:", this), 0, 0);
layout->addWidget(this->_offset_enter, 0, 1);
layout->addWidget(this->_delegate_sync, 0, 2);
layout->addWidget(new QLabel(tr("Delegate:")), 1, 0);
layout->addWidget(_delegate_select, 1, 1, 1, 2);
layout->addWidget(new QLabel(tr("Size:")), 2, 0);
layout->addWidget(_size_layout_select, 2, 1, 1, 2);
layout->addWidget(new QLabel(tr("Exprs:")), 3, 0);
layout->addWidget(_configs_stack, 3, 1, 2, 3);
_configs_stack->addWidget(_const_number_input);
_configs_stack->addWidget(_prev_field_refer);
layout->addWidget(this->_content_display, 5, 0, 3, 3);
layout->setRowStretch(7, 1);
layout->setColumnStretch(1, 1);
connect(_offset_enter, QOverload<int>::of(&QSpinBox::valueChanged),
[=](int v) {
this->_bind_u->setOffsetSpan(v);
currentAccept(_bind_u, _bind_index, _fields_getter);
emit this->reloadRequest();
});
connect(_delegate_select, QOverload<const QString&>::of(&QComboBox::currentTextChanged),
[=](const QString& current_delegate) {
auto delt_o = _bind_core->operator[](current_delegate);
QJsonObject object;
delt_o->saveTo(object);
auto delt_ins = delt_o->newDefault();
delt_ins->loadFrom(_bind_core, object);
_bind_u->setDelegate(std::dynamic_pointer_cast<ExtractDelegate>(delt_ins));
currentAccept(_bind_u, _bind_index, _fields_getter);
emit this->reloadRequest();
});
connect(_size_layout_select, QOverload<const QString&>::of(&QComboBox::currentTextChanged),
[=](const QString& size_provider_name) {
auto size_o = _bind_core->sizeProviderTypeMap()[size_provider_name];
auto size_ins = std::dynamic_pointer_cast<SizeProvider>(size_o->newDefault());
this->_bind_u->setSizeProvider(size_ins);
if (size_provider_name == ConstNumberProvider::topic()) {
_configs_stack->setCurrentIndex(0);
size_ins->setExpression("0");
_const_number_input->setValue(0);
}
if (size_provider_name == InterpretedNumberPrivider::topic()) {
_configs_stack->setCurrentIndex(1);
QSignalBlocker s(_prev_field_refer);
_prev_field_refer->clear();
s.unblock();
auto fields_map = _fields_getter->prevFields();
for (auto field_name : fields_map.keys()) {
switch (fields_map[field_name]) {
case DataType::Integer:
case DataType::Unsigned:
_prev_field_refer->addItem(tr("BindField:") + field_name, field_name);
default:
break;
}
}
}
currentAccept(_bind_u, _bind_index, _fields_getter);
emit this->reloadRequest();
});
connect(_const_number_input, QOverload<int>::of(&QSpinBox::valueChanged),
[=](int value) {
auto size_ins = _bind_u->sizeProvider();
size_ins->setExpression(QString("%1").arg(value));
currentAccept(_bind_u, _bind_index, _fields_getter);
emit this->reloadRequest();
});
connect(_prev_field_refer, QOverload<const QString&>::of(&QComboBox::currentTextChanged),
[=]() {
auto current_field = _prev_field_refer->currentData().toString();
auto size_ins = _bind_u->sizeProvider();
size_ins->setExpression(current_field);
currentAccept(_bind_u, _bind_index, _fields_getter);
emit this->reloadRequest();
});
}
void ListBasedConfiguration::currentAccept(std::shared_ptr<ExtractUnit> inst_u,
const QModelIndex& idx, std::shared_ptr<ScopeFieldsGetter> get)
{
_bind_u = std::dynamic_pointer_cast<ListBasedUnit>(inst_u);
_bind_index = idx;
_fields_getter = get;
QSignalBlocker v(_offset_enter);
_offset_enter->setRange(0, INT_MAX);
_offset_enter->setValue(inst_u->offsetSpan());
QSignalBlocker vx(_delegate_select);
this->_bind_u = std::dynamic_pointer_cast<extract::ListBasedUnit>(inst_u);
_delegate_select->clear();
_delegate_select->addItems(_bind_core->customDelegateAlias());
_delegate_select->setCurrentText(this->_bind_u->delegateInst()->aliasName());
QSignalBlocker vv(_size_layout_select);
this->_size_layout_select->clear();
this->_size_layout_select->addItems(_bind_core->sizeProviderTypeMap().keys());
this->_size_layout_select->setCurrentText(_bind_u->sizeProvider()->name());
if (this->_size_layout_select->currentText() == ConstNumberProvider::topic()) {
_configs_stack->setCurrentIndex(0);
auto size_const = std::dynamic_pointer_cast<ConstNumberProvider>(_bind_u->sizeProvider());
QSignalBlocker s(_const_number_input);
_const_number_input->setValue(size_const->value(size_const->expression()));
}
if (this->_size_layout_select->currentText() == InterpretedNumberPrivider::topic()) {
_configs_stack->setCurrentIndex(1);
auto size_rt = std::dynamic_pointer_cast<InterpretedNumberPrivider>(_bind_u->sizeProvider());
QSignalBlocker s(_prev_field_refer);
_prev_field_refer->clear();
auto fields_map = _fields_getter->prevFields();
for (auto field_name : fields_map.keys()) {
switch (fields_map[field_name]) {
case DataType::Integer:
case DataType::Unsigned:
_prev_field_refer->addItem(tr("BindField:") + field_name, field_name);
default:
break;
}
}
if (size_rt->expression() == QString()) {
auto text_expr = _prev_field_refer->currentData().toString();
size_rt->setExpression(text_expr);
}
for (auto idx = 0; idx < _prev_field_refer->count(); ++idx) {
auto expr_t = _prev_field_refer->itemData(idx).toString();
if (size_rt->expression() == expr_t) {
_prev_field_refer->setCurrentIndex(idx);
break;
}
}
}
QJsonObject content;
_bind_u->saveTo(content);
_content_display->setText(
QString::fromUtf8(QJsonDocument(content).toJson())
);
}
SingleBasedConfiguration::SingleBasedConfiguration(std::shared_ptr<TranslateBasic> core, QWidget* p /*= nullptr*/)
: QWidget(p), _bind_core(core),
_offset_enter(new QSpinBox(this)),
_delegate_changed(new QComboBox(this)),
_delegate_sync(new QPushButton("Sync", this)),
_content_display(new QTextBrowser(this))
{
auto layout = new QGridLayout(this);
layout->addWidget(new QLabel("Offset:", this), 0, 0);
layout->addWidget(this->_offset_enter, 0, 1);
layout->addWidget(this->_delegate_sync, 0, 2);
layout->addWidget(new QLabel("Delegate:", this), 1, 0);
layout->addWidget(this->_delegate_changed, 1, 1, 1, 2);
layout->addWidget(this->_content_display, 2, 0, 3, 3);
layout->setColumnStretch(1, 1);
connect(this->_offset_enter, QOverload<int>::of(&QSpinBox::valueChanged),
[=](int v_offset) {
inst_current->setOffsetSpan(v_offset);
currentAccept(this->inst_current, this->idx_current);
emit this->reloadRequest();
});
connect(this->_delegate_changed, QOverload<const QString&>::of(&QComboBox::currentTextChanged),
[=](const QString& current_alias) {
auto o_inst = _bind_core->operator[](current_alias);
auto v_inst = o_inst->newDefault();
QJsonObject content;
o_inst->saveTo(content);
v_inst->loadFrom(_bind_core, content);
inst_current->setDelegate(std::dynamic_pointer_cast<ExtractDelegate>(v_inst));
currentAccept(this->inst_current, this->idx_current);
emit this->reloadRequest();
});
}
void SingleBasedConfiguration::currentAccept(std::shared_ptr<ExtractUnit> inst_u, const QModelIndex& idx)
{
inst_current = std::dynamic_pointer_cast<SingleBasedUnit>(inst_u);
idx_current = idx;
QSignalBlocker b(_offset_enter);
_offset_enter->setRange(0, INT_MAX);
_offset_enter->setValue(inst_u->offsetSpan());
QSignalBlocker v(_delegate_changed);
_delegate_changed->clear();
_delegate_changed->addItems(_bind_core->customDelegateAlias());
auto conv = std::dynamic_pointer_cast<SingleBasedUnit>(inst_u);
_delegate_changed->setCurrentText(conv->delegateInst()->aliasName());
QJsonObject contents;
inst_u->saveTo(contents);
this->_content_display->setPlainText(QString::fromUtf8(
QJsonDocument(contents).toJson()
));
}
UnionBasedConfiguration::UnionBasedConfiguration(std::shared_ptr<TranslateBasic> core, QWidget* p /*= nullptr*/)
{
}
void UnionBasedConfiguration::currentAccept(std::shared_ptr<ExtractUnit> inst_u, const QModelIndex& idx)
{
}
UnitSelectDelegate::UnitSelectDelegate(std::shared_ptr<TranslateBasic> ins)
: _kernel(ins)
{
}
QWidget* UnitSelectDelegate::createEditor(QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index) const
{
return new QComboBox(parent);
}
void UnitSelectDelegate::setEditorData(QWidget* editor, const QModelIndex& index) const
{
auto combo = dynamic_cast<QComboBox*>(editor);
combo->addItems(_kernel->extractUnitTypeMap().keys());
combo->setCurrentText(index.data(Qt::DisplayRole).toString());
}
void UnitSelectDelegate::setModelData(QWidget* editor, QAbstractItemModel* model, const QModelIndex& index) const
{
auto combo = dynamic_cast<QComboBox*>(editor);
model->setData(index, combo->currentText(), Qt::EditRole);
}
void UnitSelectDelegate::updateEditorGeometry(QWidget* editor, const QStyleOptionViewItem& option, const QModelIndex& index) const
{
editor->setGeometry(option.rect);
}