225 lines
7.0 KiB
C++
225 lines
7.0 KiB
C++
#include "itemdetailmapper.h"
|
|
|
|
#include <QAbstractItemModel>
|
|
#include <QDataWidgetMapper>
|
|
#include <QGridLayout>
|
|
#include <QJsonArray>
|
|
#include <QJsonObject>
|
|
#include <QLabel>
|
|
#include <QLineEdit>
|
|
#include <QPushButton>
|
|
#include <QSpinBox>
|
|
#include <QTableView>
|
|
#include "model/metadata.h"
|
|
|
|
ItemDetailMapper::ItemDetailMapper(QTableView* tableView, QWidget* parent)
|
|
: QWidget{parent} {
|
|
/// model mapping
|
|
m_mapper = std::make_unique<QDataWidgetMapper>(this);
|
|
/// BUG: If multiple columns are changed not all changes are applied.
|
|
/// Multiple changes are set individually by calling setData().
|
|
/// Probably due to a conflicting dataChanged signal for too many roles&columns the data of
|
|
/// the remaining columns is reset before setData is called.
|
|
/// And a manual submit would also create multiple undo steps anyway.
|
|
/// Workaround: ManualSubmit -> AutoSubmit
|
|
// m_mapper->setSubmitPolicy(QDataWidgetMapper::ManualSubmit);
|
|
m_mapper->setSubmitPolicy(QDataWidgetMapper::AutoSubmit);
|
|
|
|
qDebug() << "Setting model...";
|
|
m_tableView = tableView;
|
|
m_model = tableView->model();
|
|
m_selectionModel = tableView->selectionModel();
|
|
|
|
m_mapper->setModel(m_model);
|
|
|
|
setupNavigationButtons();
|
|
setupWidgets();
|
|
|
|
setupConnections();
|
|
}
|
|
|
|
bool ItemDetailMapper::submit() { return m_mapper->submit(); }
|
|
|
|
void ItemDetailMapper::revert() { m_mapper->revert(); }
|
|
|
|
void ItemDetailMapper::onCurrentIndexChanged(const QModelIndex& current,
|
|
const QModelIndex& /*previous*/) {
|
|
if (!isEnabled()) {
|
|
setEnabled(true);
|
|
}
|
|
m_mapper->setCurrentModelIndex(current);
|
|
updateButtons(current.row());
|
|
emitContentChanged(current);
|
|
}
|
|
|
|
void ItemDetailMapper::rowsInserted(const QModelIndex& parent, int start, int end) {
|
|
updateButtons(m_mapper->currentIndex());
|
|
}
|
|
|
|
void ItemDetailMapper::rowsRemoved(const QModelIndex& parent, int start, int end) {
|
|
if (m_model->rowCount() == 0) {
|
|
clearControlWidgets();
|
|
}
|
|
|
|
updateButtons(m_mapper->currentIndex());
|
|
}
|
|
|
|
void ItemDetailMapper::toPrevious() {
|
|
int currentRow = m_selectionModel->currentIndex().row();
|
|
QModelIndex previousIndex = m_selectionModel->currentIndex().siblingAtRow(currentRow - 1);
|
|
if (previousIndex.isValid()) {
|
|
m_selectionModel->setCurrentIndex(previousIndex, QItemSelectionModel::ClearAndSelect);
|
|
}
|
|
}
|
|
|
|
void ItemDetailMapper::toNext() {
|
|
int currentRow = m_selectionModel->currentIndex().row();
|
|
QModelIndex nextIndex = m_selectionModel->currentIndex().siblingAtRow(currentRow + 1);
|
|
if (nextIndex.isValid()) {
|
|
m_selectionModel->setCurrentIndex(nextIndex, QItemSelectionModel::ClearAndSelect);
|
|
}
|
|
}
|
|
|
|
void ItemDetailMapper::updateButtons(int row) {
|
|
m_previousButton->setEnabled(row > 0);
|
|
m_nextButton->setEnabled(row < m_model->rowCount() - 1);
|
|
}
|
|
|
|
void ItemDetailMapper::emitContentChanged(const QModelIndex& currentIndex) {
|
|
// BUG QR-Code isn't updated after changes through the ItemDetailMapper #18
|
|
QString toStringText = "";
|
|
if (currentIndex.isValid()) {
|
|
toStringText = currentIndex.data(ToStringRole).toString();
|
|
}
|
|
emit contentChanged(toStringText);
|
|
}
|
|
|
|
void ItemDetailMapper::setupConnections() {
|
|
m_mapper->setCurrentIndex(m_selectionModel->currentIndex().row());
|
|
|
|
connect(m_model, &QAbstractItemModel::rowsInserted, this, &ItemDetailMapper::rowsInserted);
|
|
connect(m_model, &QAbstractItemModel::rowsRemoved, this, &ItemDetailMapper::rowsRemoved);
|
|
connect(m_selectionModel, &QItemSelectionModel::currentChanged, this,
|
|
&ItemDetailMapper::onCurrentIndexChanged);
|
|
|
|
updateButtons(m_selectionModel->currentIndex().row());
|
|
}
|
|
|
|
void ItemDetailMapper::setupNavigationButtons() {
|
|
m_nextButton = new QPushButton(tr("Ne&xt"));
|
|
m_previousButton = new QPushButton(tr("&Previous"));
|
|
|
|
connect(m_previousButton, &QAbstractButton::clicked, this, &ItemDetailMapper::toPrevious);
|
|
connect(m_nextButton, &QAbstractButton::clicked, this, &ItemDetailMapper::toNext);
|
|
}
|
|
|
|
void ItemDetailMapper::setupWidgets() {
|
|
m_layout = new QGridLayout();
|
|
|
|
for (int i = 0; i < USER_FACING_ROLES.size(); ++i) {
|
|
setupWidgetPairForColumn(i);
|
|
}
|
|
|
|
const int nRows = m_layout->rowCount();
|
|
m_layout->addWidget(m_previousButton, nRows, 0);
|
|
m_layout->addWidget(m_nextButton, nRows, 1);
|
|
|
|
setLayout(m_layout);
|
|
}
|
|
|
|
void ItemDetailMapper::setupWidgetPairForColumn(const int column) {
|
|
const UserRoles role = GET_ROLE_FOR_COLUMN(column);
|
|
|
|
QWidget* control = createControlWidget(role);
|
|
|
|
const QString string = QString("&%1").arg(GET_HEADER_FOR_COLUMN(column));
|
|
QLabel* label = new QLabel(string);
|
|
label->setBuddy(control);
|
|
|
|
m_layout->addWidget(label, column, 0);
|
|
m_layout->addWidget(control, column, 1);
|
|
m_controlWidgets.append(control);
|
|
|
|
if (TYPE_ROLES.contains(role)) {
|
|
m_mapper->addMapping(control, column, "currentText");
|
|
} else {
|
|
m_mapper->addMapping(control, column);
|
|
}
|
|
}
|
|
|
|
QWidget* ItemDetailMapper::createControlWidget(const int role) {
|
|
QWidget* control;
|
|
if (STRING_ROLES.contains(role)) {
|
|
control = new QLineEdit();
|
|
} else if (TYPE_ROLES.contains(role)) {
|
|
control = createComboBox(role);
|
|
} else if (INT_ROLES.contains(role)) {
|
|
QSpinBox* spinBox = new QSpinBox();
|
|
spinBox->setMaximum(1000);
|
|
control = spinBox;
|
|
} else if (DOUBLE_ROLES.contains(role)) {
|
|
QDoubleSpinBox* spinBox = new QDoubleSpinBox();
|
|
spinBox->setMaximum(1000);
|
|
control = spinBox;
|
|
} else {
|
|
qCritical() << QString("Unsupported role %1!!!").arg(role);
|
|
qDebug() << "Using line edit as well and pretend it's a string role...";
|
|
control = new QLineEdit();
|
|
}
|
|
return control;
|
|
}
|
|
|
|
QWidget* ItemDetailMapper::createComboBox(const int role) {
|
|
QStringListModel* typeModel;
|
|
if (role == TypeRole) {
|
|
typeModel = new QStringListModel(TYPES, this);
|
|
} else {
|
|
qCritical() << "Unsupported type with role:" << role
|
|
<< "- Using string list model with only one empty string!";
|
|
typeModel = new QStringListModel({""}, this);
|
|
}
|
|
QComboBox* comboBox = new QComboBox();
|
|
comboBox->setModel(typeModel);
|
|
return comboBox;
|
|
}
|
|
|
|
void ItemDetailMapper::clearControlWidgets() {
|
|
setEnabled(false);
|
|
|
|
for (int i = 0; i < m_controlWidgets.size(); ++i) {
|
|
const UserRoles role = GET_ROLE_FOR_COLUMN(i);
|
|
if (STRING_ROLES.contains(role)) {
|
|
clearLineEdit(i);
|
|
} else if (TYPE_ROLES.contains(role)) {
|
|
clearComboBox(i);
|
|
} else if (INT_ROLES.contains(role)) {
|
|
clearSpinBox(i);
|
|
} else if (DOUBLE_ROLES.contains(role)) {
|
|
clearSpinBox(i);
|
|
} else {
|
|
qCritical() << "Could not reset content for control widget in column:" << i << "!";
|
|
}
|
|
}
|
|
}
|
|
|
|
void ItemDetailMapper::clearLineEdit(const int column) {
|
|
QLineEdit* lineEdit = dynamic_cast<QLineEdit*>(m_controlWidgets[column]);
|
|
if (lineEdit) {
|
|
lineEdit->clear();
|
|
}
|
|
}
|
|
|
|
void ItemDetailMapper::clearComboBox(const int column) {
|
|
QComboBox* comboBox = dynamic_cast<QComboBox*>(m_controlWidgets[column]);
|
|
if (comboBox) {
|
|
comboBox->setCurrentText("");
|
|
}
|
|
}
|
|
|
|
void ItemDetailMapper::clearSpinBox(const int column) {
|
|
QAbstractSpinBox* spinBox = dynamic_cast<QAbstractSpinBox*>(m_controlWidgets[column]);
|
|
if (spinBox) {
|
|
spinBox->clear();
|
|
}
|
|
}
|