PDA

View Full Version : QTreeView remove issue



ComaWhite
1st January 2010, 21:49
I have my QTreeView basically working like I want. The only issue is that when I remove a row from a leaf in the QTreeView.

If I have the node expanded when an row is removed it works fine. But when the node is collapsed when I remove the row the arrow next to the leaf is gone until I add a new row or something like that.

EDIT: It seems to not update the leaf's text and add the item when it is collapsed either.



void
NickTreeModel::removeUser(Aki::NickTreeItem *item)
{
int row = -1;
for (int i = 0; i < d->rootItem->childCount(); ++i) {
QModelIndex idx = index(i, 0);
Aki::NickTreeItem *categoryItem = d->rootItem->child(i);
if ((row = categoryItem->indexOfChild(item)) != -1) {
beginRemoveRows(idx, row, row);
delete categoryItem->takeChild(row);
endRemoveRows();
reset();
}
}
}

void
NickTreeModel::removeUser(Aki::Irc::User *user)
{
int row = -1;
for (int i = 0; i < d->rootItem->childCount(); ++i) {
QModelIndex idx = index(i, 0);
Aki::NickTreeItem *categoryItem = d->rootItem->child(i);
if ((row = categoryItem->indexOfChild(user)) != -1) {
beginRemoveRows(idx, row, row);
delete categoryItem->takeChild(row);
endRemoveRows();
}
}
}

psih128
1st January 2010, 23:57
You meant that the arrow is gone and you have other rows under your leaf, right? It is possible that you have bugs in other parts of your model - index, parent functions.

The most reliable way to assure that your model does not have obvious bugs is the ModelTest (http://labs.trolltech.com/page/Projects/Itemview/Modeltest) test suite.

It's hard to say with assurance what is the problem is your case, as we cant see full model implementation

There are also a few things I noticed (probably not relevant to the problem):
1) calling reset(); does not make much sense as you are trying to remove the item.
2) You should probably call break; as soon as you find a mach in your data source to remove. Otherwise you may end up with quite subtle bugs.

Good luck!

ComaWhite
2nd January 2010, 04:11
I'm running ModelTest and it doesn't say anything about it when it happens.
My tree layout is like



Root--|
--Operators
|
--Half-Operators
|
--Voices
|
--Users


NickTreeModel::NickTreeModel(QObject *parent)
: QAbstractItemModel(parent)
{
d.reset(new Aki::NickTreeModelPrivate(this));

d->rootItem = new Aki::NickTreeItem;

d->operatorsItem = new Aki::NickTreeItem(d->rootItem, "Operators");
d->operatorsItem->setIcon(KIcon("aki_operator"));
d->rootItem->addChild(d->operatorsItem);

d->halfOperatorsItem = new Aki::NickTreeItem(d->rootItem, "Half-Operators");
d->halfOperatorsItem->setIcon(KIcon("aki_halfop"));
d->rootItem->addChild(d->halfOperatorsItem);

d->voicesItem = new Aki::NickTreeItem(d->rootItem, "Voices");
d->voicesItem->setIcon(KIcon("aki_voice"));
d->rootItem->addChild(d->voicesItem);

d->usersItem = new Aki::NickTreeItem(d->rootItem, "Users");
d->usersItem->setIcon(KIcon("aki_normal"));
d->rootItem->addChild(d->usersItem);

sort(0);
}

NickTreeModel::~NickTreeModel()
{
delete d->rootItem;
}

void
NickTreeModel::addUser(Aki::NickTreeItem *item)
{
int row = -1;
Aki::Irc::User *user = d->user(item);
if (user->isOp()) {
row = d->operatorsItem->childCount();
beginInsertRows(index(0, 0), row, row);
item->setParent(d->operatorsItem);
d->operatorsItem->addChild(item);
endInsertRows();
return;
} else if (user->isHalfOp()) {
row = d->halfOperatorsItem->childCount();
beginInsertRows(index(1, 0), row, row);
item->setParent(d->halfOperatorsItem);
d->halfOperatorsItem->addChild(item);
endInsertRows();
return;
} else if (user->isVoice()) {
row = d->voicesItem->childCount();
beginInsertRows(index(2, 0), row, row);
item->setParent(d->voicesItem);
d->voicesItem->addChild(item);
endInsertRows();
return;
} else if (user->isNormal()){
row = d->usersItem->childCount();
beginInsertRows(index(3, 0), row, row);
item->setParent(d->usersItem);
d->usersItem->addChild(item);
endInsertRows();
return;
}
}

