Split custom attributes frame/table

This commit is contained in:
GriffinR 2024-01-11 16:42:54 -05:00
parent 6e65d591c3
commit 9a9de81e1c
11 changed files with 239 additions and 138 deletions

View file

@ -0,0 +1,75 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>CustomAttributesFrame</class>
<widget class="QFrame" name="CustomAttributesFrame">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>300</height>
</rect>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="1" column="1">
<widget class="QPushButton" name="button_Delete">
<property name="text">
<string>Delete</string>
</property>
</widget>
</item>
<item row="2" column="0" colspan="3">
<widget class="CustomAttributesTable" name="tableWidget"/>
</item>
<item row="1" column="0">
<widget class="QPushButton" name="button_Add">
<property name="text">
<string>Add</string>
</property>
</widget>
</item>
<item row="1" column="2">
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="0" column="0" colspan="3">
<widget class="QLabel" name="label">
<property name="text">
<string>Custom Attributes</string>
</property>
</widget>
</item>
<item row="3" column="0" colspan="3">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>CustomAttributesTable</class>
<extends>QTableWidget</extends>
<header>customattributestable.h</header>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>

View file

@ -2383,7 +2383,7 @@
</widget> </widget>
</item> </item>
<item> <item>
<widget class="CustomAttributesTable" name="mapCustomAttributesTable"> <widget class="CustomAttributesFrame" name="mapCustomAttributesFrame">
<property name="sizePolicy"> <property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Preferred"> <sizepolicy hsizetype="Expanding" vsizetype="Preferred">
<horstretch>0</horstretch> <horstretch>0</horstretch>
@ -3324,9 +3324,9 @@
<header>mapview.h</header> <header>mapview.h</header>
</customwidget> </customwidget>
<customwidget> <customwidget>
<class>CustomAttributesTable</class> <class>CustomAttributesFrame</class>
<extends>QFrame</extends> <extends>QFrame</extends>
<header>customattributestable.h</header> <header>customattributesframe.h</header>
<container>1</container> <container>1</container>
</customwidget> </customwidget>
</customwidgets> </customwidgets>

View file

@ -0,0 +1,32 @@
#ifndef CUSTOMATTRIBUTESFRAME_H
#define CUSTOMATTRIBUTESFRAME_H
/*
The frame containing the Custom Attributes table and its Add/Delete buttons.
Shared by the map's Header tab and Events.
*/
#include "customattributestable.h"
#include <QObject>
#include <QFrame>
namespace Ui {
class CustomAttributesFrame;
}
class CustomAttributesFrame : public QFrame
{
Q_OBJECT
public:
explicit CustomAttributesFrame(QWidget *parent = nullptr);
~CustomAttributesFrame() {};
CustomAttributesTable *table;
private:
Ui::CustomAttributesFrame *ui;
};
#endif // CUSTOMATTRIBUTESFRAME_H

View file

