PDA

View Full Version : QStandardItemModel insertRow crashing



munna
27th June 2008, 06:02
Hi,

I have a treeview for which I am creating the model (QStandardItemModel) after reading values from a DB. The treeview is inside a tab and everytime a user moves to another tab and comes back I have to query the DB again and rebuild the model.

Now, the problem is that when a node a tree is opened something like below

|__+Node1
|__Node2
| |__Leaf1
| |__Leaf2
|__+Node3

and we navigate to some other tab and come back to this one, my application crashes when insertRow is called. But when the tree is like the following

|__+Node1
|__+Node2
|__+Node3

Everything works fine.


#include <FooTab.h>
#include <DeleteDBValueOp.h>
#include <NewAccountOp.h>
#include <SessionSingleton.h>
#include <UpdateDBValuesOp.h>
#include <MainWindow.h>

#define DEFAULT_NUMBER_VALUE 1
#define DEFAULT_DATETIME_VALUE "'2000-01-01 00:00:00'"

FooTab::FooTab( QWidget* )
{
qDebug() << "Inside Constructor";
ui = MainWindow::instance()->UI();
connect( ui.FooRefreshBtn, SIGNAL( clicked() ), this, SLOT( doRefreshFooTree() ) );
connect( ui.FooDeleteBtn, SIGNAL( clicked() ), this, SLOT( doFooDeleteBtnClicked() ) );
connect( ui.FooNewAccountBtn, SIGNAL( clicked() ), this, SLOT( FooNewAccountBtnClicked() ) );
connect( ui.FooUnlockBtn, SIGNAL( clicked() ), this, SLOT( FooUnlockBtnClicked() ) );
connect( ui.FooUpdateBtn, SIGNAL( clicked() ), this, SLOT( FooUpdateBtnClicked() ) );
connect( ui.FooDescriptionLE, SIGNAL( textEdited( const QString & ) ), this, SLOT( FooInfoEdited( const QString & ) ) );
connect( ui.FooNumberLE, SIGNAL( textEdited( const QString & ) ), this, SLOT( FooInfoEdited( const QString & ) ) );
connect( ui.FooInactivateBtn, SIGNAL( clicked() ), this, SLOT( FooInactivateBtnClicked() ) );

ui.FooNumberLE->setReadOnly( true );
ui.FooNewAccountBtn->setEnabled( false );
}

FooTab::~FooTab ()
{

}

/*!
* The function is called when user changed tab or
* another case, when we need to put tab in initial state for
* user to start manipulationd with accounts.
*/

void FooTab::updateClientFooTab()
{
qDebug() << "\nupdating Foo tab";

ui.FooNumberLE->setVisible( true );
ui.FooNumberL->setVisible( true );

QAbstractItemModel* model = ui.FooTree->model();

// create model if it not exists
if( model == NULL )
{
model = new QStandardItemModel;
ui.FooTree->setModel( model );

model->insertColumn( 0 );

// set names to horizontal labels
model->setHeaderData(0, Qt::Horizontal, tr("Some Header"));
}
qDebug() << model->rowCount();
if ( model->rowCount() > 0 )//When the tree is built for the first time this condition will be false.
{
model->removeRows( 0, model->rowCount());
}

// Create first level of nodes, if empty
if ( model->rowCount() == 0 )
{
qDebug() << "Empty tab. Updating...";
QSqlQuery query( ... );
QString account_names_query = QString( "SOME QUERY");

qDebug() << account_names_query;
query.exec( account_names_query );

// insert root element
model->insertRow( 0 ); //CRASHES HERE. BOOM!!!
QModelIndex root = model->index( 0, 0 );

model->insertColumn( 0, root );

Q_ASSERT( root.isValid() );
model->setData( root, "Root" );
FooTreeNodeData node_data;
node_data.was_expanded = true;
node_data.id = -1;
node_data.is_type = true;
QVariant v;
v.setValue( node_data );
model->setData( root, v, Qt::UserRole );

ui.FooTree->setRootIndex( root );
// set root as current element
ui.FooTree->setCurrentIndex( root );

// Insert zero level at TreeView, as expandable nodes
doAddNewSubnodes( root, query, model );
}

qDebug() << "Foo Tab updated";
ui.FooTree->setCurrentIndex( model->index( 0, 0 ) );

connect( ui.FooTree, SIGNAL( expanded( const QModelIndex &) ), this, SLOT( doExpandFooTreeNode( const QModelIndex &) ) );

QItemSelectionModel* selectionModel = ui.FooTree->selectionModel();
connect( selectionModel,
SIGNAL( currentChanged( const QModelIndex&, const QModelIndex& ) ),
this,
SLOT( FooTreeCurrentChanged( const QModelIndex& , const QModelIndex& ))) ;
}

