Solved Best way to subclass setData() in subclass of QSqlTableModel
-
Hi, I'm still an amateur in Qt and C++. I was wondering the best way to reimplement setData() in my class Paper_Model which is derived from QSqlTableModel as shown?
#############
// class definition
#include <sqlsetup.h>
#ifndef SQL_SQLTABLEMODEL_H
#define SQL_SQLTABLEMODEL_Hclass Paper_Model: public QSqlTableModel {
Q_OBJECT
public:
explicit Paper_Model(QObject* parent=Q_NULLPTR,const QString tablename="");
QString getColumnName(int col);
QSqlError query(const QString filter=QString("1"));
QSqlRecord undo_redo(QString undoredo); //undo model edit
bool setData(const QModelIndex &index, const QVariant &value, int role=Qt::EditRole) override;
private:
QVector<QSqlRecord> recordundoredo; // vector which holds copies stack of record under edit};
#endif //SQL_SQLTABLEMODEL_H
##############################
// class
#include "sqlsetup.h"
#include "Paper_Model.h"
//#include "sqlForeignKeyDelegate.h"
using namespace std;
Paper_Model::Paper_Model(QObject *parent,QString tablename):QSqlTableModel(parent)
{
this->setTable(tablename);
this->setEditStrategy(QSqlTableModel::OnManualSubmit);
}QString Paper_Model::getColumnName(int col) // find column name from column number
{
return this->record().fieldName(col);
}// query database model
QSqlError Paper_Model::query(const QString filter)
{
this->setFilter(filter);
this->select();
auto sqlerror=this->lastError();
if(sqlerror.type() == QSqlError::ConnectionError){ cout<<"database connection ERROR on Paper Model table name " << this->tableName().toStdString()<<endl; } else if (sqlerror.type() == QSqlError::StatementError) { cout<<"sql statement ERROR on Paper Model table name " << this->tableName().toStdString()<<endl; } else if (sqlerror.type() == QSqlError::TransactionError) { cout<<"sql transaction ERROR on Paper Model table name " << this->tableName().toStdString()<<endl; } else if (sqlerror.type() == QSqlError::UnknownError) { cout<<"sql transaction ERROR on Paper Model table name " << this->tableName().toStdString()<<endl; } return sqlerror ; // get errors if there are errors in the query
}
bool Paper_Model::setData(const QModelIndex &index, const QVariant &value, int role)
{
if(index.isValid() && (role==Qt::EditRole || role==Qt::DisplayRole))
{
// redo or undo update here} return QSqlTableModel::setData(index, value,role);
}
###############################I would like to capture the data every time the user edits the query results as shown by the table which has model: Paper_Model
This captured data would be used later to allow the user to undo or redo edits (code not written for this yet but would go in the //redo or update here
line in the code above.My central question is this:
For the most part, I want the Paper_Model::setData() to act like it would if not reimplemented with the exception of changing the redo/undo stack storage when the user edits the query results in the table. After capturing the user's edits, I would like to just send the data to the model as for the default setData behavior.
Is it correct to include the line:
return QSqlTableModel::setData(index, value,role);
in method Paper_Model::setData
to get the default behavior after doing the extra work?In general, when one wants default behavior in a subclassed method (call it Method()), is the following general code correct?
SubClass::Method()
{
// do somethingreturn BaseClass::Method();
}########### OR to get default behavior if condition not met
SubClass::Method()
{
if(condition)
{
// do something
return ....
}
else
{
return BaseClass::Method();
}where BaseClass is the base class of the class SubClass?
Thanks so much,
Phil -
Hi,
Shouldn't you implement the undo stack at the editor level rather than in such a backend class ?
-
Thanks for your reply SGaist, I'll look into this. I believe you're talking about using a delegate to implement the undo stack?
Even so, I'm still curious about the general question of getting default behavior (i.e. bypass case) for reimplemented methods?
Thanks,
Phil -
I was rather thinking about a dedicated editor.
To get the default behaviour call the base class method.
-
Hi SGaist,
I suspected this was the case, i.e. to call the base class to get default behavior, but wanted to check with you experts.
I think I wanted to send the entire record (table row) to the undo/redo stack every time the user edits a cell in that row. I would likely change the row's background color (via reimplementing the data() method with row) to indicate it's been altered and allow the user to undo or redo their changes to that row. The shown table rows would be those from the last query results and the user would be allowed to alter any of the rows and independently undo or redo each row's alterations. After the user is satisfied with his/her changes, they could send them to the underlying database.
If the undo/redo were applied only to a single cell at a time, I would definitely use a delegate. However, I was thinking that since the entire row would be subject to undo/redo, it would be better to just modify the undo/redo stack on each user edit which would be caught by the reimplemented setData() method. I would then call the base class:setData() to go ahead with default behavior after capturing the user's edits onto the redo/undo stack.
Does this make any sense?
Thanks!
Phil -
OK, I re-read your answer. You didn't propose an editor within a delegate but rather a standalone dedicated editor. I'm not sure how this would work and I'm thinking that I would then have to generate a whole table/widget entry mechanism just for this editor? I might be missing something obvious here?
Thanks again,
Phil -
I was thinking about the books example but you should take a look at the cached table example.