#include "pivaluetree_edit.h" #include "pijson.h" #include "piqt.h" #include "pivaluetree_conversions.h" #include "pivaluetree_edit_parameters.h" #include "pivaluetree_edit_reorder.h" #include "pivariant_edit.h" #include "ui_pivaluetree_edit_array.h" #include #include #include #include #include #include #include #include using Attribute = PIValueTree::Attribute; const char property_name[] = "__name__"; class ToolButton: public QToolButton { public: ToolButton(QWidget * parent = nullptr): QToolButton(parent) {} void setPressHandler(std::function f) { press_handler = f; } protected: void mousePressEvent(QMouseEvent * e) override { if (press_handler) press_handler(); QToolButton::mousePressEvent(e); } std::function press_handler; }; class GroupBox: public QGroupBox { public: GroupBox(QWidget * content = nullptr): QGroupBox() { icon_show = QIcon(":/icons/layer-visible-on.png"); icon_hide = QIcon(":/icons/layer-visible-off.png"); setLayout(new QBoxLayout(QBoxLayout::TopToBottom)); layout()->addWidget(content); setAlignment(Qt::AlignCenter); btn = new QToolButton(this); btn->setCheckable(true); btn->show(); connect(btn, &QToolButton::toggled, this, [this, content](bool on) { btn->setIcon(on ? icon_show : icon_hide); content->setVisible(on); }); btn->setChecked(true); } private: void resizeEvent(QResizeEvent * e) { QGroupBox::resizeEvent(e); btn->resize(btn->height(), btn->height()); btn->move(btn->height() / 2, 0); } QToolButton * btn = nullptr; QIcon icon_show, icon_hide; }; PIValueTreeEdit::PIValueTreeEdit(QWidget * parent): QWidget(parent) { widget_params = new PIValueTreeEditParameters(); widget_reorder = new PIValueTreeEditReorder(); ui_array = new Ui::PIValueTreeEditArray(); grid = new GridWidgets(this); auto * lay = new QBoxLayout(QBoxLayout::TopToBottom); lay->setContentsMargins(0, 0, 0, 0); setLayout(lay); } PIValueTreeEdit::~PIValueTreeEdit() { delete grid; delete ui_array; delete widget_params; } void PIValueTreeEdit::setValue(const PIValueTree & v) { current = source = v; build(); } PIValueTree PIValueTreeEdit::value() const { applyValues(); return current; } void PIValueTreeEdit::setGrouping(Grouping g) { applyValues(); cur_grouping = g; for (auto * a: widget_params->menu_grouping.actions()) { if (a->data().toInt() == g) { a->setChecked(true); break; } } build(); } void PIValueTreeEdit::setFullEditMode(bool yes) { applyValues(); is_full_edit = yes; build(); } void PIValueTreeEdit::setReadOnly(bool yes) { applyValues(); m_read_only = yes; build(); } void PIValueTreeEdit::setPermissions(Permissions p) { perm = p; applyPermissions(); } void PIValueTreeEdit::setPermission(Permission p, bool on) { perm.setFlag(p, on); applyPermissions(); } void PIValueTreeEdit::rollback() { current = source; build(); } void PIValueTreeEdit::clear() { current = PIValueTree(); removeAll(); } void PIValueTreeEdit::retranslate() { for (const auto & i: value_edits) i.second->retranslate(); for (const auto & i: tree_edits) i.second->retranslate(); for (const auto & i: comm_labels) { i.second->setText(PIVariantEditorBase::vtTr(current.child(i.first).comment())); } for (const auto & i: label_labels) { i.second->setText(PIVariantEditorBase::vtTr(i.first)); } if (tab_widget) { for (int i = 0; i < tab_widget->count(); ++i) { tab_widget->setTabText(i, PIVariantEditorBase::vtTr(Q2PIString(tab_widget->tabBar()->tabData(i).toString()))); } } grid->retranslate(); } void PIValueTreeEdit::changeEvent(QEvent * e) { if (e->type() == QEvent::LanguageChange) { if (widget_array) ui_array->retranslateUi(widget_array); retranslate(); } QWidget::changeEvent(e); } void PIValueTreeEdit::removeAll() { array_edits.clear(); value_edits.clear(); tree_edits.clear(); comm_labels.clear(); label_labels.clear(); tab_widget = nullptr; if (widget_array) { ui_array->layoutArray->removeWidget(grid); grid->hide(); grid->setParent(this); delete widget_array; widget_array = nullptr; } QLayoutItem * child = nullptr; while ((child = layout()->takeAt(0))) { delete child; } grid->clear(); } void PIValueTreeEdit::build() { grid->create_edit_buttons = false; removeAll(); // piCout << source.attributes().value(Attribute::arrayType) << array_type; grid->button_add->hide(); if (current.isArray()) { widget_array = new QWidget(); ui_array->setupUi(widget_array); applyArrayAttributes(); ui_array->layoutArray->addWidget(grid); grid->show(); uint array_type = PIVariant::typeIDFromName(current.attribute(Attribute::arrayType).toString()); int index = 0; for (const auto & i: current.children()) { auto * ve = new PIVariantEdit(); ve->setAttributes(attributesWithRO(current.attributes())); ve->setValue(i.value(), array_type); grid->add(PIValueTree({PIString::fromNumber(index), PIVariant()}), PIString::fromNumber(index + 1), ve, i.comment()); ++index; array_edits << ve; } connect(ui_array->spinCount, QOverload::of(&QSpinBox::valueChanged), this, [this](int) { PIValueTreeEdit::resizeArray(); }); layout()->addWidget(widget_array); } else { grid->create_edit_buttons = is_full_edit; layout()->addWidget(grid); if (!current.hasChildren()) grid->clear(); for (const auto & i: current.children()) { if (i.attribute(Attribute::hidden, false).toBool() && !is_full_edit) continue; if (i.attribute(Attribute::isLabel, false).toBool()) { if (i.name().isEmpty()) continue; auto * l = newLabel(i); grid->add(i, l); continue; } if (i.hasChildren() || i.isArray()) { addTreeEdit(i); } else { addValueEdit(i); } } } } void PIValueTreeEdit::applyValues() const { if (current.isArray()) { if (array_edits.isNotEmpty()) current.mergeAttributes(array_edits[0]->attributes()); current.clearChildren(); for (int i = 0; i < array_edits.size_s(); ++i) { PIValueTree vt(PIString::fromNumber(i), array_edits[i]->value()); auto comm_lbl = comm_labels.value(vt.name()); if (comm_lbl) vt.setComment(Q2PIString(comm_lbl->text())); current.addChild(vt); } } else { auto vit = value_edits.makeIterator(); while (vit.next()) { auto & c(current.child(vit.key())); c.mergeAttributes(vit.value()->attributes()); c.setValue(vit.value()->value()); } auto tit = tree_edits.makeIterator(); while (tit.next()) { auto & c(current.child(tit.key())); if (!c.isNull()) c = tit.value()->value(); } if (current.hasChildren()) { auto ge = PIVariantEditorBase::createGrouping(); ge.selectValue(cur_grouping); current.setAttribute(Attribute::grouping, ge); } } } void PIValueTreeEdit::applyPermissions() { auto * wp = widget_params; wp->actionValue->setVisible(perm.testFlag(AddValue)); wp->actionGroup->setVisible(perm.testFlag(AddGroup)); wp->actionArray->setVisible(perm.testFlag(AddArray)); wp->actionCut->setVisible(perm.testFlag(CanCut)); wp->actionCopy->setVisible(perm.testFlag(CanCopy)); wp->actionPaste->setVisible(perm.testFlag(CanPaste)); wp->actionPasteAfter->setVisible(perm.testFlag(CanPaste)); wp->actionPasteBefore->setVisible(perm.testFlag(CanPaste)); wp->checkHidden->setVisible(perm.testFlag(ChangeHidden)); wp->checkLabel->setVisible(perm.testFlag(ChangeLabel)); wp->checkReadOnly->setVisible(perm.testFlag(ChangeReadOnly)); wp->lineComment->setVisible(perm.testFlag(ChangeComment)); wp->labelComment->setVisible(perm.testFlag(ChangeComment)); wp->comboType->setVisible(perm.testFlag(ChangeType)); wp->labelType->setVisible(perm.testFlag(ChangeType)); wp->menu_grouping.menuAction()->setVisible(perm.testFlag(ChangeGrouping)); wp->actionRename->setVisible(perm.testFlag(CanRename)); wp->actionRemove->setVisible(perm.testFlag(CanRemove)); wp->actionReorder->setVisible(perm.testFlag(CanReorder)); for (auto * c: {wp->checkHidden, wp->checkLabel, wp->checkReadOnly}) if (!c->isEnabled()) c->setChecked(false); grid->button_add->setVisible( PIVector({wp->actionValue, wp->actionGroup, wp->actionArray, wp->actionPaste}).any([](QAction * a) { return a->isVisible(); })); for (auto c: tree_edits) c.second->setPermissions(perm); } void PIValueTreeEdit::actionRename(QToolButton * button, const PIString & vn) { PIString nn = Q2PIString(QInputDialog::getText(nullptr, tr("Rename"), tr("Input new name:"), QLineEdit::Normal, PI2QString(vn))); if (nn.isEmpty() || (nn == vn)) return; for (const auto & c: current.children()) { if (c.name() == nn) { QMessageBox::critical(nullptr, tr("Rename"), tr("This name already exists!")); return; } } current[vn].setName(nn); button->setProperty(property_name, PI2QString(nn)); grid->rename(vn, nn); if (value_edits.contains(vn)) { value_edits[nn] = value_edits[vn]; value_edits.remove(vn); } if (tree_edits.contains(vn)) { tree_edits[nn] = tree_edits[vn]; tree_edits.remove(vn); } if (comm_labels.contains(vn)) { comm_labels[nn] = comm_labels[vn]; comm_labels.remove(vn); } if (label_labels.contains(vn)) { label_labels[nn] = label_labels[vn]; label_labels[nn]->setText(PIVariantEditorBase::vtTr(nn)); label_labels.remove(vn); } if (tab_widget) { for (int i = 0; i < tab_widget->count(); ++i) { if (tab_widget->tabBar()->tabData(i).toString() == PI2QString(vn)) { tab_widget->setTabText(i, PIVariantEditorBase::vtTr(nn)); tab_widget->tabBar()->setTabData(i, PI2QString(nn)); break; } } } } void PIValueTreeEdit::actionRemove(QToolButton * button, const PIString & vn) { current.remove(vn); if (tab_widget) { QString qvn = PI2QString(vn); QMetaObject::invokeMethod( this, [this, qvn]() { for (int i = 0; i < tab_widget->count(); ++i) { if (tab_widget->tabBar()->tabData(i).toString() == qvn) { tab_widget->removeTab(i); break; } } if (tab_widget->count() == 0) { grid->removeRow(grid->getRow(tab_widget)); tab_widget = nullptr; } }, Qt::QueuedConnection); } grid->removeRow(grid->getRow(button)); value_edits.remove(vn); tree_edits.remove(vn); comm_labels.remove(vn); label_labels.remove(vn); } void PIValueTreeEdit::actionChange(QToolButton * button, const PIString & vn) { auto & vt(current[vn]); if (vt.isArray()) { auto * ve = tree_edits.value(vn, nullptr); if (!ve) return; vt = ve->value(); if (!widget_params->showFor(vt)) return; ve->setValue(vt); ve->resizeArray(); // ve->applyArrayAttributes(); } else { bool was_label = vt.attribute(Attribute::isLabel, false).toBool(); auto * ve = value_edits.value(vn, nullptr); if (ve) { vt.setValue(ve->value()); vt.mergeAttributes(ve->attributes()); } if (!widget_params->showFor(vt)) return; bool now_label = vt.attribute(Attribute::isLabel, false).toBool(); if (was_label ^ now_label) { if (now_label) { auto * l = newLabel(vt); grid->replace(grid->getRow(button), l); value_edits.remove(vt.name()); comm_labels.remove(vt.name()); } else { auto * ve = new PIVariantEdit(); applyVariantEdit(ve, vt); grid->replace(grid->getRow(button), vt.name(), ve, vt.comment()); value_edits[vt.name()] = ve; } ve = nullptr; } if (ve) { applyVariantEdit(ve, vt); } if (now_label) { label_labels[vt.name()]->setStyleSheet(PI2QString(vt.attribute(Attribute::style).toString())); } } auto * cl = comm_labels.value(vn, nullptr); if (cl) cl->setText(PIVariantEditorBase::vtTr(vt.comment())); } void PIValueTreeEdit::actionReorder(QToolButton *, const PIString & vn) { if (!widget_reorder->showFor(current)) return; grid->reorder(widget_reorder->map); auto cl = current.children(); current.clearChildren(); for (int i = 0; i < cl.size_s(); ++i) { int mi = widget_reorder->map.value(i, i); if (mi < 0 || mi >= cl.size_s()) continue; current.addChild(cl[mi]); } } void PIValueTreeEdit::actionCopy(QToolButton *, const PIString & vn) { PIValueTree cur_val = value(); auto & vt(cur_val[vn]); // piCout << vt; PIString json = PIValueTreeConversions::toJSON(vt, PIValueTreeConversions::Default | PIValueTreeConversions::IncludeRoot).toJSON(PIJSON::Tree); QApplication::clipboard()->setText(PI2QString(json)); } void PIValueTreeEdit::actionPaste(QToolButton * button, const PIString & vn, int offset) { PIString json = Q2PIString(QApplication::clipboard()->text()); if (json.isEmpty()) return; PIValueTree ins_val = PIValueTreeConversions::fromJSON(PIJSON::fromJSON(json)); // if (ins_val.name.isEmpty()) return; PIValueTree cur_val = value(); cur_val.insertChild(cur_val.childIndex(vn) + offset, ins_val); setValue(cur_val); } void PIValueTreeEdit::actionTriggered(QToolButton * button, const PIString & vn, QAction * a) { if (a == widget_params->actionRename) { actionRename(button, vn); return; } if (a == widget_params->actionRemove) { actionRemove(button, vn); return; } if (a == widget_params->actionChange) { actionChange(button, vn); return; } if (a == widget_params->actionReorder) { actionReorder(button, vn); return; } if (a == widget_params->actionCut) { actionCopy(button, vn); actionRemove(button, vn); return; } if (a == widget_params->actionCopy) { actionCopy(button, vn); return; } if (a == widget_params->actionPasteBefore) { actionPaste(button, vn, 0); return; } if (a == widget_params->actionPasteAfter) { actionPaste(button, vn, 1); return; } setGrouping((Grouping)a->data().toInt()); } void PIValueTreeEdit::checkActions() { bool can_paste = true; PIString str = Q2PIString(QApplication::clipboard()->text()); if (str.isEmpty() || !str.startsWith("{")) { can_paste = false; } else { PIJSON j = PIJSON::fromJSON(str); if (!j.contains("name")) can_paste = false; else { if (current.contains(j["name"].value().toString())) can_paste = false; } } widget_params->actionPasteBefore->setEnabled(can_paste); widget_params->actionPasteAfter->setEnabled(can_paste); widget_params->actionPaste->setEnabled(can_paste); } PIValueTreeEdit * PIValueTreeEdit::addTreeEdit(const PIValueTree & vt) { auto * ve = new PIValueTreeEdit(); PIStringList rp = root_path; rp << vt.name(); ve->root_path = rp; ve->parent_tree = this; ve->m_read_only = m_read_only; ve->setGrouping((Grouping)vt.attribute(Attribute::grouping, PIVariantEditorBase::createGrouping()).toEnum().selectedValue()); ve->setFullEditMode(is_full_edit); ve->setPermissions(permissions()); ve->setValue(vt); switch (cur_grouping) { case Indent: grid->add(vt, vt.name(), ve, vt.comment(), true); break; case Groups: { auto * gb = new GroupBox(ve); gb->setTitle(PI2QString(vt.name())); gb->setToolTip(PI2QString(vt.comment())); gb->setProperty(property_name, PI2QString(vt.name())); grid->add(vt, gb, true); } break; case Tabs: { createTabWidget(); auto * cw = new QWidget(); cw->setLayout(new QBoxLayout(QBoxLayout::TopToBottom)); cw->layout()->addWidget(ve); cw->layout()->addItem(new QSpacerItem(0, 0, QSizePolicy::Preferred, QSizePolicy::Expanding)); int tab = tab_widget->addTab(cw, PIVariantEditorBase::vtTr(vt.name())); tab_widget->tabBar()->setTabData(tab, PI2QString(vt.name())); if (is_full_edit) { auto * b = grid->createConfigButton(vt, true); tab_widget->tabBar()->setTabButton(tab, QTabBar::RightSide, b); } } break; default: break; } tree_edits[vt.name()] = ve; return ve; } PIValueTreeEdit * PIValueTreeEdit::rootTreeEdit() { PIValueTreeEdit * ret = this; while (ret->parent_tree) ret = ret->parent_tree; return ret; } void PIValueTreeEdit::addValueEdit(const PIValueTree & vt) { auto * ve = new PIVariantEdit(); applyVariantEdit(ve, vt); grid->add(vt, vt.name(), ve, vt.comment()); value_edits[vt.name()] = ve; } void PIValueTreeEdit::applyArrayAttributes() { ui_array->spinCount->setRange(current.attribute(Attribute::arrayMinCount, 0).toInt(), current.attribute(Attribute::arrayMaxCount, 65536).toInt()); ui_array->spinCount->setValue(current.children().size_s()); ui_array->widgetEdit->setVisible(current.attribute(Attribute::arrayResize, false).toBool()); uint array_type = PIVariant::typeIDFromName(current.attribute(Attribute::arrayType).toString()); for (int i = 0; i < array_edits.size_s(); ++i) { auto * w = array_edits[i]; w->setAttributes(attributesWithRO(current.attributes())); w->setValue(i < current.children().size_s() ? current.children()[i].value() : PIVariant(), array_type); } } QLabel * PIValueTreeEdit::newLabel(const PIValueTree & vt) { auto * l = new QLabel(); l->setAlignment(Qt::AlignCenter); l->setText(PIVariantEditorBase::vtTr(vt.name())); l->setStyleSheet(PI2QString(vt.attribute(Attribute::style).toString())); label_labels[vt.name()] = l; return l; } void PIValueTreeEdit::applyVariantEdit(PIVariantEdit * ve, const PIValueTree & vt) { ve->setAttributes(attributesWithRO(vt.attributes())); ve->setValue(vt.value()); ve->setFullEditMode(is_full_edit); } void PIValueTreeEdit::createTabWidget() { if (tab_widget) return; tab_widget = new QTabWidget(); grid->addRow(tab_widget); } void PIValueTreeEdit::resizeArray() { if (!ui_array) return; uint array_type = PIVariant::typeIDFromName(current.attribute(Attribute::arrayType).toString()); int value = piMaxi(ui_array->spinCount->value(), 0); for (int i = grid->rowCount() - 1; i >= value; --i) grid->removeRow(i); array_edits.resize(grid->rowCount()); for (int i = grid->rowCount(); i < value; ++i) { auto * ve = new PIVariantEdit(); ve->setAttributes(attributesWithRO(current.attributes())); ve->setValue(PIVariant::fromType(array_type), array_type); grid->add(PIValueTree(), PIString::fromNumber(i + 1), ve, ""); array_edits << ve; } } PIVariantMap PIValueTreeEdit::attributesWithRO(const PIVariantMap & attr) { PIVariantMap ret = attr; if (m_read_only) ret[PIValueTree::Attribute::readOnly] = true; return ret; } void PIValueTreeEdit::newRequest(NewType type) { PIString nn; if (rootTreeEdit()->allowed_names && (type == NewType::Value)) { QStringList anl = PI2QStringList(rootTreeEdit()->allowed_names()); if (anl.isEmpty()) { QMessageBox::warning(nullptr, tr("New item"), tr("No allowed names!")); return; } bool ok = false; nn = Q2PIString(QInputDialog::getItem(nullptr, tr("New item"), tr("Select new name:"), anl, 0, false, &ok)); if (!ok) return; } else { nn = Q2PIString(QInputDialog::getText(nullptr, tr("New item"), tr("Input new name:"))); } if (nn.isEmpty()) return; for (const auto & c: current.children()) { if (c.name() == nn) { QMessageBox::critical(nullptr, tr("New item"), tr("This name already exists!")); return; } } PIValueTree vt; vt.setName(nn); if (type == NewType::Value) { if (rootTreeEdit()->value_by_name) { vt.setValue(rootTreeEdit()->value_by_name(nn)); } if (!widget_params->showFor(vt)) return; } if (type == NewType::Array) { vt.setAttribute(Attribute::arrayType, PIVariant::typeName()); if (!widget_params->showFor(vt)) return; } current.addChild(vt); switch (type) { case NewType::Value: if (vt.attribute(Attribute::isLabel, false).toBool()) { auto * l = newLabel(vt); grid->add(vt, l); } else { addValueEdit(vt); } break; case NewType::Group: addTreeEdit(vt); break; case NewType::Array: addTreeEdit(vt)->resizeArray(); break; } } // PIValueTreeEdit::GridWidgets PIValueTreeEdit::GridWidgets::GridWidgets(PIValueTreeEdit * p) { parent = p; icon_conf = QIcon(":/icons/configure.png"); auto newSeparator = []() { auto * a = new QAction(); a->setSeparator(true); return a; }; auto * wp = p->widget_params; auto common_actions = {newSeparator(), wp->actionCut, wp->actionCopy, wp->actionPasteBefore, wp->actionPasteAfter, newSeparator(), wp->actionRemove}; menu_group.addActions({wp->actionRename, wp->actionReorder, wp->menu_grouping.menuAction()}); menu_conf.addActions({wp->actionRename, wp->actionChange, wp->actionReorder, wp->menu_grouping.menuAction()}); menu_group.addActions(common_actions); menu_conf.addActions(common_actions); menu_new.addActions({wp->actionValue, wp->actionGroup, wp->actionArray, newSeparator(), wp->actionPaste}); button_add = new ToolButton(); button_add->setIcon(QIcon(":/icons/list-add.png")); button_add->setPopupMode(QToolButton::InstantPopup); button_add->setMenu(&menu_new); ((ToolButton *)button_add)->setPressHandler([this]() { parent->checkActions(); }); wp->actionValue->setData((int)NewType::Value); wp->actionGroup->setData((int)NewType::Group); wp->actionArray->setData((int)NewType::Array); connect(button_add, &QToolButton::triggered, this, [this](QAction * a) { if (a == parent->widget_params->actionPaste) parent->actionPaste(button_add, "", parent->current.children().size_s() + 1); else parent->newRequest((NewType)a->data().toInt()); }); } PIValueTreeEdit::GridWidgets::~GridWidgets() { delete button_add; } int PIValueTreeEdit::GridWidgets::getRow(QWidget * w) const { if (!w) return -1; for (int r = 0; r < lay->rowCount(); ++r) { for (int c = 0; c < lay->columnCount(); ++c) { auto * li = lay->itemAtPosition(r, c); if (!li) continue; if (li->widget() && (li->widget() == w)) return r; } } return -1; } void PIValueTreeEdit::GridWidgets::add(const PIValueTree & vt, const PIString & label, QWidget * w, const PIString & comment, bool is_group) { int col = beginRow(vt, is_group); auto * l = new QLabel(); auto * c = new QLabel(PIVariantEditorBase::vtTr(comment)); l->setProperty(property_name, PI2QString(label)); QString nn = PIVariantEditorBase::vtTr(label); if (!nn.isEmpty()) nn += ':'; l->setText(nn); l->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); c->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); w->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); lay->addWidget(l, row_count, col++, Qt::AlignVCenter | Qt::AlignRight); lay->addWidget(w, row_count, col++); lay->addWidget(c, row_count, col++, Qt::AlignVCenter | Qt::AlignLeft); widgets << l << w << c; labels << l; parent->comm_labels[vt.name()] = c; ++row_count; changed(); } void PIValueTreeEdit::GridWidgets::add(const PIValueTree & vt, QWidget * w, bool is_group) { int col = beginRow(vt, is_group); lay->addWidget(w, row_count, col, 1, -1); widgets << w; ++row_count; changed(); } void PIValueTreeEdit::GridWidgets::addRow(QWidget * w) { lay->addWidget(w, row_count, 0, 1, -1); widgets << w; ++row_count; changed(); } QToolButton * PIValueTreeEdit::GridWidgets::createConfigButton(const PIValueTree & vt, bool is_group) { auto * b = new ToolButton(); b->setIcon(icon_conf); b->setPopupMode(QToolButton::InstantPopup); b->setMenu((is_group && !vt.isArray()) ? &menu_group : &menu_conf); b->setProperty(property_name, PI2QString(vt.name())); b->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); b->setPressHandler([this]() { parent->checkActions(); }); // connect(b, &QToolButton::pressed, parent, &PIValueTreeEdit::checkActions); connect(b, &QToolButton::triggered, this, [this, b](QAction * a) { parent->actionTriggered(b, Q2PIString(b->property(property_name).toString()), a); }); return b; } void PIValueTreeEdit::GridWidgets::replace(int row, QWidget * w) { int col = removeRowEdits(row); lay->addWidget(w, row, col, 1, -1); widgets << w; } void PIValueTreeEdit::GridWidgets::replace(int row, const PIString & label, QWidget * w, const PIString & comment) { int col = removeRowEdits(row); auto * l = new QLabel(); auto * c = new QLabel(PIVariantEditorBase::vtTr(comment)); l->setProperty(property_name, PI2QString(label)); QString nn = PIVariantEditorBase::vtTr(label); if (!nn.isEmpty()) nn += ':'; l->setText(nn); l->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); c->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); w->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); lay->addWidget(l, row, col++, Qt::AlignVCenter | Qt::AlignRight); lay->addWidget(w, row, col++); lay->addWidget(c, row, col++, Qt::AlignVCenter | Qt::AlignLeft); widgets << l << w << c; labels << l; parent->comm_labels[label] = c; } int PIValueTreeEdit::GridWidgets::beginRow(const PIValueTree & vt, bool is_group) { if (!create_edit_buttons) return 0; auto * b = createConfigButton(vt, is_group); lay->addWidget(b, row_count, 0); widgets << b; return 1; } void PIValueTreeEdit::GridWidgets::rename(const PIString & prev_name, const PIString & new_name) { for (auto * w: widgets) { auto * gb = qobject_cast(w); if (!gb) continue; if (gb->property(property_name).toString() == PI2QString(prev_name)) { gb->setProperty(property_name, PI2QString(new_name)); gb->setTitle(PIVariantEditorBase::vtTr(new_name)); break; } } for (auto * l: labels) if (l->property(property_name).toString() == PI2QString(prev_name)) { l->setProperty(property_name, PI2QString(new_name)); QString nn = PIVariantEditorBase::vtTr(new_name); if (!nn.isEmpty()) nn += ':'; l->setText(nn); break; } } void PIValueTreeEdit::GridWidgets::clear() { piDeleteAllAndClear(widgets); labels.clear(); if (lay) delete lay; lay = new QGridLayout(); lay->setContentsMargins(0, 0, 0, 0); setLayout(lay); row_count = 0; changed(); } void PIValueTreeEdit::GridWidgets::changed() { if (!create_edit_buttons || !lay) return; lay->addWidget(button_add, row_count, 0); button_add->show(); adjustSize(); } void PIValueTreeEdit::GridWidgets::retranslate() { for (auto * w: widgets) { auto * gb = qobject_cast(w); if (!gb) continue; gb->setTitle(PIVariantEditorBase::vtTr(Q2PIString(gb->property(property_name).toString()))); } for (auto * l: labels) { QString nn = PIVariantEditorBase::vtTr(Q2PIString(l->property(property_name).toString())); if (!nn.isEmpty()) nn += ':'; l->setText(nn); } } int PIValueTreeEdit::GridWidgets::removeRowEdits(int row) { int col = create_edit_buttons ? 1 : 0; for (int c = col; c < lay->columnCount(); ++c) { auto * li = lay->itemAtPosition(row, c); if (li) { QWidget * w = li->widget(); if (w) { widgets.removeOne(w); QLabel * lbl = qobject_cast(w); if (lbl) labels.removeOne(lbl); delete w; } } } return col; } void PIValueTreeEdit::GridWidgets::removeRow(int index) { if (!lay) return; if ((index < 0) || (index >= row_count) || (index >= lay->rowCount())) return; for (int c = 0; c < lay->columnCount(); ++c) { auto * li = lay->itemAtPosition(index, c); if (li) { QWidget * w = li->widget(); if (w) { widgets.removeOne(w); QLabel * lbl = qobject_cast(w); if (lbl) labels.removeOne(lbl); delete w; } } } --row_count; simplify(); changed(); } void PIValueTreeEdit::GridWidgets::simplify(const PIMap & map) { struct Info { Qt::Alignment align; int row_span = 0; int col_span = 0; }; if (!lay) return; QVector> wg; QMap wa; for (int r = 0; r < lay->rowCount(); ++r) { QMap row; for (int c = 0; c < lay->columnCount(); ++c) { auto * li = lay->itemAtPosition(r, c); if (!li) continue; if (li->widget()) { row[c] = li->widget(); Info info; info.align = li->alignment(); int pos[4]; lay->getItemPosition(lay->indexOf(li), &(pos[0]), &(pos[1]), &(pos[2]), &(pos[3])); info.row_span = pos[2]; info.col_span = pos[3]; wa[li->widget()] = info; c += (pos[3] - 1); } } if (!row.isEmpty()) wg << row; } delete lay; lay = new QGridLayout(); lay->setContentsMargins(0, 0, 0, 0); int rindex = 0; for (int i = 0; i < wg.size(); ++i) { int mi = map.value(i, i); if (mi < 0 || mi >= wg.size()) continue; QMapIterator it(wg[mi]); while (it.hasNext()) { it.next(); Info info = wa.value(it.value()); lay->addWidget(it.value(), rindex, it.key(), info.row_span, info.col_span, info.align); } ++rindex; } setLayout(lay); adjustSize(); }