/*!
* The slot is run, when user expands Tree node.
* If node is expanded first time, then it selects from DB subnodes.
* else just expands.
* \param index clicked node
*/
void FooTab::doExpandFooTreeNode( const QModelIndex &index)
{
qDebug() << "expanded Foo node";
QSqlQuery query( SessionSingleton::instance()->database() );

QAbstractItemModel *model = ui.FooTree->model();
// If wasn't expanded yet
FooTreeNodeData node_data = model->data( index, Qt::UserRole ).value<FooTreeNodeData>();
if ( !node_data.was_expanded )
{
qDebug() << "Wasn't expanded yet. Read data from DB";
// Now expanded
QVariant v;
node_data.was_expanded = true;
v.setValue( node_data );
model->setData( index, v, Qt::UserRole );

// Delete fictiuous subnode
model->removeRow( 0, index );

QString accounts_query_string = QString( "SOME OTHER QUERY");

qDebug() << accounts_query_string;
query.exec( accounts_query_string );

while( query.next() )
{
int id = query.value( 0 ).toInt();
QString description = query.value( 1 ).toString();
int number = query.value( 2 ).toInt();

qDebug() << id << description << number;

if( description.isEmpty() )
{
description = QString( "%1" ).arg( number );
}

FooTreeNodeData node_data;
node_data.is_type = false;
node_data.was_expanded = true;
node_data.id = id;

model->insertRow( model->rowCount( index ), index );
QModelIndex subindex = model->index( model->rowCount( index ) - 1, 0, index );

model->setData( subindex, description );
QVariant v;
v.setValue( node_data );
model->setData( subindex, v, Qt::UserRole );

model->insertColumn( 0, subindex );

// adding sub node
QSqlQuery query_subnode( DATABASECONNECTION );
QString qry_accounts_subtypes = QString( "THE THIRD QUERY");
qDebug() << qry_accounts_subtypes;
query_subnode.exec( qry_accounts_subtypes );
if (query_subnode.size() > 0)
{
while ( query_subnode.next() )
{
QString name = query_subnode.value( 0 ).toString();
int id = query_subnode.value( 1 ).toInt();

//Q_ASSERT( !name.isEmpty() );
if ( name.isEmpty() )
{
name = "<EMPTY>";
}

qDebug() << "Insert node: " << name;
// Insert node
int model_row_count = model->rowCount( subindex );
model->insertRow( model_row_count, subindex );
QModelIndex sub_subindex = model->index( model->rowCount( subindex ) - 1, 0, subindex );
model->setData( sub_subindex, name );

FooTreeNodeData node_data;
node_data.id = id;
node_data.was_expanded = true;
node_data.is_type = false;
QVariant v;
v.setValue( node_data );

model->setData( sub_subindex, v, Qt::UserRole );
node_data = model->data( sub_subindex, Qt::UserRole ).value<FooTreeNodeData>();
qDebug() << "Node type ID: " << node_data.id;

// Insert subnode
model->insertColumn( 0, sub_subindex );
}
}
}
}
}


