From 08f253eb09f454e5be4b5a120c314c13569f5d43 Mon Sep 17 00:00:00 2001 From: peri4 Date: Mon, 26 Dec 2022 14:09:40 +0300 Subject: [PATCH] PIValueTreeEdit individual grouping feature --- libs/piqt_widgets/pivaluetree_edit.cpp | 149 ++++++++++++++---- libs/piqt_widgets/pivaluetree_edit.h | 27 +++- .../pivaluetree_edit_parameters.cpp | 15 ++ .../pivaluetree_edit_parameters.h | 3 + libs/piqt_widgets/pivariant_edit.cpp | 15 +- libs/piqt_widgets/pivariant_edit.h | 16 +- utils/valuetreeeditor/mainwindow.cpp | 21 ++- utils/valuetreeeditor/mainwindow.h | 3 +- utils/valuetreeeditor/mainwindow.ui | 22 +-- 9 files changed, 200 insertions(+), 71 deletions(-) diff --git a/libs/piqt_widgets/pivaluetree_edit.cpp b/libs/piqt_widgets/pivaluetree_edit.cpp index c488022..227a3a5 100644 --- a/libs/piqt_widgets/pivaluetree_edit.cpp +++ b/libs/piqt_widgets/pivaluetree_edit.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include using Attribute = PIValueTree::Attribute; @@ -48,9 +49,17 @@ PIValueTree PIValueTreeEdit::value() const { } -void PIValueTreeEdit::setGroupingEnabled(bool yes) { +void PIValueTreeEdit::setGrouping(Grouping g) { applyValues(); - is_grouping = yes; + cur_grouping = real_grouping = g; + if (parent_tree && g == Parent) real_grouping = parent_tree->real_grouping; + if (real_grouping == Parent) real_grouping = Indent; + for (auto * a: widget_params->menu_grouping.actions()) { + if (a->data().toInt() == g) { + a->setChecked(true); + break; + } + } build(); } @@ -104,6 +113,7 @@ void PIValueTreeEdit::removeAll() { tree_edits.clear(); comm_labels.clear(); label_labels.clear(); + tab_widget = nullptr; if (widget_array) { ui_array->layoutArray->removeWidget(grid); grid->hide(); @@ -193,6 +203,11 @@ void PIValueTreeEdit::applyValues() const { 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); + } } } @@ -227,14 +242,43 @@ void PIValueTreeEdit::actionTriggered(QToolButton * button, const PIString & 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; + } + } + } + return; } if (a == widget_params->actionRemove) { 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); + return; } if (a == widget_params->actionChange) { auto & vt(current[vn]); @@ -277,6 +321,7 @@ void PIValueTreeEdit::actionTriggered(QToolButton * button, const PIString & vn, } auto * cl = comm_labels.value(vn, nullptr); if (cl) cl->setText(PIVariantEditorBase::vtTr(vt.comment())); + return; } if (a == widget_params->actionReorder) { if (!widget_reorder->showFor(current)) return; @@ -288,7 +333,9 @@ void PIValueTreeEdit::actionTriggered(QToolButton * button, const PIString & vn, if (mi < 0 || mi >= cl.size_s()) continue; current.addChild(cl[mi]); } + return; } + setGrouping((Grouping)a->data().toInt()); } @@ -296,11 +343,14 @@ PIValueTreeEdit * PIValueTreeEdit::addTreeEdit(const PIValueTree & vt) { auto * ve = new PIValueTreeEdit(); PIStringList rp = root_path; rp << vt.name(); - ve->root_path = rp; - ve->setGroupingEnabled(is_grouping); + ve->root_path = rp; + ve->parent_tree = this; + ve->setGrouping((Grouping)vt.attribute(Attribute::grouping, Parent).toInt()); ve->setFullEditMode(is_full_edit); ve->setValue(vt); - if (is_grouping) { + switch (real_grouping) { + case Indent: grid->add(vt, vt.name(), ve, vt.comment(), true); break; + case Groups: { auto * gb = new QGroupBox(); gb->setLayout(new QBoxLayout(QBoxLayout::TopToBottom)); gb->layout()->addWidget(ve); @@ -312,8 +362,21 @@ PIValueTreeEdit * PIValueTreeEdit::addTreeEdit(const PIValueTree & vt) { gb->setProperty(property_name, PI2QString(vt.name())); connect(gb, &QGroupBox::toggled, ve, &QWidget::setVisible); grid->add(vt, gb, true); - } else { - grid->add(vt, vt.name(), ve, vt.comment(), 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; @@ -359,6 +422,13 @@ void PIValueTreeEdit::applyVariantEdit(PIVariantEdit * ve, const PIValueTree & v } +void PIValueTreeEdit::createTabWidget() { + if (tab_widget) return; + tab_widget = new QTabWidget(); + grid->addRow(tab_widget); +} + + void PIValueTreeEdit::newRequest(NewType type) { PIString nn = Q2PIString(QInputDialog::getText(nullptr, tr("New item"), tr("Input new name:"))); if (nn.isEmpty()) return; @@ -396,8 +466,11 @@ PIValueTreeEdit::GridWidgets::GridWidgets(PIValueTreeEdit * p) { a->setSeparator(true); return a; }; - menu_group.addActions( - {p->widget_params->actionRename, p->widget_params->actionReorder, newSeparator(), p->widget_params->actionRemove}); + menu_group.addActions({p->widget_params->actionRename, + p->widget_params->actionReorder, + p->widget_params->menu_grouping.menuAction(), + newSeparator(), + p->widget_params->actionRemove}); menu_conf.addActions({p->widget_params->actionRename, p->widget_params->actionChange, p->widget_params->actionReorder, @@ -468,6 +541,28 @@ void PIValueTreeEdit::GridWidgets::add(const PIValueTree & vt, QWidget * w, bool } +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 QToolButton(); + 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); + 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); @@ -497,31 +592,21 @@ void PIValueTreeEdit::GridWidgets::replace(int row, const PIString & label, QWid int PIValueTreeEdit::GridWidgets::beginRow(const PIValueTree & vt, bool is_group) { if (!create_edit_buttons) return 0; - auto * b = new QToolButton(); - 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); + auto * b = createConfigButton(vt, is_group); lay->addWidget(b, row_count, 0); - connect(b, &QToolButton::triggered, this, [this, b](QAction * a) { - parent->actionTriggered(b, Q2PIString(b->property(property_name).toString()), a); - }); widgets << b; return 1; } void PIValueTreeEdit::GridWidgets::rename(const PIString & prev_name, const PIString & new_name) { - if (parent->is_grouping) { - 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 * 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) @@ -556,12 +641,10 @@ void PIValueTreeEdit::GridWidgets::changed() { void PIValueTreeEdit::GridWidgets::retranslate() { - if (parent->is_grouping) { - for (auto * w: widgets) { - auto * gb = qobject_cast(w); - if (!gb) continue; - gb->setTitle(PIVariantEditorBase::vtTr(Q2PIString(gb->property(property_name).toString()))); - } + 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())); diff --git a/libs/piqt_widgets/pivaluetree_edit.h b/libs/piqt_widgets/pivaluetree_edit.h index 5924398..1409231 100644 --- a/libs/piqt_widgets/pivaluetree_edit.h +++ b/libs/piqt_widgets/pivaluetree_edit.h @@ -30,6 +30,7 @@ class QGridLayout; class QToolButton; +class QTabWidget; class PIVariantEdit; class PIValueTreeEditParameters; class PIValueTreeEditReorder; @@ -39,20 +40,24 @@ class PIValueTreeEditArray; class QAD_PIQT_UTILS_EXPORT PIValueTreeEdit: public QWidget { Q_OBJECT + Q_ENUMS(Grouping) public: PIValueTreeEdit(QWidget * parent = nullptr); ~PIValueTreeEdit(); - enum TreeStyle { - Label + enum Grouping { + Indent, + Groups, + Tabs, + Parent = 0xFF }; void setValue(const PIValueTree & v); PIValueTree value() const; - bool isGroupingEnabled() const { return is_grouping; } - void setGroupingEnabled(bool yes); + Grouping grouping() const { return cur_grouping; } + void setGrouping(Grouping g); bool isFullEditMode() const { return is_full_edit; } void setFullEditMode(bool yes); @@ -79,6 +84,7 @@ private: void applyArrayAttributes(); QLabel * newLabel(const PIValueTree & vt); void applyVariantEdit(PIVariantEdit * ve, const PIValueTree & vt); + void createTabWidget(); class GridWidgets: public QWidget { public: @@ -89,11 +95,14 @@ private: void removeRow(int index); void add(const PIValueTree & vt, const PIString & label, QWidget * w, const PIString & comment, bool is_group = false); void add(const PIValueTree & vt, QWidget * w, bool is_group = false); + void addRow(QWidget * w); + QToolButton * createConfigButton(const PIValueTree & vt, bool is_group); void replace(int row, QWidget * w); void replace(int row, const PIString & label, QWidget * w, const PIString & comment); int beginRow(const PIValueTree & vt, bool is_group); void rename(const PIString & prev_name, const PIString & new_name); void reorder(const PIMap & map) { simplify(map); } + void simplify(const PIMap & map = PIMap()); void clear(); void changed(); void retranslate(); @@ -103,7 +112,6 @@ private: private: int removeRowEdits(int row); - void simplify(const PIMap & map = PIMap()); int row_count = 0; QGridLayout * lay = nullptr; @@ -114,7 +122,8 @@ private: QIcon icon_conf; }; - QWidget * widget_array = nullptr; + QWidget * widget_array = nullptr; + PIValueTreeEdit * parent_tree = nullptr; PIValueTreeEditParameters * widget_params; PIValueTreeEditReorder * widget_reorder; PIStringList root_path; @@ -122,10 +131,12 @@ private: PIMap value_edits; PIMap tree_edits; PIMap comm_labels, label_labels; + QTabWidget * tab_widget = nullptr; Ui::PIValueTreeEditArray * ui_array; - GridWidgets * grid = nullptr; + GridWidgets * grid = nullptr; + Grouping cur_grouping = Parent, real_grouping = Indent; mutable PIValueTree source, current; - bool is_grouping = true, is_full_edit = false; + bool is_full_edit = false; }; diff --git a/libs/piqt_widgets/pivaluetree_edit_parameters.cpp b/libs/piqt_widgets/pivaluetree_edit_parameters.cpp index 4efa616..95f7baf 100644 --- a/libs/piqt_widgets/pivaluetree_edit_parameters.cpp +++ b/libs/piqt_widgets/pivaluetree_edit_parameters.cpp @@ -1,10 +1,12 @@ #include "pivaluetree_edit_parameters.h" #include "piqt.h" +#include "pivaluetree_edit.h" #include "pivariant_edit.h" #include #include +#include using Attribute = PIValueTree::Attribute; @@ -13,6 +15,19 @@ const char property_name[] = "__name__"; PIValueTreeEditParameters::PIValueTreeEditParameters(QWidget * parent): QDialog(parent) { setupUi(this); + auto * ag = new QActionGroup(this); + ag->setExclusive(true); + // connect(ag, &QActionGroup::triggered, [this](QAction * a) { widget->setGrouping((PIValueTreeEdit::Grouping)a->data().toInt()); }); + auto mo = PIValueTreeEdit::staticMetaObject; + auto me = mo.enumerator(mo.indexOfEnumerator("Grouping")); + for (int i = 0; i < me.keyCount(); ++i) { + auto * a = ag->addAction(me.key(i)); + a->setCheckable(true); + a->setData(me.value(i)); + if (me.value(i) == PIValueTreeEdit::Indent) a->setChecked(true); + } + menu_grouping.addActions(ag->actions()); + menu_grouping.menuAction()->setText(tr("Grouping")); } diff --git a/libs/piqt_widgets/pivaluetree_edit_parameters.h b/libs/piqt_widgets/pivaluetree_edit_parameters.h index e96c370..b34f378 100644 --- a/libs/piqt_widgets/pivaluetree_edit_parameters.h +++ b/libs/piqt_widgets/pivaluetree_edit_parameters.h @@ -26,6 +26,7 @@ #include #include #include +#include class PIVariantEdit; @@ -40,6 +41,8 @@ public: bool showFor(PIValueTree & vt); + QMenu menu_grouping; + private: void createAttributes(QList & list, QFormLayout * lay, const PIVariantMap & attr = PIVariantMap(), bool inv_filter = false); diff --git a/libs/piqt_widgets/pivariant_edit.cpp b/libs/piqt_widgets/pivariant_edit.cpp index 04fca50..ceb79a5 100644 --- a/libs/piqt_widgets/pivariant_edit.cpp +++ b/libs/piqt_widgets/pivariant_edit.cpp @@ -1,6 +1,7 @@ #include "pivariant_edit.h" #include "piqt.h" +#include "pivaluetree_edit.h" #include @@ -33,6 +34,15 @@ PIVariantMap PIVariantEditorBase::editorDefaultAttributes(uint type_id) { } +PIVariantTypes::Enum PIVariantEditorBase::createGrouping() { + PIVariantTypes::Enum ret; + ret << PIVariantTypes::Enumerator(PIValueTreeEdit::Indent, "indent") << PIVariantTypes::Enumerator(PIValueTreeEdit::Groups, "groups") + << PIVariantTypes::Enumerator(PIValueTreeEdit::Tabs, "tabs") << PIVariantTypes::Enumerator(PIValueTreeEdit::Parent, "parent"); + ret.selectValue(PIValueTreeEdit::Parent); + return ret; +} + + void PIVariantEditorBase::createBoxLayout(QBoxLayout::Direction d) { auto * l = new QBoxLayout(d); l->setContentsMargins(0, 0, 0, 0); @@ -58,12 +68,9 @@ PIMap & PIVariantEditorBase::default_attributes() { } -PIVariantEdit::PIVariantEdit(QWidget * parent): QWidget(parent) { +PIVariantEdit::PIVariantEdit(QWidget * parent): PIVariantEditorBase(parent) { label = new QLabel(); label->setAlignment(Qt::AlignCenter); - auto * l = new QBoxLayout(QBoxLayout::LeftToRight); - l->setContentsMargins(0, 0, 0, 0); - setLayout(l); setValue(PIVariant()); } diff --git a/libs/piqt_widgets/pivariant_edit.h b/libs/piqt_widgets/pivariant_edit.h index c77c955..c9f49ce 100644 --- a/libs/piqt_widgets/pivariant_edit.h +++ b/libs/piqt_widgets/pivariant_edit.h @@ -40,7 +40,7 @@ class QAD_PIQT_UTILS_EXPORT PIVariantEditorBase: public QWidget { friend class PIVariantEdit; public: - PIVariantEditorBase() { createBoxLayout(); } + PIVariantEditorBase(QWidget * parent = nullptr): QWidget(parent) { createBoxLayout(); } virtual ~PIVariantEditorBase() {} virtual void setValue(const PIVariant & v) = 0; @@ -67,6 +67,7 @@ public: static PIVariantEditorBase * createEditor(uint type_id); static bool editorExists(uint type_id); static PIVariantMap editorDefaultAttributes(uint type_id); + static PIVariantTypes::Enum createGrouping(); protected: void createBoxLayout(QBoxLayout::Direction d = QBoxLayout::LeftToRight); @@ -82,21 +83,22 @@ private: }; -class QAD_PIQT_UTILS_EXPORT PIVariantEdit: public QWidget { +class QAD_PIQT_UTILS_EXPORT PIVariantEdit: public PIVariantEditorBase { Q_OBJECT public: PIVariantEdit(QWidget * parent = nullptr); ~PIVariantEdit(); - void setValue(const PIVariant & v, uint type_id = 0); - PIVariant value() const; + void setValue(const PIVariant & v, uint type_id); + void setValue(const PIVariant & v) override { setValue(v, v.typeID()); } + PIVariant value() const override; void setAttributes(const PIVariantMap & a); - PIVariantMap attributes() const; + PIVariantMap attributes() const override; - void setFullEditMode(bool on); - void retranslate(); + void setFullEditMode(bool on) override; + void retranslate() override; private: PIVariantEditorBase * editor = nullptr; diff --git a/utils/valuetreeeditor/mainwindow.cpp b/utils/valuetreeeditor/mainwindow.cpp index 3fb506d..a1a8303 100644 --- a/utils/valuetreeeditor/mainwindow.cpp +++ b/utils/valuetreeeditor/mainwindow.cpp @@ -3,7 +3,9 @@ #include "piqt.h" #include "qad_locations.h" +#include #include +#include #include #include #include @@ -15,7 +17,19 @@ MainWindow::MainWindow(QWidget * parent): EMainWindow(parent), Ui::MainWindow() session.setFile(QAD::userPath(QAD::ltConfig, "session_valuetreeeditor")); session.addEntry(this); session.load(); - widget->setGroupingEnabled(actionGrouping->isChecked()); + auto * ag = new QActionGroup(this); + ag->setExclusive(true); + connect(ag, &QActionGroup::triggered, [this](QAction * a) { widget->setGrouping((PIValueTreeEdit::Grouping)a->data().toInt()); }); + auto mo = PIValueTreeEdit::staticMetaObject; + auto me = mo.enumerator(mo.indexOfEnumerator("Grouping")); + for (int i = 0; i < me.keyCount(); ++i) { + if (me.value(i) == PIValueTreeEdit::Parent) continue; + auto * a = ag->addAction(me.key(i)); + a->setCheckable(true); + a->setData(me.value(i)); + if (me.value(i) == PIValueTreeEdit::Indent) a->setChecked(true); + } + menuView->addActions(ag->actions()); widget->setFullEditMode(actionFull_edit_mode->isChecked()); } @@ -80,11 +94,6 @@ QString MainWindow::loadFilter() { } -void MainWindow::on_actionGrouping_toggled(bool on) { - widget->setGroupingEnabled(on); -} - - void MainWindow::on_actionFull_edit_mode_toggled(bool on) { widget->setFullEditMode(on); } diff --git a/utils/valuetreeeditor/mainwindow.h b/utils/valuetreeeditor/mainwindow.h index b7651f9..e0b6808 100644 --- a/utils/valuetreeeditor/mainwindow.h +++ b/utils/valuetreeeditor/mainwindow.h @@ -19,13 +19,12 @@ public: bool save(const QString & path) override; protected: - void changeEvent(QEvent * e); + void changeEvent(QEvent * e) override; QString loadFilter() override; QString saveFilter() override { return loadFilter(); } private slots: - void on_actionGrouping_toggled(bool on); void on_actionFull_edit_mode_toggled(bool on); }; diff --git a/utils/valuetreeeditor/mainwindow.ui b/utils/valuetreeeditor/mainwindow.ui index 993e8f8..7d680dc 100644 --- a/utils/valuetreeeditor/mainwindow.ui +++ b/utils/valuetreeeditor/mainwindow.ui @@ -44,13 +44,20 @@ 0 0 780 - 446 + 444 + + + + Qt::Vertical + + + @@ -94,8 +101,8 @@ View - + @@ -138,7 +145,7 @@ - + :/icons/document-new.png:/icons/document-new.png @@ -157,14 +164,6 @@ About ... - - - true - - - Grouping - - true @@ -189,6 +188,7 @@ +