void
NickTreeModel::removeUser(Aki::NickTreeItem *item)
{
int row = -1;
for (int i = 0; i < d->rootItem->childCount(); ++i) {
QModelIndex idx = index(i, 0);
Aki::NickTreeItem *categoryItem = d->rootItem->child(i);
if ((row = categoryItem->indexOfChild(item)) != -1) {
beginRemoveRows(idx, row, row);
delete categoryItem->takeChild(row);
endRemoveRows();
return;
}
}
}

void
NickTreeModel::removeUser(Aki::Irc::User *user)
{
int row = -1;
for (int i = 0; i < d->rootItem->childCount(); ++i) {
QModelIndex idx = index(i, 0);
Aki::NickTreeItem *categoryItem = d->rootItem->child(i);
if ((row = categoryItem->indexOfChild(user)) != -1) {
beginRemoveRows(idx, row, row);
delete categoryItem->takeChild(row);
endRemoveRows();
return;
}
}
}

void
NickTreeModel::changeParents(Aki::NickTreeItem *item)
{
int row = -1;
QModelIndex idx;
Aki::NickTreeItem *categoryItem;
for (int i = 0; i < d->rootItem->childCount(); ++i) {
idx = index(i, 0);
categoryItem = d->item(idx);
if (categoryItem->indexOfChild(item) != -1) {
row = categoryItem->indexOfChild(item);
break;
}
}

if (!idx.isValid() || row == -1) {
return;
}

int newRow = -1;
Aki::Irc::User *user = d->user(item);
if (user->isOp()) {
newRow = d->operatorsItem->childCount();
if (idx == index(0, 0) &&
row == (newRow - 1)) {
return;
}
bool success = beginMoveRows(idx, row, row, index(0, 0), newRow);
if (success) {
Aki::NickTreeItem *old = categoryItem->takeChild(row);
old->setParent(d->operatorsItem);
d->operatorsItem->addChild(old);
endMoveRows();
return;
}

} else if (user->isHalfOp()) {
newRow = d->halfOperatorsItem->childCount();
if (idx == index(1, 0) &&
row == (newRow - 1)) {
return;
}
bool success = beginMoveRows(idx, row, row, index(1, 0), newRow);
if (success) {
Aki::NickTreeItem *old = categoryItem->takeChild(row);
old->setParent(d->halfOperatorsItem);
d->halfOperatorsItem->addChild(old);
endMoveRows();
return;
}
} else if (user->isVoice()) {
newRow = d->voicesItem->childCount();
if (idx == index(2, 0) &&
row == (newRow - 1)) {
return;
}
bool success = beginMoveRows(idx, row, row, index(2, 0), newRow);
if (success) {
Aki::NickTreeItem *old = categoryItem->takeChild(row);
old->setParent(d->voicesItem);
d->voicesItem->addChild(old);
endMoveRows();
return;
}
} else if (user->isNormal()){
newRow = d->usersItem->childCount();
if (idx == index(3, 0) &&
row == (newRow - 1)) {
return;
}
bool success = beginMoveRows(idx, row, row, index(3, 0), newRow);
if (success) {
Aki::NickTreeItem *old = categoryItem->takeChild(row);
old->setParent(d->usersItem);
d->usersItem->addChild(old);
endMoveRows();
return;
}
}
}

QList<Aki::Irc::User*>
NickTreeModel::users()
{
QList<Aki::Irc::User*> tmp;

for (int i = 0; i < d->rootItem->childCount(); ++i) {
Aki::NickTreeItem *item = d->rootItem->child(i);
for (int j = 0; j < item->childCount(); ++j) {
Aki::Irc::User *child =
item->child(j)->data(Aki::NickTreeItem::IrcUserRole).value<Aki::Irc::User*>();
tmp.append(child);
}
}

return tmp;
}

