Code generator - UI finishing

This commit is contained in:
Jakub Melka 2020-03-15 18:53:44 +01:00
parent c17b9c347c
commit 36cdb41cdb
5 changed files with 488 additions and 5 deletions

View File

@ -193,6 +193,10 @@ CodeGenerator::CodeGenerator(QObject* parent) :
{
qRegisterMetaType<GeneratedCodeStorage*>("codegen::GeneratedCodeStorage");
qRegisterMetaType<GeneratedFunction*>("codegen::GeneratedFunction");
qRegisterMetaType<GeneratedBase*>("codegen::GeneratedBase");
qRegisterMetaType<GeneratedParameter*>("codegen::GeneratedParameter");
qRegisterMetaType<GeneratedPDFObject*>("codegen::GeneratedPDFObject");
qRegisterMetaType<GeneratedAction*>("codegen::GeneratedAction");
qRegisterMetaType<QObjectList>("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<const GeneratedFunction*>(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<codegen::GeneratedBase*>(this)) > 0;
}
break;
}
case Operation::MoveDown:
{
if (const GeneratedBase* parentBase = getParent())
{
QObjectList items = parentBase->getItems();
return items.indexOf(const_cast<codegen::GeneratedBase*>(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<codegen::GeneratedBase*>(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<codegen::GeneratedBase*>(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<codegen::GeneratedBase*>(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;

View File

@ -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<GeneratedBase*>(parent()); }
const GeneratedBase* getParent() const { return qobject_cast<const GeneratedBase*>(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);

View File

@ -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<int>::of(&QComboBox::currentIndexChanged), this, &GeneratorMainWindow::saveGeneratedSettings);
connect(ui->parameterDataTypeCombo, QOverload<int>::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<void(QTreeWidgetItem*)> updateFunction = [&](QTreeWidgetItem* item)
{
const codegen::GeneratedBase* generatedBase = item->data(0, Qt::UserRole).value<codegen::GeneratedBase*>();
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<void(codegen::GeneratedBase*, QTreeWidgetItem*)> 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<codegen::GeneratedBase*>(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<codegen::GeneratedBase*>();
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();
}
}

View File

@ -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<codegen::GeneratedFunction*, QTreeWidgetItem*> m_mapFunctionToWidgetItem;
bool m_isLoadingData;

View File

@ -97,10 +97,13 @@
<widget class="QLineEdit" name="parameterNameEdit"/>
</item>
<item row="1" column="3" rowspan="4">
<widget class="QTextBrowser" name="descriptionEdit">
<widget class="QTextBrowser" name="parameterDescriptionEdit">
<property name="acceptRichText">
<bool>false</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByKeyboard|Qt::LinksAccessibleByMouse|Qt::TextBrowserInteraction|Qt::TextEditable|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="4" column="0">
@ -127,7 +130,7 @@
<item row="0" column="3">
<widget class="QLabel" name="descriptionLabel">
<property name="text">
<string>Text description</string>
<string>Text description / C++ code</string>
</property>
</widget>
</item>
@ -139,11 +142,22 @@
</item>
<item>
<widget class="QTreeWidget" name="parameterTreeWidget">
<property name="columnCount">
<number>2</number>
</property>
<attribute name="headerVisible">
<bool>false</bool>
</attribute>
<column>
<property name="text">
<string notr="true">1</string>
</property>
</column>
<column>
<property name="text">
<string notr="true">2</string>
</property>
</column>
</widget>
</item>
<item>