Files
GenericQtClientWidgets/views/itemdetailmapper.cpp

201 lines
6.5 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) {
clearEditWidgets();
}
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();
addWidgetsWithMapping(0);
addWidgetsWithMapping(1);
addWidgetsWithMapping(2);
m_typeLabel = new QLabel(GET_HEADER_FOR_COLUMN(3));
m_typeBox = new QComboBox();
m_typeLabel->setBuddy(m_typeBox);
m_typeModel = new QStringListModel(TYPES, this);
m_typeBox->setModel(m_typeModel);
m_layout->addWidget(m_typeLabel, 3, 0);
m_layout->addWidget(m_typeBox, 3, 1);
m_mapper->addMapping(m_typeBox, 3, "currentText");
m_amountLabel = new QLabel("&Amount");
m_amountBox = new QSpinBox();
m_amountBox->setMaximum(1000);
m_amountLabel->setBuddy(m_amountBox);
m_layout->addWidget(m_amountLabel, 4, 0);
m_layout->addWidget(m_amountBox, 4, 1);
m_mapper->addMapping(m_amountBox, 4);
m_factorLabel = new QLabel("&Factor");
m_factorBox = new QDoubleSpinBox();
m_factorBox->setMaximum(1000);
m_factorLabel->setBuddy(m_factorBox);
m_layout->addWidget(m_factorLabel, 5, 0);
m_layout->addWidget(m_factorBox, 5, 1);
m_mapper->addMapping(m_factorBox, 5);
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::addWidgetsWithMapping(const int column) {
QPair<QWidget*, QWidget*> widgetPair0 = createWidgetPairForColumn(column);
QWidget* control = widgetPair0.second;
m_layout->addWidget(widgetPair0.first, column, 0);
m_layout->addWidget(control, column, 1);
m_mapper->addMapping(control, column);
editControls.append(control);
}
QPair<QWidget*, QWidget*> ItemDetailMapper::createWidgetPairForColumn(const int column) {
const UserRoles role = GET_ROLE_FOR_COLUMN(column);
QWidget* edit;
if (STRING_ROLES.contains(role)) {
edit = new QLineEdit();
} else {
qCritical()
<< QString("Only string roles are supported yet. But tried with role %1!!!").arg(role);
qDebug() << "Using line edit as well and pretend it's a string role...";
edit = new QLineEdit();
}
const QString string = QString("&%1").arg(GET_HEADER_FOR_COLUMN(column));
QLabel* label = new QLabel(string);
label->setBuddy(edit);
return QPair<QWidget*, QWidget*>(label, edit);
}
void ItemDetailMapper::clearEditWidgets() {
setEnabled(false);
clearLineEdit(0);
clearLineEdit(1);
clearLineEdit(2);
m_typeBox->setCurrentIndex(m_typeBox->count() - 1);
m_amountBox->clear();
m_factorBox->clear();
}
void ItemDetailMapper::clearLineEdit(const int column) {
QLineEdit* lineEdit = dynamic_cast<QLineEdit*>(editControls[column]);
if (lineEdit) {
lineEdit->clear();
}
}