void
NickTreeModel::clear()
{
beginRemoveRows(QModelIndex(), 0, 3);
delete d->rootItem->takeChild(3);
delete d->rootItem->takeChild(2);
delete d->rootItem->takeChild(1);
delete d->rootItem->takeChild(0);
endRemoveRows();
}

void
NickTreeModel::addCategories()
{
beginInsertRows(QModelIndex(), 0, 3);
d->operatorsItem = new Aki::NickTreeItem(d->rootItem, "Operators");
d->operatorsItem->setIcon(KIcon("aki_operator"));
d->rootItem->addChild(d->operatorsItem);

d->halfOperatorsItem = new Aki::NickTreeItem(d->rootItem, "Half-Operators");
d->halfOperatorsItem->setIcon(KIcon("aki_halfop"));
d->rootItem->addChild(d->halfOperatorsItem);

d->voicesItem = new Aki::NickTreeItem(d->rootItem, "Voices");
d->voicesItem->setIcon(KIcon("aki_voice"));
d->rootItem->addChild(d->voicesItem);

d->usersItem = new Aki::NickTreeItem(d->rootItem, "Users");
d->usersItem->setIcon(KIcon("aki_normal"));
d->rootItem->addChild(d->usersItem);
endInsertRows();
}

QVariant
NickTreeModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid()) {
return QVariant();
}

Aki::NickTreeItem *item = d->item(index);

switch (role) {
case Aki::NickTreeModel::AwayRole: {
return item->data(Aki::NickTreeItem::IrcUserAwayRole);
break;
}
case Qt::DecorationRole: {
return item->data(Qt::DecorationRole);
break;
}
case Qt::DisplayRole: {
return item->data(Qt::DisplayRole);
break;
}
case Aki::NickTreeModel::UserRole: {
return item->data(Aki::NickTreeItem::IrcUserRole);
break;
}
case Qt::ToolTipRole: {
return item->data(Qt::ToolTipRole);
break;
}
default: {
return QVariant();
}
}

return QVariant();
}

int
NickTreeModel::columnCount(const QModelIndex &parent) const
{
if (parent.isValid()) {
return d->item(parent)->columnCount();
}

return d->rootItem->columnCount();
}

int
NickTreeModel::rowCount(const QModelIndex &parent) const
{
if (parent.column() > 0) {
return 0;
}

if (!parent.isValid()) {
return d->rootItem->childCount();
}

return d->item(parent)->childCount();
}

QModelIndex
NickTreeModel::parent(const QModelIndex &child) const
{
if (!child.isValid()) {
return QModelIndex();
}

Aki::NickTreeItem *childItem = d->item(child);
Aki::NickTreeItem *parentItem = childItem->parent();

if (parentItem == d->rootItem) {
return QModelIndex();
}

return createIndex(parentItem->row(), 0, parentItem);
}

QModelIndex
NickTreeModel::index(int row, int column, const QModelIndex &parent) const
{
if (!hasIndex(row, column, parent)) {
return QModelIndex();
}

Aki::NickTreeItem *parentItem = 0;

if (!parent.isValid()) {
parentItem = d->rootItem;
} else {
parentItem = d->item(parent);
}

Aki::NickTreeItem *childItem = parentItem->child(row);
if (childItem) {
return createIndex(row, column, childItem);
} else {
return QModelIndex();
}

return QModelIndex();
}

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

return d->item(index)->flags();
}

bool
NickTreeModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
if (!index.isValid()) {
return false;
}

if (role != Aki::NickTreeModel::UserRole) {
return false;
}

Aki::NickTreeItem *item = d->item(index);
if (item) {
item->setData(0, Aki::NickTreeItem::IrcUserRole, value);
emit dataChanged(index, index);
return true;
}

return false;
}
#include "nicktreemodel.moc"

ComaWhite
2nd January 2010, 19:13
I found the problem. It's a bug in Qt that has never been fixed at all in the past 3 years. One of the guys in #qt on freenode told me about it. I can reproduce it in one of the examples in Qt.

If you compile Qt's EditableTreeModel. Create a toplevel item and create a child in it. Keep the child selected and collapse the leaf and remove the row and the issue appears.