diff --git a/CMakeLists.txt b/CMakeLists.txt index a236e59..d975692 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,7 +4,7 @@ cmake_policy(SET CMP0072 NEW) # FindOpenGL prefers GLVND by default project(QAD) set(QAD_MAJOR 2) set(QAD_MINOR 16) -set(QAD_REVISION 2) +set(QAD_REVISION 3) set(QAD_SUFFIX ) set(QAD_COMPANY SHS) set(QAD_DOMAIN org.SHS) diff --git a/libs/application/emainwindow.cpp b/libs/application/emainwindow.cpp index 7203708..9de81e2 100644 --- a/libs/application/emainwindow.cpp +++ b/libs/application/emainwindow.cpp @@ -416,7 +416,7 @@ bool EMainWindow::saveFile(bool ask) { bool EMainWindow::saveAsFile() { QString ret = QFileDialog::getSaveFileName(this, tr("Select file to save"), file_name, saveFilter()); if (ret.isEmpty()) return false; - if (save(ret)) addToRecent(ret); + if (save(ret)) addToRecent(file_name); return true; } diff --git a/libs/piqt_utils/pivaluetree_edit.cpp b/libs/piqt_utils/pivaluetree_edit.cpp index 525abba..9b20e78 100644 --- a/libs/piqt_utils/pivaluetree_edit.cpp +++ b/libs/piqt_utils/pivaluetree_edit.cpp @@ -1,11 +1,14 @@ #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 @@ -19,6 +22,20 @@ 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() { @@ -239,134 +256,210 @@ void PIValueTreeEdit::applyValues() const { } +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) { - 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; - } - } - } + actionRename(button, vn); 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); + actionRemove(button, vn); return; } if (a == widget_params->actionChange) { - 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())); + actionChange(button, vn); return; } if (a == widget_params->actionReorder) { - 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]); - } + 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); +} + + PIValueTreeEdit * PIValueTreeEdit::addTreeEdit(const PIValueTree & vt) { auto * ve = new PIValueTreeEdit(); PIStringList rp = root_path; @@ -528,24 +621,21 @@ PIValueTreeEdit::GridWidgets::GridWidgets(PIValueTreeEdit * p) { a->setSeparator(true); return a; }; - 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, - newSeparator(), - p->widget_params->actionRemove}); - menu_new.addActions({p->widget_params->actionValue, p->widget_params->actionGroup, p->widget_params->actionArray}); + 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}); + menu_group.addActions(common_actions); + menu_conf.addActions(common_actions); + menu_new.addActions({wp->actionValue, wp->actionGroup, wp->actionArray}); button_add = new QToolButton(); button_add->setIcon(QIcon(":/icons/list-add.png")); button_add->setPopupMode(QToolButton::InstantPopup); button_add->setMenu(&menu_new); - p->widget_params->actionValue->setData((int)NewType::Value); - p->widget_params->actionGroup->setData((int)NewType::Group); - p->widget_params->actionArray->setData((int)NewType::Array); + 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) { parent->newRequest((NewType)a->data().toInt()); }); } @@ -612,12 +702,14 @@ void PIValueTreeEdit::GridWidgets::addRow(QWidget * w) { QToolButton * PIValueTreeEdit::GridWidgets::createConfigButton(const PIValueTree & vt, bool is_group) { - auto * b = new QToolButton(); + 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); }); diff --git a/libs/piqt_utils/pivaluetree_edit.h b/libs/piqt_utils/pivaluetree_edit.h index 40837c4..dc344aa 100644 --- a/libs/piqt_utils/pivaluetree_edit.h +++ b/libs/piqt_utils/pivaluetree_edit.h @@ -80,7 +80,14 @@ private: void removeAll(); void build(); void applyValues() const; + void actionRename(QToolButton * button, const PIString & vn); + void actionRemove(QToolButton * button, const PIString & vn); + void actionChange(QToolButton * button, const PIString & vn); + void actionReorder(QToolButton * button, const PIString & vn); + void actionCopy(QToolButton * button, const PIString & vn); + void actionPaste(QToolButton * button, const PIString & vn, int offset); void actionTriggered(QToolButton * button, const PIString & vn, QAction * a); + void checkActions(); void newRequest(NewType type); PIValueTreeEdit * addTreeEdit(const PIValueTree & vt); PIValueTreeEdit * rootTreeEdit(); diff --git a/libs/piqt_utils/pivaluetree_edit_parameters.ui b/libs/piqt_utils/pivaluetree_edit_parameters.ui index 232eb0c..4458dc0 100644 --- a/libs/piqt_utils/pivaluetree_edit_parameters.ui +++ b/libs/piqt_utils/pivaluetree_edit_parameters.ui @@ -167,6 +167,48 @@ Reorder ... + + + + :/icons/edit-copy.png:/icons/edit-copy.png + + + Copy + + + + + + :/icons/edit-cut.png:/icons/edit-cut.png + + + Cut + + + + + + :/icons/edit-paste.png:/icons/edit-paste.png + + + Paste before + + + Paste before + + + + + + :/icons/edit-paste.png:/icons/edit-paste.png + + + Paste after + + + Paste after + + @@ -185,6 +227,7 @@ + diff --git a/libs/piqt_utils/pivaluetree_edit_reorder.ui b/libs/piqt_utils/pivaluetree_edit_reorder.ui index 2366088..3779b70 100644 --- a/libs/piqt_utils/pivaluetree_edit_reorder.ui +++ b/libs/piqt_utils/pivaluetree_edit_reorder.ui @@ -45,76 +45,8 @@ - - - - :/icons/edit-delete.png:/icons/edit-delete.png - - - Remove - - - - - - :/icons/configure.png:/icons/configure.png - - - Change ... - - - - - - :/icons/border-line.png:/icons/border-line.png - - - Rename ... - - - - - - :/icons/code-variable.png:/icons/code-variable.png - - - Value - - - - - - :/icons/code-struct.png:/icons/code-struct.png - - - Group - - - - - - :/icons/code-union.png:/icons/code-union.png - - - Array - - - - - - :/icons/legend.png:/icons/legend.png - - - Reorder ... - - - - - - - - + buttonBox diff --git a/libs/piqt_utils/pivariant_edit_enum.ui b/libs/piqt_utils/pivariant_edit_enum.ui index 0553e2e..d15774e 100644 --- a/libs/piqt_utils/pivariant_edit_enum.ui +++ b/libs/piqt_utils/pivariant_edit_enum.ui @@ -74,6 +74,12 @@ Qt::Horizontal + + + 0 + 0 + + @@ -116,74 +122,10 @@ - - - - :/icons/edit-delete.png:/icons/edit-delete.png - - - Remove - - - - - - :/icons/configure.png:/icons/configure.png - - - Change ... - - - - - - :/icons/border-line.png:/icons/border-line.png - - - Rename ... - - - - - - :/icons/code-variable.png:/icons/code-variable.png - - - Value - - - - - - :/icons/code-struct.png:/icons/code-struct.png - - - Group - - - - - - :/icons/code-union.png:/icons/code-union.png - - - Array - - - - - - :/icons/legend.png:/icons/legend.png - - - Reorder ... - - - diff --git a/libs/piqt_utils/qad_piqt_widgets.qrc b/libs/piqt_utils/qad_piqt_widgets.qrc index d88ebed..98468f6 100644 --- a/libs/piqt_utils/qad_piqt_widgets.qrc +++ b/libs/piqt_utils/qad_piqt_widgets.qrc @@ -1,5 +1,6 @@ + ../../icons/edit-cut.png ../../icons/configure.png ../../icons/border-line.png ../../icons/list-add.png diff --git a/libs/utils/qad_locations.cpp b/libs/utils/qad_locations.cpp index b77d67a..440f7f2 100644 --- a/libs/utils/qad_locations.cpp +++ b/libs/utils/qad_locations.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) # include @@ -74,12 +75,22 @@ void QAD::loadTranslations(QString lang) { if (lang.isEmpty()) lang = QLocale().bcp47Name(); QString short_lang = lang.left(2); QStringList dirs = resourcePaths("lang"); + QString std_dir = QDir::cleanPath(QLibraryInfo::location(QLibraryInfo::TranslationsPath)); + bool has_std = false; + for (const QString & d: dirs) { + if (QDir::cleanPath(d) == std_dir) { + has_std = true; + break; + } + } + if (!has_std) dirs << std_dir; for (const QString & d: dirs) { QDirIterator dit(d); while (dit.hasNext()) { dit.next(); if (!dit.filePath().endsWith(".qm")) continue; if (!dit.fileInfo().baseName().endsWith(lang) && !dit.fileInfo().baseName().endsWith(short_lang)) continue; + if (dit.fileName() == QString("qt_%1.qm").arg(short_lang)) continue; QTranslator * tr = new QTranslator(); if (tr->load(dit.filePath())) { qApp->installTranslator(tr);