/*!
* \brief Add new subnodes to \c index from \c query
*
* \note Also, added fictuous subnode to subnodes be expandable
* \param index node where insert subnodes
* \param query from get subnode names
* \param model model to add subnodes to
*/
void FooTab::doAddNewSubnodes( const QModelIndex &index, QSqlQuery &query, QAbstractItemModel *model)
{
while ( query.next() )
{
QString name = query.value( 0 ).toString();
int id = query.value( 1 ).toInt();

Q_ASSERT( !name.isEmpty() );
if ( name.isEmpty() )
{
name = "<EMPTY>";
}

qDebug() << "Insert node: " << name;
// Insert node
int model_row_count = model->rowCount( index );
model->insertRow( model_row_count, index );
QModelIndex subindex = model->index( model->rowCount( index ) - 1, 0, index );
model->setData( subindex, name );

FooTreeNodeData node_data;
node_data.id = id;
node_data.was_expanded = false;
node_data.is_type = true;
QVariant v;
v.setValue( node_data );

model->setData( subindex, v, Qt::UserRole );
node_data = model->data( subindex, Qt::UserRole ).value<FooTreeNodeData>();
qDebug() << "Node type ID: " << node_data.id;

// Insert subnode
model->insertColumn( 0, subindex );
model->insertRow( 0, subindex );
}
}


Can someone please tell me what wrong with the code above?

Thanks a lot

cyberboy
27th June 2008, 11:55
I didn't see the fault in your code, but here's mine.
I'm using a QAbstractTableModel, maybe you can use it for your program.


#include "articlesTableModel.h"
#include <QtGui>


ArticlesTableModel::ArticlesTableModel(const QList<QStringList> &data, const QStringList &header, QObject *parent)
: QAbstractTableModel(parent)
{
qDebug("ArticlesTableModel::ArticlesTableModel(): Constructing the table model");
this->articles = data;
this->header = header;
}


int ArticlesTableModel::rowCount( const QModelIndex& parent) const
{
Q_UNUSED(parent);
return articles.count();
}

int ArticlesTableModel::columnCount( const QModelIndex& parent) const
{
Q_UNUSED(parent);
return header.count();
}

QVariant ArticlesTableModel::headerData(int section, Qt::Orientation orientation, int role) const
{
if( Qt::Horizontal == orientation)
{
if(Qt::DisplayRole == role)
{
return header.at(section);
}
}

return QAbstractTableModel::headerData(section, orientation, role);
}

QVariant ArticlesTableModel::data(const QModelIndex &index, int role) const
{

if(!index.isValid())
return QVariant();

QStringList record = this->articles.at(index.row());

if(role == Qt::DisplayRole || role == Qt::EditRole){

return record.at(index.column());

}

return QVariant();

}

Qt::ItemFlags ArticlesTableModel::flags(const QModelIndex &index) const
{
if(!index.isValid())
return 0;

return QAbstractTableModel::flags(index) | Qt::ItemIsEditable;
}


bool ArticlesTableModel::setData(const QModelIndex& index, const QVariant& value, int role)
{
if(index.isValid() && (role == Qt::DisplayRole || role == Qt::EditRole)){
this->articles[index.row()][index.column()] = value.toString();
emit dataChanged(index, index);
return true;
}

return false;
}

bool ArticlesTableModel::insertRows(int row, int count, const QModelIndex &parent)
{
Q_UNUSED(parent);
QStringList emptyRecord;
for(int i = 0; i < columnCount(QModelIndex()); i++)
emptyRecord.append(QString());
beginInsertRows(QModelIndex(), row, row+count-1);
for(int i = 0; i < count; i++){
this->articles.insert(row, emptyRecord);
}
endInsertRows();

return true;
}

bool ArticlesTableModel::removeRows(int row, int count, const QModelIndex &parent)
{
Q_UNUSED(parent);
if(row-count-1 > this->articles.count() -1) return false;
beginRemoveRows(QModelIndex(), row, row+count-1);
for(int i=0; i<count; i++)
this->articles.removeAt(row);
endRemoveRows();
return true;

}