diff --git a/CodeGenerator/codegenerator.cpp b/CodeGenerator/codegenerator.cpp index 351375d..375f6be 100644 --- a/CodeGenerator/codegenerator.cpp +++ b/CodeGenerator/codegenerator.cpp @@ -193,6 +193,10 @@ CodeGenerator::CodeGenerator(QObject* parent) : { qRegisterMetaType("codegen::GeneratedCodeStorage"); qRegisterMetaType("codegen::GeneratedFunction"); + qRegisterMetaType("codegen::GeneratedBase"); + qRegisterMetaType("codegen::GeneratedParameter"); + qRegisterMetaType("codegen::GeneratedPDFObject"); + qRegisterMetaType("codegen::GeneratedAction"); qRegisterMetaType("QObjectList"); } @@ -355,6 +359,20 @@ bool GeneratedFunction::canHaveSubitems() const return true; } +QStringList GeneratedFunction::getCaptions() const +{ + return QStringList() << QString("Function") << QString("%1 %2(...)").arg(Serializer::convertEnumToString(m_returnType), m_functionName); +} + +GeneratedBase* GeneratedFunction::appendItem() +{ + Q_ASSERT(canHaveSubitems()); + + GeneratedBase* newItem = new GeneratedAction(this); + addItem(newItem); + return newItem; +} + GeneratedFunction::DataType GeneratedFunction::getReturnType() const { return m_returnType; @@ -465,6 +483,30 @@ bool GeneratedAction::canHaveSubitems() const return false; } +QStringList GeneratedAction::getCaptions() const +{ + return QStringList() << QString("Action %1").arg(Serializer::convertEnumToString(m_actionType)) << (!m_variableName.isEmpty() ? QString("%1 %2").arg(Serializer::convertEnumToString(m_variableType), m_variableName) : QString()); +} + +GeneratedBase* GeneratedAction::appendItem() +{ + Q_ASSERT(canHaveSubitems()); + GeneratedBase* newItem = nullptr; + switch (m_actionType) + { + case Parameters: + newItem = new GeneratedParameter(this); + break; + + default: + newItem = new GeneratedPDFObject(this); + break; + } + + addItem(newItem); + return newItem; +} + GeneratedAction::ActionType GeneratedAction::getActionType() const { return m_actionType; @@ -510,6 +552,105 @@ void GeneratedAction::setCode(const QString& code) m_code = code; } +bool GeneratedBase::canPerformOperation(Operation operation) const +{ + const bool isFunction = qobject_cast(this) != nullptr; + switch (operation) + { + case Operation::Delete: + return !isFunction; + + case Operation::MoveUp: + { + if (const GeneratedBase* parentBase = getParent()) + { + QObjectList items = parentBase->getItems(); + return items.indexOf(const_cast(this)) > 0; + } + + break; + } + + case Operation::MoveDown: + { + if (const GeneratedBase* parentBase = getParent()) + { + QObjectList items = parentBase->getItems(); + return items.indexOf(const_cast(this)) < items.size() - 1; + } + + break; + } + + case Operation::NewSibling: + return !isFunction; + + case Operation::NewChild: + return canHaveSubitems(); + + default: + break; + } + + return false; +} + +void GeneratedBase::performOperation(GeneratedBase::Operation operation) +{ + switch (operation) + { + case Operation::Delete: + { + getParent()->removeItem(this); + break; + } + + case Operation::MoveUp: + { + GeneratedBase* parentItem = getParent(); + QObjectList items = parentItem->getItems(); + const int index = items.indexOf(this); + items.removeAll(const_cast(this)); + items.insert(index - 1, this); + parentItem->setItems(qMove(items)); + break; + } + + case Operation::MoveDown: + { + GeneratedBase* parentItem = getParent(); + QObjectList items = parentItem->getItems(); + const int index = items.indexOf(this); + items.removeAll(const_cast(this)); + items.insert(index + 1, this); + parentItem->setItems(qMove(items)); + break; + } + + case Operation::NewSibling: + { + GeneratedBase* parentItem = getParent(); + if (GeneratedBase* createdItem = parentItem->appendItem()) + { + QObjectList items = parentItem->getItems(); + items.removeAll(createdItem); + items.insert(items.indexOf(const_cast(this)), createdItem); + parentItem->setItems(qMove(items)); + } + break; + } + + case Operation::NewChild: + { + appendItem(); + break; + } + + default: + break; + } +} + QObjectList GeneratedBase::getItems() const { return m_items; @@ -628,6 +769,46 @@ bool GeneratedPDFObject::canHaveSubitems() const return false; } +QStringList GeneratedPDFObject::getCaptions() const +{ + QString name; + switch (m_objectType) + { + case Object: + name = tr("Object"); + break; + case ArraySimple: + name = tr("Array (simple)"); + break; + case ArrayComplex: + name = tr("Array (complex)"); + break; + case Dictionary: + name = tr("Dictionary"); + break; + case DictionaryItemSimple: + name = tr("Item (simple), name = '%1'").arg(m_dictionaryItemName); + break; + case DictionaryItemComplex: + name = tr("Item (complex), name = '%1'").arg(m_dictionaryItemName); + break; + + default: + Q_ASSERT(false); + break; + } + + return QStringList() << name << m_value; +} + +GeneratedBase* GeneratedPDFObject::appendItem() +{ + Q_ASSERT(canHaveSubitems()); + GeneratedBase* newItem = new GeneratedPDFObject(this); + addItem(newItem); + return newItem; +} + QString GeneratedPDFObject::getValue() const { return m_value; @@ -740,6 +921,16 @@ bool GeneratedParameter::canHaveSubitems() const return false; } +QStringList GeneratedParameter::getCaptions() const +{ + return QStringList() << QString("%1 %2").arg(Serializer::convertEnumToString(m_parameterDataType)).arg(m_parameterName) << m_parameterDescription; +} + +GeneratedBase* GeneratedParameter::appendItem() +{ + return nullptr; +} + QString GeneratedParameter::getParameterName() const { return m_parameterName; diff --git a/CodeGenerator/codegenerator.h b/CodeGenerator/codegenerator.h index e0e6602..f1cecc2 100644 --- a/CodeGenerator/codegenerator.h +++ b/CodeGenerator/codegenerator.h @@ -142,6 +142,22 @@ public: virtual void writeField(FieldType fieldType, QVariant value) = 0; virtual void fillComboBox(QComboBox* comboBox, FieldType fieldType) = 0; virtual bool canHaveSubitems() const = 0; + virtual QStringList getCaptions() const = 0; + virtual GeneratedBase* appendItem() = 0; + + enum class Operation + { + Delete, + MoveUp, + MoveDown, + NewSibling, + NewChild + }; + + GeneratedBase* getParent() { return qobject_cast(parent()); } + const GeneratedBase* getParent() const { return qobject_cast(parent()); } + bool canPerformOperation(Operation operation) const; + void performOperation(Operation operation); QObjectList getItems() const; void setItems(const QObjectList& items); @@ -171,6 +187,8 @@ public: virtual void writeField(FieldType fieldType, QVariant value) override; virtual void fillComboBox(QComboBox* comboBox, FieldType fieldType) override; virtual bool canHaveSubitems() const override; + virtual QStringList getCaptions() const override; + virtual GeneratedBase* appendItem() override; QString getParameterName() const; void setParameterName(const QString& parameterName); @@ -217,6 +235,8 @@ public: virtual void writeField(FieldType fieldType, QVariant value) override; virtual void fillComboBox(QComboBox* comboBox, FieldType fieldType) override; virtual bool canHaveSubitems() const override; + virtual QStringList getCaptions() const override; + virtual GeneratedBase* appendItem() override; QString getValue() const; void setValue(const QString& value); @@ -261,6 +281,8 @@ public: virtual void writeField(FieldType fieldType, QVariant value) override; virtual void fillComboBox(QComboBox* comboBox, FieldType fieldType) override; virtual bool canHaveSubitems() const override; + virtual QStringList getCaptions() const override; + virtual GeneratedBase* appendItem() override; ActionType getActionType() const; void setActionType(ActionType actionType); @@ -310,6 +332,8 @@ public: virtual void writeField(FieldType fieldType, QVariant value) override; virtual void fillComboBox(QComboBox* comboBox, FieldType fieldType) override; virtual bool canHaveSubitems() const override; + virtual QStringList getCaptions() const override; + virtual GeneratedBase* appendItem() override; QString getFunctionTypeString() const; void setFunctionTypeString(const QString& string); diff --git a/CodeGenerator/generatormainwindow.cpp b/CodeGenerator/generatormainwindow.cpp index ec25bbd..dfbfee3 100644 --- a/CodeGenerator/generatormainwindow.cpp +++ b/CodeGenerator/generatormainwindow.cpp @@ -32,10 +32,13 @@ GeneratorMainWindow::GeneratorMainWindow(QWidget *parent) : ui(new Ui::GeneratorMainWindow), m_generator(new codegen::CodeGenerator(this)), m_currentFunction(nullptr), + m_currentSettings(nullptr), m_isLoadingData(false) { ui->setupUi(this); + ui->parameterTreeWidget->header()->setMinimumSectionSize(200); + m_generator->initialize(); loadSettings(); @@ -45,6 +48,12 @@ GeneratorMainWindow::GeneratorMainWindow(QWidget *parent) : load(m_defaultFileName); } connect(ui->generatedFunctionsTreeWidget, &QTreeWidget::currentItemChanged, this, &GeneratorMainWindow::onCurrentItemChanged); + connect(ui->parameterTreeWidget, &QTreeWidget::currentItemChanged, this, &GeneratorMainWindow::onParameterTreeCurrentItemChanged); + connect(ui->parameterNameEdit, &QLineEdit::editingFinished, this, &GeneratorMainWindow::saveGeneratedSettings); + connect(ui->parameterItemTypeCombo, QOverload::of(&QComboBox::currentIndexChanged), this, &GeneratorMainWindow::saveGeneratedSettings); + connect(ui->parameterDataTypeCombo, QOverload::of(&QComboBox::currentIndexChanged), this, &GeneratorMainWindow::saveGeneratedSettings); + connect(ui->parameterValueEdit, &QLineEdit::editingFinished, this, &GeneratorMainWindow::saveGeneratedSettings); + connect(ui->parameterDescriptionEdit, &QTextBrowser::textChanged, this, &GeneratorMainWindow::saveGeneratedSettings); setWindowState(Qt::WindowMaximized); updateFunctionListUI(); @@ -76,6 +85,117 @@ void GeneratorMainWindow::saveSettings() settings.setValue("fileName", m_defaultFileName); } +void GeneratorMainWindow::loadGeneratedSettings() +{ + BoolGuard guard(m_isLoadingData); + + const bool hasName = m_currentSettings && m_currentSettings->hasField(codegen::GeneratedBase::FieldType::Name); + const bool hasItemType = m_currentSettings && m_currentSettings->hasField(codegen::GeneratedBase::FieldType::ItemType); + const bool hasDataType = m_currentSettings && m_currentSettings->hasField(codegen::GeneratedBase::FieldType::DataType); + const bool hasValue = m_currentSettings && m_currentSettings->hasField(codegen::GeneratedBase::FieldType::Value); + const bool hasDescription = m_currentSettings && m_currentSettings->hasField(codegen::GeneratedBase::FieldType::Description); + + ui->parameterNameEdit->setEnabled(hasName); + ui->parameterItemTypeCombo->setEnabled(hasItemType); + ui->parameterDataTypeCombo->setEnabled(hasDataType); + ui->parameterValueEdit->setEnabled(hasValue); + ui->parameterDescriptionEdit->setEnabled(hasDescription); + + if (hasName) + { + ui->parameterNameEdit->setText(m_currentSettings->readField(codegen::GeneratedBase::FieldType::Name).toString()); + } + else + { + ui->parameterNameEdit->clear(); + } + + if (hasItemType) + { + m_currentSettings->fillComboBox(ui->parameterItemTypeCombo, codegen::GeneratedBase::FieldType::ItemType); + } + else + { + ui->parameterItemTypeCombo->clear(); + } + + if (hasDataType) + { + m_currentSettings->fillComboBox(ui->parameterDataTypeCombo, codegen::GeneratedBase::FieldType::DataType); + } + else + { + ui->parameterDataTypeCombo->clear(); + } + + if (hasValue) + { + ui->parameterValueEdit->setText(m_currentSettings->readField(codegen::GeneratedBase::FieldType::Value).toString()); + } + else + { + ui->parameterValueEdit->clear(); + } + + if (hasDescription) + { + ui->parameterDescriptionEdit->setText(m_currentSettings->readField(codegen::GeneratedBase::FieldType::Description).toString()); + } + else + { + ui->parameterDescriptionEdit->clear(); + } + + ui->itemDeleteButton->setEnabled(m_currentSettings && m_currentSettings->canPerformOperation(codegen::GeneratedBase::Operation::Delete)); + ui->itemUpButton->setEnabled(m_currentSettings && m_currentSettings->canPerformOperation(codegen::GeneratedBase::Operation::MoveUp)); + ui->itemDownButton->setEnabled(m_currentSettings && m_currentSettings->canPerformOperation(codegen::GeneratedBase::Operation::MoveDown)); + ui->itemNewSiblingButton->setEnabled(m_currentSettings && m_currentSettings->canPerformOperation(codegen::GeneratedBase::Operation::NewSibling)); + ui->itemNewChildButton->setEnabled(m_currentSettings && m_currentSettings->canPerformOperation(codegen::GeneratedBase::Operation::NewChild)); +} + +void GeneratorMainWindow::saveGeneratedSettings() +{ + if (m_isLoadingData || !m_currentSettings) + { + return; + } + + const bool hasName = m_currentSettings && m_currentSettings->hasField(codegen::GeneratedBase::FieldType::Name); + const bool hasItemType = m_currentSettings && m_currentSettings->hasField(codegen::GeneratedBase::FieldType::ItemType); + const bool hasDataType = m_currentSettings && m_currentSettings->hasField(codegen::GeneratedBase::FieldType::DataType); + const bool hasValue = m_currentSettings && m_currentSettings->hasField(codegen::GeneratedBase::FieldType::Value); + const bool hasDescription = m_currentSettings && m_currentSettings->hasField(codegen::GeneratedBase::FieldType::Description); + + m_currentSettings->writeField(codegen::GeneratedBase::FieldType::Name, hasName ? ui->parameterNameEdit->text() : QVariant()); + m_currentSettings->writeField(codegen::GeneratedBase::FieldType::ItemType, hasItemType ? ui->parameterItemTypeCombo->currentData() : QVariant()); + m_currentSettings->writeField(codegen::GeneratedBase::FieldType::DataType, hasDataType ? ui->parameterDataTypeCombo->currentData() : QVariant()); + m_currentSettings->writeField(codegen::GeneratedBase::FieldType::Value, hasValue ? ui->parameterValueEdit->text() : QVariant()); + m_currentSettings->writeField(codegen::GeneratedBase::FieldType::Description, hasDescription ? ui->parameterDescriptionEdit->toPlainText() : QVariant()); + + if (sender() != ui->parameterDescriptionEdit) + { + loadGeneratedSettings(); + + // Update the captions + std::function updateFunction = [&](QTreeWidgetItem* item) + { + const codegen::GeneratedBase* generatedBase = item->data(0, Qt::UserRole).value(); + QStringList captions = generatedBase->getCaptions(); + + for (int i = 0; i < captions.size(); ++i) + { + item->setText(i, captions[i]); + } + + for (int i = 0; i < item->childCount(); ++i) + { + updateFunction(item->child(i)); + } + }; + updateFunction(ui->parameterTreeWidget->topLevelItem(0)); + } +} + void GeneratorMainWindow::updateFunctionListUI() { BoolGuard guard(m_isLoadingData); @@ -120,16 +240,61 @@ void GeneratorMainWindow::updateFunctionListUI() { ui->generatedFunctionsTreeWidget->setCurrentItem(it->second, 0, QItemSelectionModel::SelectCurrent); } +} - m_isLoadingData = false; +void GeneratorMainWindow::updateGeneratedSettingsTree() +{ + BoolGuard guard(m_isLoadingData); + + ui->parameterTreeWidget->setUpdatesEnabled(false); + ui->parameterTreeWidget->clear(); + + QTreeWidgetItem* selected = nullptr; + std::function createTree = [this, &selected, &createTree](codegen::GeneratedBase* generatedItem, QTreeWidgetItem* parent) + { + QTreeWidgetItem* item = nullptr; + if (parent) + { + item = new QTreeWidgetItem(parent, generatedItem->getCaptions()); + } + else + { + item = new QTreeWidgetItem(ui->parameterTreeWidget, generatedItem->getCaptions()); + } + + item->setData(0, Qt::UserRole, QVariant::fromValue(generatedItem)); + + if (generatedItem == m_currentSettings) + { + selected = item; + } + + for (QObject* object : generatedItem->getItems()) + { + createTree(qobject_cast(object), item); + } + }; + + if (m_currentFunction) + { + createTree(m_currentFunction, nullptr); + } + + ui->parameterTreeWidget->expandAll(); + ui->parameterTreeWidget->resizeColumnToContents(0); + ui->parameterTreeWidget->setUpdatesEnabled(true); + + if (selected) + { + ui->parameterTreeWidget->setCurrentItem(selected, 0, QItemSelectionModel::SelectCurrent); + } } void GeneratorMainWindow::setCurrentFunction(codegen::GeneratedFunction* currentFunction) { - BoolGuard guard(m_isLoadingData); - if (m_currentFunction != currentFunction) { + BoolGuard guard(m_isLoadingData); m_currentFunction = currentFunction; // Select current function @@ -137,10 +302,23 @@ void GeneratorMainWindow::setCurrentFunction(codegen::GeneratedFunction* current if (it != m_mapFunctionToWidgetItem.cend()) { ui->generatedFunctionsTreeWidget->setCurrentItem(it->second, 0, QItemSelectionModel::SelectCurrent); + ui->generatedFunctionsTreeWidget->setFocus(); + setCurrentSettings(m_currentFunction); + updateGeneratedSettingsTree(); } } } +void GeneratorMainWindow::setCurrentSettings(codegen::GeneratedBase* currentSettings) +{ + if (m_currentSettings != currentSettings) + { + BoolGuard guard(m_isLoadingData); + m_currentSettings = currentSettings; + loadGeneratedSettings(); + } +} + void GeneratorMainWindow::onCurrentItemChanged(QTreeWidgetItem* current, QTreeWidgetItem* previous) { Q_UNUSED(previous); @@ -154,6 +332,19 @@ void GeneratorMainWindow::onCurrentItemChanged(QTreeWidgetItem* current, QTreeWi setCurrentFunction(function); } +void GeneratorMainWindow::onParameterTreeCurrentItemChanged(QTreeWidgetItem* current, QTreeWidgetItem* previous) +{ + Q_UNUSED(previous); + + if (m_isLoadingData) + { + return; + } + + codegen::GeneratedBase* baseObject = current->data(0, Qt::UserRole).value(); + setCurrentSettings(baseObject); +} + void GeneratorMainWindow::loadSettings() { QSettings settings("MelkaJ"); @@ -245,3 +436,53 @@ void GeneratorMainWindow::on_removeFunctionButton_clicked() updateFunctionListUI(); } } + +void GeneratorMainWindow::on_itemDeleteButton_clicked() +{ + if (m_currentSettings) + { + m_currentSettings->performOperation(codegen::GeneratedBase::Operation::Delete); + setCurrentSettings(m_currentFunction); + updateGeneratedSettingsTree(); + } +} + +void GeneratorMainWindow::on_itemUpButton_clicked() +{ + if (m_currentSettings) + { + m_currentSettings->performOperation(codegen::GeneratedBase::Operation::MoveUp); + updateGeneratedSettingsTree(); + loadGeneratedSettings(); + } +} + +void GeneratorMainWindow::on_itemDownButton_clicked() +{ + if (m_currentSettings) + { + m_currentSettings->performOperation(codegen::GeneratedBase::Operation::MoveDown); + updateGeneratedSettingsTree(); + loadGeneratedSettings(); + } +} + +void GeneratorMainWindow::on_itemNewChildButton_clicked() +{ + if (m_currentSettings) + { + m_currentSettings->performOperation(codegen::GeneratedBase::Operation::NewChild); + updateGeneratedSettingsTree(); + loadGeneratedSettings(); + } +} + +void GeneratorMainWindow::on_itemNewSiblingButton_clicked() +{ + if (m_currentSettings) + { + m_currentSettings->performOperation(codegen::GeneratedBase::Operation::NewSibling); + updateGeneratedSettingsTree(); + loadGeneratedSettings(); + } +} diff --git a/CodeGenerator/generatormainwindow.h b/CodeGenerator/generatormainwindow.h index 1484f5a..299c811 100644 --- a/CodeGenerator/generatormainwindow.h +++ b/CodeGenerator/generatormainwindow.h @@ -26,6 +26,7 @@ namespace codegen { class CodeGenerator; class GeneratedFunction; +class GeneratedBase; } namespace Ui @@ -71,18 +72,30 @@ private slots: void on_newFunctionButton_clicked(); void on_cloneFunctionButton_clicked(); void on_removeFunctionButton_clicked(); + void on_itemDeleteButton_clicked(); + void on_itemUpButton_clicked(); + void on_itemDownButton_clicked(); + void on_itemNewChildButton_clicked(); + void on_itemNewSiblingButton_clicked(); private: void loadSettings(); void saveSettings(); + void loadGeneratedSettings(); + void saveGeneratedSettings(); + void updateFunctionListUI(); + void updateGeneratedSettingsTree(); void setCurrentFunction(codegen::GeneratedFunction* currentFunction); + void setCurrentSettings(codegen::GeneratedBase* currentSettings); void onCurrentItemChanged(QTreeWidgetItem* current, QTreeWidgetItem* previous); + void onParameterTreeCurrentItemChanged(QTreeWidgetItem* current, QTreeWidgetItem* previous); Ui::GeneratorMainWindow* ui; codegen::CodeGenerator* m_generator; codegen::GeneratedFunction* m_currentFunction; + codegen::GeneratedBase* m_currentSettings; QString m_defaultFileName; std::map m_mapFunctionToWidgetItem; bool m_isLoadingData; diff --git a/CodeGenerator/generatormainwindow.ui b/CodeGenerator/generatormainwindow.ui index 5fbaf35..b2d8fba 100644 --- a/CodeGenerator/generatormainwindow.ui +++ b/CodeGenerator/generatormainwindow.ui @@ -97,10 +97,13 @@ - + false + + Qt::LinksAccessibleByKeyboard|Qt::LinksAccessibleByMouse|Qt::TextBrowserInteraction|Qt::TextEditable|Qt::TextSelectableByMouse + @@ -127,7 +130,7 @@ - Text description + Text description / C++ code @@ -139,11 +142,22 @@ + + 2 + + + false + 1 + + + 2 + +