Refreshing a Custom Model data (QList<UserDefinedClass>) and swapping the lists contained in a QMap
-
Hello everyone, what I'm trying to implement is the following QMainWindow made of the components:
-
left QListView do not exist for the moment and is simulated to simplify testing, so don't focus to much on it.
-
GroupEditor (righ Widget) uses a custom model (PathsInfoTableModel) that is set to the QTableView
2.1) This widget as a Custom Card ( visible under the QTableView on the image above) and is simply a QWidget with a
QDataWidgetMapper that is connected to the QTableView currentItem that is called MapperPathInfo.
The application's storage Structure:
// QMap< QString, QList<PathInfo> > "GroupName1" { [ Path_info_1, Path_info_2, ... , Path_info_12, ] }, "GroupName2" { [ Path_info_1, Path_info_2, ... , Path_info_7, ] }
Functionality Description:
In the main window constructor a customModel called PathsInfoTableModel( QList<PathInfo> data) is istanciated and then passed to the GroupEditor's constructor (right widget) for the QTableView and is forwarded to the Widget mapper MapperPathInfo that set also QDataWidgetMapper->setModel( m_model )
long story short, a customModel is istanciated in the main window and then shared to QTableView and a QDataWidgetMapper
When the user want to edit a group (that contains a QList of paths obj) he clicks the "Edit Group"
-> this will take the "GroupName" as a QString and use it as a key in the QMap to retrive the corresponding QList<PathInfo>
and set the model's internal data structure to that QListauto current_list = (*QMap)["GroupName2"]; //definition in the model: void setListData( QList<PathInfo>& new_paths_list ); customModel->setListData( current_list);
model definition:
class PathsInfoTableModel : public QAbstractTableModel { Q_OBJECT public: explicit PathsInfoTableModel( QList<PathInfo> group= QList<PathInfo>(), QObject *parent = nullptr ); // virtual override int rowCount( const QModelIndex &parent = QModelIndex() ) const override; int columnCount( const QModelIndex &parent = QModelIndex() ) const override; QVariant data( const QModelIndex &index, int role = Qt::DisplayRole ) const override; bool setData( const QModelIndex& index, const QVariant& value, int role ) override; QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override; Qt::ItemFlags flags(const QModelIndex &index) const override; QList<PathInfo>& getPathInfoList() { return m_model_data; } void setListData( QList<PathInfo>& new_paths_list ); private: QList<PathInfo> m_model_data; };
model implementation:
PathsInfoTableModel::PathsInfoTableModel(QList<PathInfo> group, QObject *parent) : QAbstractTableModel{parent}, m_model_data{ group } {} Qt::ItemFlags PathsInfoTableModel::flags( const QModelIndex &index ) const { if ( !index.isValid() ) return Qt::NoItemFlags; // sets path_col and IsOpenable_col editable if ( index.column() == 3 ) { return Qt::ItemIsEditable | Qt::ItemIsEnabled | Qt::ItemIsSelectable; } return Qt::ItemIsEnabled | Qt::ItemIsSelectable; } int PathsInfoTableModel::rowCount( const QModelIndex &parent ) const { Q_UNUSED(parent) return m_model_data.size(); } int PathsInfoTableModel::columnCount( const QModelIndex &parent ) const { Q_UNUSED(parent) return 4; } QVariant PathsInfoTableModel::data( const QModelIndex &index, int role ) const { auto col = index.column(); auto row = index.row(); PathInfo p = m_model_data.at(row); // add pixmap to first and third column if ( role == Qt::DecorationRole && (col == 0 || col == 2) ) { auto is_path_valid = p[2].toBool(); // select the right icon for // the first column if ( col == 0 ) { // path doesn't exist if ( !is_path_valid ) return p.NOT_A_FILE_PIX; // exists and is a file if ( p[0].toBool() ) return p.FILE_PIX; // is a folder return p.FOLDER_PIX; } return ( is_path_valid ) ? p.VALID_PIX : p.INVALID_PIX; } if ( role == Qt::DisplayRole && col == 1 ) { return p[col]; } /**************************************************************************** * change it with a custom QStyledItem * to draw the chips instead ****************************************************************************/ // add text Valid-Invalid if ( role == Qt::DisplayRole && col == 2 ) { return ( p[col].toBool() ) ? QVariant( QString("Valid") ) : QVariant( QString("Invalid") ); } return QVariant(); } bool PathsInfoTableModel::setData( const QModelIndex& index, const QVariant& value, int role ) { auto row = index.row(), col = index.column(); QModelIndex fileTypeIdx = createIndex(row, 0); QModelIndex validityIdx = createIndex(row, 2); if ( !index.isValid() || row >= m_model_data.size() ) return false; if ( role == Qt::DisplayRole || role == Qt::EditRole ) { // get PathInfo at row index.row() PathInfo& pathInfo = m_model_data[row]; if ( col == 1 ) // edit the path_column { // not a path, return if ( !value.canConvert<QString>() ) return false; QString oldPath = pathInfo.path(); pathInfo.changePath( value.toString() ); if ( oldPath != pathInfo.path() ) { emit dataChanged( index, index, { Qt::DisplayRole, Qt::EditRole } ); emit dataChanged( fileTypeIdx, fileTypeIdx, { Qt::DisplayRole } ); emit dataChanged( validityIdx, validityIdx, { Qt::DisplayRole } ); return true; } return true; } else if ( col == 2 ) // edit the isValid chip { // check if data is of type bool if ( !value.canConvert<bool>() ) return false; bool old_state = pathInfo.pathValidity(); // checks if path is valid pathInfo.checkPathValidity(); if ( old_state != pathInfo.pathValidity() ) { // update FileType and ValidityChip col emit dataChanged( fileTypeIdx, fileTypeIdx, { Qt::DisplayRole } ); emit dataChanged( validityIdx, validityIdx, { Qt::DisplayRole } ); return true; } return true; } else if ( col == 3 ) // edit the isOpenable_col { if ( !value.canConvert<bool>() ) return false; pathInfo.setOpenable( value.toBool() ); emit dataChanged( index, index, { Qt::DisplayRole, Qt::EditRole } ); return true; } return false; } return false; } QVariant PathsInfoTableModel::headerData( int section, Qt::Orientation orientation, int role ) const { if ( orientation != Qt::Horizontal || role != Qt::DisplayRole ) return QVariant(); switch ( section ) { case 0: return "Type"; case 1: return "Full Path"; case 2: return "Validity State"; case 3: return "Openable"; default: return QVariant(); } } void PathsInfoTableModel::setListData( QList<PathInfo>& new_paths_list ) { beginResetModel(); m_model_data = new_paths_list; endResetModel(); }
-
-
I have to make 2 different post because the first was getting to long.
the problems:
there is something in the model resetting when a change the old QList with the new QList retrived from the QMap that is causing segmentation fault. I Post the full code on gitHub (https://github.com/aVenturelli-qt/ArchWay-Project-Manager) because it will never fit to the forum.
How can I have a model pointing to QList stored in a QMap that can be directly modified by the model and when i'm done editing it and switch to a dfferent Qlist (also contained in the QMap but inside a different key) a can reset the Model with new Data ?
-
@Andrea_Venturelli said in Refreshing a Custom Model data (QList<UserDefinedClass>) and swapping the lists contained in a QMap:
beginResetModel();
m_model_data = new_paths_list;
endResetModel();I would have suggested exactly this now...
This doesn't work for you?!Reset the model when you switch to new list and assign the new one to update all views
-
commenting out the instanciation of the left widget will prevent the segmentation fault problem, so the problem mist be in some custom slot where i update the values after the “modelChanged()” signal.
it seems like the model exist for all the component that uses it but when accesing the have a reference to some non existing data and crush..
without a deep knowledge of QMap<> i think I’m missing some core concepts that is casuing the problem after the model resetted