#include "itemdetailmapper.h" #include #include #include #include #include #include #include #include #include #include #include "../widgethelper.h" ItemDetailMapper::ItemDetailMapper(QTableView* tableView, QWidget* parent) : QWidget{parent} { /// model mapping m_mapper = std::make_unique(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); 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); const int nRows = m_layout->rowCount(); m_layout->addWidget(m_previousButton, nRows, 0); m_layout->addWidget(m_nextButton, nRows, 1); } void ItemDetailMapper::setupWidgets() { m_layout = new QGridLayout(); for (int i = 0; i < USER_FACING_ROLES.size(); ++i) { setupWidgetPairForColumn(i); } setupNavigationButtons(); setLayout(m_layout); } void ItemDetailMapper::setupWidgetPairForColumn(const int column) { // REFACTOR consolidate ItemDetailMapper::setupWidgetPairForColumn(...) // with NewItemDialog::setupWidgetPairForColumn(...) const UserRoles role = GET_ROLE_FOR_COLUMN(column); QWidget* control = WidgetHelper::createControlWidget(role, this); 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); } } 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(m_controlWidgets[column]); if (lineEdit) { lineEdit->clear(); } } void ItemDetailMapper::clearComboBox(const int column) { QComboBox* comboBox = dynamic_cast(m_controlWidgets[column]); if (comboBox) { comboBox->setCurrentText(""); } } void ItemDetailMapper::clearSpinBox(const int column) { QAbstractSpinBox* spinBox = dynamic_cast(m_controlWidgets[column]); if (spinBox) { spinBox->clear(); } }