@ -1,22 +1,23 @@
#ifndef CUSTOMATTRIBUTESTABLE_H #ifndef CUSTOMATTRIBUTESTABLE_H
#define CUSTOMATTRIBUTESTABLE_H #define CUSTOMATTRIBUTESTABLE_H
#include "events.h"
#include <QObject> #include <QObject>
#include <QFrame> #include <QJsonValue>
#include <QTableWidget> #include <QTableWidget>
class CustomAttributesTable : public QFrame class CustomAttributesTable : public QTableWidget
{ {
Q_OBJECT Q_OBJECT
public: public:
explicit CustomAttributesTable(QWidget *parent = nullptr); explicit CustomAttributesTable(QWidget *parent = nullptr);
~CustomAttributesTable(); ~CustomAttributesTable() {};
QMap<QString, QJsonValue> getAttributes() const; QMap<QString, QJsonValue> getAttributes() const;
void setAttributes(const QMap<QString, QJsonValue> attributes); void setAttributes(const QMap<QString, QJsonValue> attributes);
void addNewAttribute(const QString &key, QJsonValue value, bool setAsDefault); void addNewAttribute(const QString &key, QJsonValue value, bool setAsDefault);
bool deleteSelectedAttributes();
QSet<QString> keys() const; QSet<QString> keys() const;
QSet<QString> defaultKeys() const; QSet<QString> defaultKeys() const;
@ -29,9 +30,10 @@ signals:
void defaultSet(QString key, QJsonValue value); void defaultSet(QString key, QJsonValue value);
void defaultRemoved(QString key); void defaultRemoved(QString key);
private: protected:
QTableWidget *table; void resizeEvent(QResizeEvent *event);
private:
QSet<QString> m_keys; // All keys currently in the table QSet<QString> m_keys; // All keys currently in the table
QSet<QString> m_defaultKeys; // All keys that are in this table by default (whether or not they're present) QSet<QString> m_defaultKeys; // All keys that are in this table by default (whether or not they're present)
QSet<QString> m_restrictedKeys; // All keys not allowed in the table QSet<QString> m_restrictedKeys; // All keys not allowed in the table
@ -39,7 +41,6 @@ private:
QPair<QString, QJsonValue> getAttribute(int row) const; QPair<QString, QJsonValue> getAttribute(int row) const;
int addAttribute(const QString &key, QJsonValue value); int addAttribute(const QString &key, QJsonValue value);
void removeAttribute(const QString &key); void removeAttribute(const QString &key);
bool deleteSelectedAttributes();
void setDefaultAttribute(const QString &key, QJsonValue value); void setDefaultAttribute(const QString &key, QJsonValue value);
void unsetDefaultAttribute(const QString &key); void unsetDefaultAttribute(const QString &key);
void resizeVertically(); void resizeVertically();

View file

@ -50,7 +50,7 @@ public:
QFrame *frame_contents; QFrame *frame_contents;
QVBoxLayout *layout_contents; QVBoxLayout *layout_contents;
CustomAttributesTable *custom_attributes; CustomAttributesFrame *custom_attributes;
protected: protected:
bool populated = false; bool populated = false;

View file

@ -44,6 +44,7 @@ SOURCES += src/core/block.cpp \
src/scriptapi/scripting.cpp \ src/scriptapi/scripting.cpp \
src/ui/aboutporymap.cpp \ src/ui/aboutporymap.cpp \
src/ui/customattributesdialog.cpp \ src/ui/customattributesdialog.cpp \
src/ui/customattributestable.cpp \
src/ui/customscriptseditor.cpp \ src/ui/customscriptseditor.cpp \
src/ui/customscriptslistitem.cpp \ src/ui/customscriptslistitem.cpp \
src/ui/draggablepixmapitem.cpp \ src/ui/draggablepixmapitem.cpp \
@ -57,7 +58,7 @@ SOURCES += src/core/block.cpp \
src/ui/regionmaplayoutpixmapitem.cpp \ src/ui/regionmaplayoutpixmapitem.cpp \
src/ui/regionmapentriespixmapitem.cpp \ src/ui/regionmapentriespixmapitem.cpp \
src/ui/cursortilerect.cpp \ src/ui/cursortilerect.cpp \
src/ui/customattributestable.cpp \ src/ui/customattributesframe.cpp \
src/ui/eventframes.cpp \ src/ui/eventframes.cpp \
src/ui/filterchildrenproxymodel.cpp \ src/ui/filterchildrenproxymodel.cpp \
src/ui/graphicsview.cpp \ src/ui/graphicsview.cpp \
@ -136,6 +137,7 @@ HEADERS += include/core/block.h \
include/lib/orderedjson.h \ include/lib/orderedjson.h \
include/ui/aboutporymap.h \ include/ui/aboutporymap.h \
include/ui/customattributesdialog.h \ include/ui/customattributesdialog.h \
include/ui/customattributestable.h \
include/ui/customscriptseditor.h \ include/ui/customscriptseditor.h \
include/ui/customscriptslistitem.h \ include/ui/customscriptslistitem.h \
include/ui/draggablepixmapitem.h \ include/ui/draggablepixmapitem.h \
@ -148,7 +150,7 @@ HEADERS += include/core/block.h \
include/ui/regionmaplayoutpixmapitem.h \ include/ui/regionmaplayoutpixmapitem.h \
include/ui/regionmapentriespixmapitem.h \ include/ui/regionmapentriespixmapitem.h \
include/ui/cursortilerect.h \ include/ui/cursortilerect.h \
include/ui/customattributestable.h \ include/ui/customattributesframe.h \
include/ui/eventframes.h \ include/ui/eventframes.h \
include/ui/filterchildrenproxymodel.h \ include/ui/filterchildrenproxymodel.h \
include/ui/graphicsview.h \ include/ui/graphicsview.h \
@ -201,6 +203,7 @@ HEADERS += include/core/block.h \
include/ui/uintspinbox.h include/ui/uintspinbox.h
FORMS += forms/mainwindow.ui \ FORMS += forms/mainwindow.ui \
forms/customattributesframe.ui \
forms/prefabcreationdialog.ui \ forms/prefabcreationdialog.ui \
forms/prefabframe.ui \ forms/prefabframe.ui \
forms/tileseteditor.ui \ forms/tileseteditor.ui \

View file

@ -11,7 +11,7 @@
#include "editcommands.h" #include "editcommands.h"
#include "config.h" #include "config.h"
#include "scripting.h" #include "scripting.h"
#include "customattributestable.h" #include "customattributesframe.h"
#include <QCheckBox> #include <QCheckBox>
#include <QPainter> #include <QPainter>
#include <QMouseEvent> #include <QMouseEvent>
@ -1953,7 +1953,7 @@ void Editor::toggleBorderVisibility(bool visible, bool enableScriptCallback)
void Editor::updateCustomMapHeaderValues() void Editor::updateCustomMapHeaderValues()
{ {
map->customHeaders = ui->mapCustomAttributesTable->getAttributes(); map->customHeaders = ui->mapCustomAttributesFrame->table->getAttributes();
emit editedMapData(); emit editedMapData();
} }

View file

@ -8,7 +8,7 @@
#include "eventframes.h" #include "eventframes.h"
#include "bordermetatilespixmapitem.h" #include "bordermetatilespixmapitem.h"
#include "currentselectedmetatilespixmapitem.h" #include "currentselectedmetatilespixmapitem.h"
#include "customattributestable.h" #include "customattributesframe.h"
#include "scripting.h" #include "scripting.h"
#include "adjustingstackedwidget.h" #include "adjustingstackedwidget.h"
#include "draggablepixmapitem.h" #include "draggablepixmapitem.h"
@ -303,22 +303,22 @@ void MainWindow::initEditor() {
}); });
// Connect the Custom Attributes table on the Header tab // Connect the Custom Attributes table on the Header tab
connect(ui->mapCustomAttributesTable, &CustomAttributesTable::edited, [this]() { connect(ui->mapCustomAttributesFrame->table, &CustomAttributesTable::edited, [this]() {
this->markMapEdited(); this->markMapEdited();
this->editor->updateCustomMapHeaderValues(); this->editor->updateCustomMapHeaderValues();
}); });
connect(ui->mapCustomAttributesTable, &CustomAttributesTable::defaultSet, [](QString key, QJsonValue value) { connect(ui->mapCustomAttributesFrame->table, &CustomAttributesTable::defaultSet, [](QString key, QJsonValue value) {
projectConfig.insertDefaultMapCustomAttribute(key, value); projectConfig.insertDefaultMapCustomAttribute(key, value);
}); });
connect(ui->mapCustomAttributesTable, &CustomAttributesTable::defaultRemoved, [](QString key) { connect(ui->mapCustomAttributesFrame->table, &CustomAttributesTable::defaultRemoved, [](QString key) {
projectConfig.removeDefaultMapCustomAttribute(key); projectConfig.removeDefaultMapCustomAttribute(key);
}); });
} }
void MainWindow::resetMapCustomAttributesTable() { void MainWindow::resetMapCustomAttributesTable() {
QStringList keys = projectConfig.getDefaultMapCustomAttributes().keys(); QStringList keys = projectConfig.getDefaultMapCustomAttributes().keys();
ui->mapCustomAttributesTable->setDefaultKeys(QSet<QString>(keys.begin(), keys.end())); ui->mapCustomAttributesFrame->table->setDefaultKeys(QSet<QString>(keys.begin(), keys.end()));
ui->mapCustomAttributesTable->setRestrictedKeys(Project::getTopLevelMapFields()); ui->mapCustomAttributesFrame->table->setRestrictedKeys(Project::getTopLevelMapFields());
} }
void MainWindow::initMiscHeapObjects() { void MainWindow::initMiscHeapObjects() {
@ -867,7 +867,7 @@ void MainWindow::displayMapProperties() {
ui->checkBox_AllowEscaping->setChecked(map->allowEscaping); ui->checkBox_AllowEscaping->setChecked(map->allowEscaping);
ui->spinBox_FloorNumber->setValue(map->floorNumber); ui->spinBox_FloorNumber->setValue(map->floorNumber);
ui->mapCustomAttributesTable->setAttributes(map->customHeaders); ui->mapCustomAttributesFrame->table->setAttributes(map->customHeaders);
} }
void MainWindow::on_comboBox_Song_currentTextChanged(const QString &song) void MainWindow::on_comboBox_Song_currentTextChanged(const QString &song)

View file

@ -0,0 +1,26 @@
#include "customattributesframe.h"
#include "ui_customattributesframe.h"
#include "customattributesdialog.h"
#include <QHBoxLayout>
#include <QPushButton>
#include <QLabel>
CustomAttributesFrame::CustomAttributesFrame(QWidget *parent) :
QFrame(parent),
ui(new Ui::CustomAttributesFrame)
{
ui->setupUi(this);
this->table = ui->tableWidget;
// Connect the "Add" button
connect(ui->button_Add, &QPushButton::clicked, [this]() {
CustomAttributesDialog dialog(this->table);
dialog.exec();
});
// Connect the "Delete" button
connect(ui->button_Delete, &QPushButton::clicked, [this]() {
this->table->deleteSelectedAttributes();
});
}

View file

@ -1,11 +1,7 @@
#include "customattributestable.h" #include "customattributestable.h"
#include "customattributesdialog.h" #include "customattributesdialog.h"
#include "parseutil.h" #include "parseutil.h"
#include <QHBoxLayout>
#include <QHeaderView> #include <QHeaderView>
#include <QPushButton>
#include <QTableWidget>
#include <QLabel>
#include <QScrollBar> #include <QScrollBar>
#include <QSpinBox> #include <QSpinBox>
@ -16,74 +12,37 @@ enum Column {
}; };
CustomAttributesTable::CustomAttributesTable(QWidget *parent) : CustomAttributesTable::CustomAttributesTable(QWidget *parent) :
QFrame(parent) QTableWidget(parent)
{ {
this->setAttribute(Qt::WA_DeleteOnClose); this->setColumnCount(Column::Count);
this->setHorizontalScrollMode(QAbstractItemView::ScrollPerPixel);
this->setHorizontalHeaderLabels(QStringList({"Key", "Value"}));
this->horizontalHeader()->setStretchLastSection(true);
this->horizontalHeader()->setSectionResizeMode(QHeaderView::Interactive);
//this->horizontalHeader()->setMaximumSectionSize(this->horizontalHeader()->length()); // TODO
this->horizontalHeader()->setVisible(false);
this->verticalHeader()->setVisible(false);
QVBoxLayout *layout = new QVBoxLayout(this); connect(this, &QTableWidget::cellChanged, this, &CustomAttributesTable::edited);
QLabel *label = new QLabel("Custom Attributes");
layout->addWidget(label);
QFrame *buttonsFrame = new QFrame(this);
buttonsFrame->setLayout(new QHBoxLayout());
QPushButton *addButton = new QPushButton(this);
QPushButton *deleteButton = new QPushButton(this);
addButton->setText("Add");
deleteButton->setText("Delete");
buttonsFrame->layout()->addWidget(addButton);
buttonsFrame->layout()->addWidget(deleteButton);
buttonsFrame->layout()->addItem(new QSpacerItem(1, 1, QSizePolicy::Expanding, QSizePolicy::Fixed));
buttonsFrame->layout()->setContentsMargins(0, 0, 0, 0);
layout->addWidget(buttonsFrame);
this->table = new QTableWidget(this);
this->table->setColumnCount(Column::Count);
this->table->setHorizontalScrollMode(QAbstractItemView::ScrollPerPixel);
this->table->setHorizontalHeaderLabels(QStringList({"Key", "Value"}));
this->table->horizontalHeader()->setStretchLastSection(true);
this->table->horizontalHeader()->setSectionResizeMode(QHeaderView::Interactive);
//this->table->horizontalHeader()->setMaximumSectionSize(this->table->horizontalHeader()->length()); // TODO
this->table->horizontalHeader()->setVisible(false);
this->table->verticalHeader()->setVisible(false);
layout->addWidget(this->table);
layout->addStretch(1);
// Connect the "Add" button
connect(addButton, &QPushButton::clicked, [this]() {
CustomAttributesDialog dialog(this);
if (dialog.exec() == QDialog::Accepted) {
emit this->edited();
}
});
// Connect the "Delete" button
connect(deleteButton, &QPushButton::clicked, [this]() {
if (this->deleteSelectedAttributes()) {
emit this->edited();
}
});
connect(this->table, &QTableWidget::cellChanged, [this]() {
emit this->edited();
});
// Key cells are uneditable, but users should be allowed to select one and press delete to remove the row. // Key cells are uneditable, but users should be allowed to select one and press delete to remove the row.
// Adding the "Selectable" flag to the Key cell changes its appearance to match the Value cell, which // Adding the "Selectable" flag to the Key cell changes its appearance to match the Value cell, which
// makes it confusing that you can't edit the Key cell. To keep the uneditable appearance and allow // makes it confusing that you can't edit the Key cell. To keep the uneditable appearance and allow
// deleting rows by selecting Key cells, we select the full row when a Key cell is selected. // deleting rows by selecting Key cells, we select the full row when a Key cell is selected.
connect(this->table, &QTableWidget::cellClicked, [this](int row, int column) { connect(this, &QTableWidget::cellClicked, [this](int row, int column) {
if (column == Column::Key) { if (column == Column::Key) {
this->table->selectRow(row); this->selectRow(row);
} }
}); });
// Double clicking the Key cell will bring up the dialog window to edit all the attribute's properties // Double clicking the Key cell will bring up the dialog window to edit all the attribute's properties
connect(this->table, &QTableWidget::cellDoubleClicked, [this](int row, int column) { connect(this, &QTableWidget::cellDoubleClicked, [this](int row, int column) {
if (column == Column::Key) { if (column == Column::Key) {
// Get cell data // Get cell data
auto keyValuePair = this->getAttribute(row); auto keyValuePair = this->getAttribute(row);
auto key = keyValuePair.first; auto key = keyValuePair.first;
// TODO: This dialog is confusing if the name is changed
// Create dialog // Create dialog
CustomAttributesDialog dialog(this); CustomAttributesDialog dialog(this);
dialog.setInput(key, keyValuePair.second, this->m_defaultKeys.contains(key)); dialog.setInput(key, keyValuePair.second, this->m_defaultKeys.contains(key));
@ -94,32 +53,9 @@ CustomAttributesTable::CustomAttributesTable(QWidget *parent) :
}); });
} }
CustomAttributesTable::~CustomAttributesTable()
{
}
void CustomAttributesTable::resizeVertically() {
int height = 0;
for (int i = 0; i < this->table->rowCount(); i++) {
height += this->table->rowHeight(i);
}
// Header disappears if there are no entries
if (this->table->rowCount() == 0) {
this->table->horizontalHeader()->setVisible(false);
} else {
this->table->horizontalHeader()->setVisible(true);
height += this->table->horizontalHeader()->height() + 2;
}
this->table->setMinimumHeight(height);
this->table->setMaximumHeight(height);
this->updateGeometry();
}
QMap<QString, QJsonValue> CustomAttributesTable::getAttributes() const { QMap<QString, QJsonValue> CustomAttributesTable::getAttributes() const {
QMap<QString, QJsonValue> fields; QMap<QString, QJsonValue> fields;
for (int row = 0; row < this->table->rowCount(); row++) { for (int row = 0; row < this->rowCount(); row++) {
auto keyValuePair = this->getAttribute(row); auto keyValuePair = this->getAttribute(row);
if (!keyValuePair.first.isEmpty()) if (!keyValuePair.first.isEmpty())
fields[keyValuePair.first] = keyValuePair.second; fields[keyValuePair.first] = keyValuePair.second;
@ -128,7 +64,7 @@ QMap<QString, QJsonValue> CustomAttributesTable::getAttributes() const {
} }
QPair<QString, QJsonValue> CustomAttributesTable::getAttribute(int row) const { QPair<QString, QJsonValue> CustomAttributesTable::getAttribute(int row) const {
auto keyItem = this->table->item(row, Column::Key); auto keyItem = this->item(row, Column::Key);
if (!keyItem) if (!keyItem)
return QPair<QString, QJsonValue>(); return QPair<QString, QJsonValue>();
@ -137,22 +73,22 @@ QPair<QString, QJsonValue> CustomAttributesTable::getAttribute(int row) const {
QJsonValue value; QJsonValue value;
if (type == QJsonValue::String) { if (type == QJsonValue::String) {
value = QJsonValue(this->table->item(row, Column::Value)->text()); value = QJsonValue(this->item(row, Column::Value)->text());
} else if (type == QJsonValue::Double) { } else if (type == QJsonValue::Double) {
auto spinBox = static_cast<QSpinBox*>(this->table->cellWidget(row, Column::Value)); auto spinBox = static_cast<QSpinBox*>(this->cellWidget(row, Column::Value));
value = QJsonValue(spinBox->value()); value = QJsonValue(spinBox->value());
} else if (type == QJsonValue::Bool) { } else if (type == QJsonValue::Bool) {
value = QJsonValue(this->table->item(row, Column::Value)->checkState() == Qt::Checked); value = QJsonValue(this->item(row, Column::Value)->checkState() == Qt::Checked);
} else { } else {
// All other types will just be preserved // All other types will just be preserved
value = this->table->item(row, Column::Value)->data(Qt::UserRole).toJsonValue(); value = this->item(row, Column::Value)->data(Qt::UserRole).toJsonValue();
} }
return QPair<QString, QJsonValue>(keyItem->text(), value); return QPair<QString, QJsonValue>(keyItem->text(), value);
} }
int CustomAttributesTable::addAttribute(const QString &key, QJsonValue value) { int CustomAttributesTable::addAttribute(const QString &key, QJsonValue value) {
const QSignalBlocker blocker(this->table); const QSignalBlocker blocker(this);
// Certain key names cannot be used (if they would overwrite a field used outside this table) // Certain key names cannot be used (if they would overwrite a field used outside this table)
if (this->m_restrictedKeys.contains(key)) if (this->m_restrictedKeys.contains(key))
@ -163,8 +99,8 @@ int CustomAttributesTable::addAttribute(const QString &key, QJsonValue value) {
this->removeAttribute(key); this->removeAttribute(key);
// Add new row // Add new row
int rowIndex = this->table->rowCount(); int rowIndex = this->rowCount();
this->table->insertRow(rowIndex); this->insertRow(rowIndex);
QJsonValue::Type type = value.type(); QJsonValue::Type type = value.type();
@ -174,37 +110,37 @@ int CustomAttributesTable::addAttribute(const QString &key, QJsonValue value) {
keyItem->setData(Qt::UserRole, type); // Record the type for writing to the file keyItem->setData(Qt::UserRole, type); // Record the type for writing to the file
keyItem->setTextAlignment(Qt::AlignCenter); keyItem->setTextAlignment(Qt::AlignCenter);
keyItem->setToolTip(key); // Display name as tool tip in case it's too long to see in the cell keyItem->setToolTip(key); // Display name as tool tip in case it's too long to see in the cell
this->table->setItem(rowIndex, Column::Key, keyItem); this->setItem(rowIndex, Column::Key, keyItem);
// Add value to table // Add value to table
switch (type) { switch (type) {
case QJsonValue::String: { case QJsonValue::String: {
// Add a regular cell item for editing text // Add a regular cell item for editing text
this->table->setItem(rowIndex, Column::Value, new QTableWidgetItem(ParseUtil::jsonToQString(value))); this->setItem(rowIndex, Column::Value, new QTableWidgetItem(ParseUtil::jsonToQString(value)));
break; break;
} case QJsonValue::Double: { } case QJsonValue::Double: {
// Add a spin box for editing number values // Add a spin box for editing number values
auto spinBox = new QSpinBox(this->table); auto spinBox = new QSpinBox(this);
spinBox->setMinimum(INT_MIN); spinBox->setMinimum(INT_MIN);
spinBox->setMaximum(INT_MAX); spinBox->setMaximum(INT_MAX);
spinBox->setValue(ParseUtil::jsonToInt(value)); spinBox->setValue(ParseUtil::jsonToInt(value));
// This connection will be handled by QTableWidget::cellChanged for other cell types // This connection will be handled by QTableWidget::cellChanged for other cell types
connect(spinBox, QOverload<int>::of(&QSpinBox::valueChanged), [this]() { emit this->edited(); }); connect(spinBox, QOverload<int>::of(&QSpinBox::valueChanged), [this]() { emit this->edited(); });
this->table->setCellWidget(rowIndex, Column::Value, spinBox); this->setCellWidget(rowIndex, Column::Value, spinBox);
break; break;
} case QJsonValue::Bool: { } case QJsonValue::Bool: {
// Add a checkable cell item for editing bools // Add a checkable cell item for editing bools
auto valueItem = new QTableWidgetItem(""); auto valueItem = new QTableWidgetItem("");
valueItem->setCheckState(value.toBool() ? Qt::Checked : Qt::Unchecked); valueItem->setCheckState(value.toBool() ? Qt::Checked : Qt::Unchecked);
valueItem->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsSelectable); valueItem->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsSelectable);
this->table->setItem(rowIndex, Column::Value, valueItem); this->setItem(rowIndex, Column::Value, valueItem);
break; break;
} default: { } default: {
// Arrays, objects, or null/undefined values cannot be edited // Arrays, objects, or null/undefined values cannot be edited
auto valueItem = new QTableWidgetItem("This value cannot be edited from this table"); auto valueItem = new QTableWidgetItem("This value cannot be edited from this table");
valueItem->setFlags(Qt::NoItemFlags); valueItem->setFlags(Qt::NoItemFlags);
valueItem->setData(Qt::UserRole, value); // Preserve the value for writing to the file valueItem->setData(Qt::UserRole, value); // Preserve the value for writing to the file
this->table->setItem(rowIndex, Column::Value, valueItem); this->setItem(rowIndex, Column::Value, valueItem);
break; break;
}} }}
this->m_keys.insert(key); this->m_keys.insert(key);
@ -217,13 +153,15 @@ void CustomAttributesTable::addNewAttribute(const QString &key, QJsonValue value
int row = this->addAttribute(key, value); int row = this->addAttribute(key, value);
if (row < 0) return; if (row < 0) return;
if (setAsDefault) this->setDefaultAttribute(key, value); if (setAsDefault) this->setDefaultAttribute(key, value);
this->table->selectRow(row);
this->resizeVertically(); this->resizeVertically();
this->selectRow(row);
emit this->edited();
} }
// For programmatically populating the table // For programmatically populating the table
void CustomAttributesTable::setAttributes(const QMap<QString, QJsonValue> attributes) { void CustomAttributesTable::setAttributes(const QMap<QString, QJsonValue> attributes) {
this->table->setRowCount(0); // Clear old values this->m_keys.clear();
this->setRowCount(0); // Clear old values
for (auto it = attributes.cbegin(); it != attributes.cend(); it++) for (auto it = attributes.cbegin(); it != attributes.cend(); it++)
this->addAttribute(it.key(), it.value()); this->addAttribute(it.key(), it.value());
this->resizeVertically(); this->resizeVertically();
@ -240,23 +178,22 @@ void CustomAttributesTable::unsetDefaultAttribute(const QString &key) {
} }
void CustomAttributesTable::removeAttribute(const QString &key) { void CustomAttributesTable::removeAttribute(const QString &key) {
for (int row = 0; row < this->table->rowCount(); row++) { for (int row = 0; row < this->rowCount(); row++) {
auto keyItem = this->table->item(row, Column::Key); auto keyItem = this->item(row, Column::Key);
if (keyItem && keyItem->text() == key) { if (keyItem && keyItem->text() == key) {
this->m_keys.remove(key); this->m_keys.remove(key);
this->table->removeRow(row); this->removeRow(row);
break; break;
} }
} }
// No need to adjust size because this is (at the moment) only used for replacement
} }
bool CustomAttributesTable::deleteSelectedAttributes() { bool CustomAttributesTable::deleteSelectedAttributes() {
int rowCount = this->table->rowCount(); int rowCount = this->rowCount();
if (rowCount <= 0) if (rowCount <= 0)
return false; return false;
QModelIndexList indexList = this->table->selectionModel()->selectedIndexes(); QModelIndexList indexList = this->selectionModel()->selectedIndexes();
QList<QPersistentModelIndex> persistentIndexes; QList<QPersistentModelIndex> persistentIndexes;
for (QModelIndex index : indexList) { for (QModelIndex index : indexList) {
QPersistentModelIndex persistentIndex(index); QPersistentModelIndex persistentIndex(index);
@ -268,18 +205,45 @@ bool CustomAttributesTable::deleteSelectedAttributes() {
for (QPersistentModelIndex index : persistentIndexes) { for (QPersistentModelIndex index : persistentIndexes) {
auto row = index.row(); auto row = index.row();
auto item = this->table->item(row, Column::Key); auto item = this->item(row, Column::Key);
if (item) this->m_keys.remove(item->text()); if (item) this->m_keys.remove(item->text());
this->table->removeRow(row); this->removeRow(row);
}
if (this->table->rowCount() > 0) {
this->table->selectRow(0);
} }
this->resizeVertically(); this->resizeVertically();
if (this->rowCount() > 0) {
this->selectRow(0);
}
emit this->edited();
return true; return true;
} }
void CustomAttributesTable::resizeVertically() {
int height = 0;
if (this->rowCount() == 0) {
// Hide header when table is empty
this->horizontalHeader()->setVisible(false);
} else {
for (int i = 0; i < this->rowCount(); i++)
height += this->rowHeight(i);
// Account for header and horizontal scroll bar
this->horizontalHeader()->setVisible(true);
height += this->horizontalHeader()->height();
if (this->horizontalScrollBar()->isVisible())
height += this->horizontalScrollBar()->height();
height += 2; // Border
}
this->setMinimumHeight(height);
this->setMaximumHeight(height);
}
void CustomAttributesTable::resizeEvent(QResizeEvent *event) {
this->resizeVertically();
QAbstractItemView::resizeEvent(event);
}
QSet<QString> CustomAttributesTable::keys() const { QSet<QString> CustomAttributesTable::keys() const {
return this->m_keys; return this->m_keys;
} }

View file

@ -1,5 +1,5 @@
#include "eventframes.h" #include "eventframes.h"
#include "customattributestable.h" #include "customattributesframe.h"
#include "editcommands.h" #include "editcommands.h"
#include "draggablepixmapitem.h" #include "draggablepixmapitem.h"
@ -102,10 +102,10 @@ void EventFrame::setup() {
} }
void EventFrame::initCustomAttributesTable() { void EventFrame::initCustomAttributesTable() {
this->custom_attributes = new CustomAttributesTable(this); this->custom_attributes = new CustomAttributesFrame(this);
QStringList keys = projectConfig.getDefaultEventCustomAttributes(this->event->getEventType()).keys(); QStringList keys = projectConfig.getDefaultEventCustomAttributes(this->event->getEventType()).keys();
this->custom_attributes->setDefaultKeys(QSet<QString>(keys.begin(), keys.end())); this->custom_attributes->table->setDefaultKeys(QSet<QString>(keys.begin(), keys.end()));
this->custom_attributes->setRestrictedKeys(this->event->getExpectedFields()); this->custom_attributes->table->setRestrictedKeys(this->event->getExpectedFields());
this->layout_contents->addWidget(this->custom_attributes); this->layout_contents->addWidget(this->custom_attributes);
} }
@ -138,14 +138,14 @@ void EventFrame::connectSignals(MainWindow *) {
}); });
this->custom_attributes->disconnect(); this->custom_attributes->disconnect();
connect(this->custom_attributes, &CustomAttributesTable::edited, [this]() { connect(this->custom_attributes->table, &CustomAttributesTable::edited, [this]() {
this->event->setCustomAttributes(this->custom_attributes->getAttributes()); this->event->setCustomAttributes(this->custom_attributes->table->getAttributes());
this->event->modify(); this->event->modify();
}); });
connect(this->custom_attributes, &CustomAttributesTable::defaultSet, [this](QString key, QJsonValue value) { connect(this->custom_attributes->table, &CustomAttributesTable::defaultSet, [this](QString key, QJsonValue value) {
projectConfig.insertDefaultEventCustomAttribute(this->event->getEventType(), key, value); projectConfig.insertDefaultEventCustomAttribute(this->event->getEventType(), key, value);
}); });
connect(this->custom_attributes, &CustomAttributesTable::defaultRemoved, [this](QString key) { connect(this->custom_attributes->table, &CustomAttributesTable::defaultRemoved, [this](QString key) {
projectConfig.removeDefaultEventCustomAttribute(this->event->getEventType(), key); projectConfig.removeDefaultEventCustomAttribute(this->event->getEventType(), key);
}); });
} }
@ -159,7 +159,7 @@ void EventFrame::initialize() {
this->spinner_y->setValue(this->event->getY()); this->spinner_y->setValue(this->event->getY());
this->spinner_z->setValue(this->event->getZ()); this->spinner_z->setValue(this->event->getZ());
this->custom_attributes->setAttributes(this->event->getCustomAttributes()); this->custom_attributes->table->setAttributes(this->event->getCustomAttributes());
this->label_icon->setPixmap(this->event->getPixmap()); this->label_icon->setPixmap(this->event->getPixmap());
} }