crash when using QStandardItem::setChild?... what's the diff between setChild and insertRow?



  • Hi,
    I'm debugging a crash on a "complex" tree when I'm moving a part of it.
    It's easier with a schema to express what I'm trying to do. Here it is: https://postimg.org/image/hok913xft/

    So basically, I'm on the item "System 2" and I'm editing its Type so it will move in the Tree.
    From "Sytem 2", I'm getting its container Item "System Container", from there I'm creating the new QStandardItem "Type B", that I'm adding as a last child of the System Container.
    I'm then also doing another setChild on the new Type to add him the "System 2"

    Does it sounds alright? The documentation of setChild says it will take the ownership of the items.

    Anyway, here is the full backtrace

    Thread 1 (Thread 0x7ffff7fab840 (LWP 31734)):
    #0  0x00007ffff301f97c in ?? () from /opt/Qt5.5.1/5.5/gcc_64/lib/libQt5Core.so.5
    No symbol table info available.
    #1  0x00007ffff301fa5d in QSortFilterProxyModel::mapToSource(QModelIndex const&) const () from /opt/Qt5.5.1/5.5/gcc_64/lib/libQt5Core.so.5
    No symbol table info available.
    #2  0x00007ffff302225c in ?? () from /opt/Qt5.5.1/5.5/gcc_64/lib/libQt5Core.so.5
    No symbol table info available.
    #3  0x00007ffff3025c42 in ?? () from /opt/Qt5.5.1/5.5/gcc_64/lib/libQt5Core.so.5
    No symbol table info available.
    #4  0x00007ffff302b543 in ?? () from /opt/Qt5.5.1/5.5/gcc_64/lib/libQt5Core.so.5
    No symbol table info available.
    #5  0x00007ffff308435e in QMetaObject::activate(QObject*, int, int, void**) () from /opt/Qt5.5.1/5.5/gcc_64/lib/libQt5Core.so.5
    No symbol table info available.
    #6  0x00007ffff3100ce6 in QAbstractItemModel::layoutAboutToBeChanged(QList<QPersistentModelIndex> const&, QAbstractItemModel::LayoutChangeHint) () from /opt/Qt5.5.1/5.5/gcc_64/lib/libQt5Core.so.5
    No symbol table info available.
    #7  0x00007ffff45275e8 in ?? () from /opt/Qt5.5.1/5.5/gcc_64/lib/libQt5Gui.so.5
    No symbol table info available.
    #8  0x0000000000448102 in QStandardItem::setChild (this=0x7cc2840, arow=2, aitem=0x7ce3e60) at /opt/Qt5.5.1/5.5/gcc_64/include/QtGui/qstandarditemmodel.h:288
    No locals.
    #9  0x00000000004692a7 in TreeSimpleItem::addChildTreeSimpleItem (this=0x7cc2840, childEltView=0x7aa9430, childEltType=0xd7ab50, label=...) at ../../../trunk/Ezavionics/View/Tree/TreeItem/TreeSimpleItem.cpp:128
            __PRETTY_FUNCTION__ = "TreeSimpleItem* TreeSimpleItem::addChildTreeSimpleItem(ElementView*, ElementType*, QString)"
            childTreeSimpleItem = 0x7ce3e60
    #10 0x0000000000468e7b in TreeSimpleItem::getChildTreeSimpleItem (this=0x7cc2840, childEltView=0x7aa9430, childEltType=0xd7ab50, label=...) at ../../../trunk/Ezavionics/View/Tree/TreeItem/TreeSimpleItem.cpp:114
            childTreeSimpleItem = 0x0
            it = {i = 0x7cc2c88}
            __PRETTY_FUNCTION__ = "TreeSimpleItem* TreeSimpleItem::getChildTreeSimpleItem(ElementView*, ElementType*, QString)"
    #11 0x000000000060c613 in PhysicalItemView::getParentTreeItem (this=0x195d850, containerTreeElementItem=0x7cc2160, treeContainmentLinkProperty=0xd968d0) at ../../../trunk/Ezavionics/View/Element/PhysicalItemView.cpp:111
            childRootItem = 0x7cc2840
            piTypeView = 0x7aa9430
            label = {static null = {<No data fields>}, d = 0x71c1fb0}
            parentTreeItem = 0x0
            __PRETTY_FUNCTION__ = "virtual TreeItem* PhysicalItemView::getParentTreeItem(TreeElementItem*, LinkProperty*)"
    #12 0x000000000044349f in ElementView::refreshParentTree (this=0x195d850, treeContainerLinkProperty=0xd884c0) at ../../../trunk/Ezavionics/View/Element/elementview.cpp:923
            newParent = 0x7a31cd0
            it2End = {i = {i = 0x200a250}}
            newParentItem = 0x7dac480
            compatible = true
            treeItemLinkProperty = 0xd884c0
            __PRETTY_FUNCTION__ = "void ElementView::refreshParentTree(LinkProperty*)"
            elementType = 0xd7b520
            treeItems = {q_hash = {{d = 0x7defb90, e = 0x7defb90}}}
            treeItem = 0x7df0b30
            eltView = 0x195d850
            treeContainmentLinkProperty = 0xd968d0
            it2 = {i = {i = 0x7d1bdb0}}
            treeModel = 0x177f420
            it = {i = {i = 0x7df0d60}}
            itEnd = {i = {i = 0x7defb90}}
            parentTreeItem = 0x7cc2160
            parentTreeItems = {q_hash = {{d = 0x200a250, e = 0x200a250}}}
            parentTreeContainerLinkProperty = 0xd965a0
    #13 0x0000000000443c56 in ElementView::refreshDependantElementViews (this=0x195d850, property=0xd883c0) at ../../../trunk/Ezavionics/View/Element/elementview.cpp:983
            element = 0x71f6580
            it2End = {i = {i = 0x7d16bc0}}
            linkedElements = {q_hash = {{d = 0x7d16bc0, e = 0x7d16bc0}}}
            __PRETTY_FUNCTION__ = "void ElementView::refreshDependantElementViews(Property*)"
            dependantProperties = 0xd883e0
            itEnd = {i = {i = 0x2d74180}}
            dependantEltView = 0x7a31cd0
            it = {i = {i = 0x2d74250}}
            linkProperty = 0xd884c0
            it2 = {i = {i = 0x8053820}}
    #14 0x00000000004427e0 in ElementView::update (this=0x195d850, property=0xd883c0, propertyValue=...) at ../../../trunk/Ezavionics/View/Element/elementview.cpp:825
            redrawFctDaisyRequired = false
            redrawSysDaisyRequired = false
            redrawTopoDaisyRequired = false
            __PRETTY_FUNCTION__ = "void ElementView::update(Property*, QVariant)"
    #15 0x00000000004b40fd in UpdateElementCommand::redo (this=0x7be61e0) at ../../../trunk/Ezavionics/Command/UpdateElementCommand.cpp:57
    No locals.
    #16 0x00007ffff733c198 in QUndoStack::push(QUndoCommand*) () from /opt/Qt5.5.1/5.5/gcc_64/lib/libQt5Widgets.so.5
    No symbol table info available.
    

    The crash is only happening when System 2 is expanded on my treeView and when I selected one of its occurence prior to come back on System 2 to edit its type.

    Any idea what could go wrong?

    Something else, as I suspect it is a refresh issue, I was about to not move my Item but try to create a new one. Doing this, I've just now change my 2 setChild to be insertRow and there are no crash anymore.

    Can you please explain what is the difference between setChild and insertRow?
    Can we have a QStandardItem in several places in a QStandardItemModel? or when we insert it somewhere it gets removed from where it was? (graphically it seems to be that but I'd like confirmation)

    Thanks in advance for your help.


  • Lifetime Qt Champion

    Hi,

    Can you show the code where you do that ?



  • Hi,
    it's a little complicated but basically the main code is like this:

                                    {
                                        newParentItem = getParentTreeItem(parentTreeItem, treeContainmentLinkProperty);
                                        
                                        if (newParentItem == 0)
                                        {
                                            newParentItem = parentTreeItem;
                                        }
                                        newParentItem->setChild(newParentItem->rowCount(), treeItem);
                                    }
    

    So basically,

    • parentTreeItem is the QStandardItem related to "System Container"
    • newParentItem is the one related to the Type, so in my exemple the function getParentTreeItem will return me a pointer on "Type B"
    • treeItem is the QStandardItem related to "System 2" that I've just edited and whose Type just changed.

    Here is kind of what happen in getParentTreeItem:

    ::getParentTreeItem(TreeElementItem* containerTreeElementItem, LinkProperty* treeContainmentLinkProperty)
    ...
         TreeSimpleItem* childTreeSimpleItem = new TreeSimpleItem(childEltType, getTreeModel(), 0, label);
        containerTreeElementItem->setChild(containerTreeElementItem->rowCount(), childTreeSimpleItem);
        return childTreeSimpleItem;
    

    Do you see anything suspicious? basically I'm creating the new Type "Type B", insert it under System Container, and from him move the System 2 under it...

    The crash on the stack is about QSortFilterProxyModel
    My View uses a Proxy and at the end of it a sort is done...
    I'm never using the Proxy, I guessing there could be an index problem there, should I warn it to refresh. Maybe remove my items from the model before moving them to not have a refresh issue?
    I understood that the Proxy was transparent once it was set up on the view and that we would just act straight on the model.

    In fact the replacement from setChild by insertRow was solving the issue but just temporarly, when I move back after my System I'm having a crash this time in the sorting of the Proxy...

    I'm definitely have some messed up index... how can I make this better?


  • Lifetime Qt Champion

    Isn't it insertChild ?

    Suspicious things ? Well... getParentTreeItem looks pretty suspicious. You create a new "parent tree item" each time you call that function.

    IIRC, you can invalidate the state of the QSortFilterProxyModel.



  • @SGaist
    Thanks for your answer.
    I've simplified the code I've exposed here. Basically I only create a new parent item for the Type of my System if it doesn't exist already, otherwise the getParentTreeItem function will return the matching existing one.

    it is not insertChild but setChild. I've modified my code to never use again setChild but rather takeRow and insertRow. This is not a problem in my case cause the rows of my tree only have one column.

    However I still have a crash in a particular case that have well isolated. I don't now if I should open a new ticket, I going to expose the issue here first.

    So exactly with the same use case: https://postimg.org/image/hok913xft/
    I'm changing the Type of "System 2". So another QStandardItem "Type B" is created and I'm doing a takeRow on the old parent ("Type A") then an insert under this new type.

    Everything works well BUT I'm then arriving to this code when I select an Item on my ViewTree:

    void TreeView::selectTreeItem(TreeItem *treeItem)
    {
        if (treeItem != 0)
        {
            TreeProxyModel* proxyModel = dynamic_cast<TreeProxyModel*>(model());
            if (proxyModel != 0 && proxyModel->getSourceModel() == treeItem->getTreeModel())
            {
                QModelIndex proxyModelIndex = proxyModel->getProxyModelIndexFromTreeItem(treeItem);
                if (proxyModelIndex.isValid() && proxyModelIndex != _selectedIndex)
                {
                    QItemSelectionModel* selectionModel = this->selectionModel();
                    if (selectionModel != 0)
                    {
                        selectionModel->clear();
                        selectionModel->setCurrentIndex(proxyModelIndex, QItemSelectionModel::Select);
                        selectionModel->select(proxyModelIndex, QItemSelectionModel::Select);
                        this->scrollTo(proxyModelIndex, QAbstractItemView::EnsureVisible);
                    }
                }
            }
        }
    }
    

    There is a crash in selectionModel->clear() if I'm selecting a child Occurence under the System2 I've just changed type.
    Basically, the selection model didn't unselect "System 2" before doing the move so it has corrupt indexes...
    I'm trying to force the UnSelect but it is done asynchronously and it happen after the move of my item...

    Any idea how I could say to the QItemSelectionModel that it may have corrupted indexes? Do I need to reimplement a clear function that would test the validity of its index prior to UnSelect?


  • Lifetime Qt Champion

    Are you properly calling the begin/moveXXX function when you are modifying your model ?



  • Hello, happy new year!
    how would you do this? I've seen this move function: QAbstractItemModel::moveRow(const QModelIndex &sourceParent, int sourceRow, const QModelIndex &destinationParent, int destinationChild) and also some begin/end functions (
    bool QAbstractItemModel::beginMoveColumns, QAbstractItemModel::endMoveRows) but those last ones are protected.

    I'm acting directly on the QStandardItem of my tree model. Doing:

                if (andDelete)
                {
                    parentItem->removeRow(treeItem->row());
                }
                else
                {
                    parentItem->takeRow(treeItem->row());
                }
                newParentItem->insertRow(0, treeItem);
    

    I would except the QStandardItemModel to be updated accordingly and signal all the view using it of the change. My QTreeView picks the change but it seems that the associated QItemSelectionModel doesn't staight away....

    Am I doing it wrong? what is the link between my QSortFilterProxyModel and QItemSelectionModel. As my TreeView is set on the the SortFilterProxyModel, shouldn't be the index synchronized?

    Here is my backtrace:

    Thread 1 (Thread 0x7ffff7fab840 (LWP 3907)):
    #0  0x00007ffff30257c8 in QSortFilterProxyModel::parent(QModelIndex const&) const () from /opt/Qt5.5.1/5.5/gcc_64/lib/libQt5Core.so.5
    No symbol table info available.
    #1  0x00007ffff2ffa2c3 in QPersistentModelIndex::parent() const () from /opt/Qt5.5.1/5.5/gcc_64/lib/libQt5Core.so.5
    No symbol table info available.
    #2  0x00007ffff3013bfd in ?? () from /opt/Qt5.5.1/5.5/gcc_64/lib/libQt5Core.so.5
    No symbol table info available.
    #3  0x00007ffff3010463 in QItemSelectionModel::select(QItemSelection const&, QFlags<QItemSelectionModel::SelectionFlag>) () from /opt/Qt5.5.1/5.5/gcc_64/lib/libQt5Core.so.5
    No symbol table info available.
    #4  0x00007ffff300ad68 in QItemSelectionModel::clearSelection() () from /opt/Qt5.5.1/5.5/gcc_64/lib/libQt5Core.so.5
    No symbol table info available.
    #5  0x00007ffff300adb9 in QItemSelectionModel::clear() () from /opt/Qt5.5.1/5.5/gcc_64/lib/libQt5Core.so.5
    No symbol table info available.
    #6  0x0000000000636ff8 in TreeView::selectTreeItem (this=0x46550f0, treeItem=0x7f40450) at ../../../trunk/Ezavionics/View/Tree/TreeView.cpp:64
            selectionModel = 0x59ae190
            proxyModelIndex = {r = 0, c = 0, i = 132584912, m = 0x201f0a0}
            proxyModel = 0x201f0a0
    #7  0x00000000007ef4fe in TreeView::qt_static_metacall (_o=0x46550f0, _c=QMetaObject::InvokeMetaMethod, _id=1, _a=0x7fffffffcff0) at debug/moc_TreeView.cpp:81
            _t = 0x46550f0
    #8  0x00007ffff308435e in QMetaObject::activate(QObject*, int, int, void**) () from /opt/Qt5.5.1/5.5/gcc_64/lib/libQt5Core.so.5
    No symbol table info available.
    #9  0x00000000007e4a1a in ActionDispatcher::selectTreeItemRequested (this=0xee7200, _t1=0x7f40450, _t2=false) at debug/moc_ActionDispatcher.cpp:308
            _a = {0x0, 0x7fffffffcfe0, 0x7fffffffcfdc}
    #10 0x0000000000463ee2 in ActionDispatcher::selectTreeRepresentation (this=0xee7200, eltView=0x7b313e0) at ../../../trunk/Ezavionics/Action/ActionDispatcher.cpp:469
            treeItems = {q_hash = {{d = 0x7f3fc30, e = 0x7f3fc30}}}
            it = {i = {i = 0x7f3f0a0}}
            itEnd = {i = {i = 0x7f3fc30}}
            treeItem = 0x7f40450
            __PRETTY_FUNCTION__ = "void ActionDispatcher::selectTreeRepresentation(ElementView*)"
    #11 0x0000000000462ff5 in ActionDispatcher::selectElementView (this=0xee7200, elementView=0x7b313e0, forceHighlight=false) at ../../../trunk/Ezavionics/Action/ActionDispatcher.cpp:309
            __PRETTY_FUNCTION__ = "void ActionDispatcher::selectElementView(ElementView*, bool)"
    #12 0x00000000006cd247 in DiagramScene::mouseReleaseEvent (this=0x463d3f0, event=0x7fffffffd5c0) at ../../../trunk/Ezavionics/View/Graphics/diagramscene.cpp:81
            eltView = 0x7b313e0
            qItem = 0x857b1d0
    

    If I try instead of doing a clear on the selection model to iterate on the selections:

    void TreeView::myClear(QItemSelectionModel *selectionModel)
    {
        uint nbSelect = 0;
        for (QModelIndex index : selectionModel->selectedIndexes())
        {
            if (index.isValid())
                ++nbSelect;
        }
    qDebug() << "[TreeView::myClear] nbSelect: " << nbSelect;
    }
    

    I'm getting the same kind of issue....

    #0  0x00007ffff30257c8 in QSortFilterProxyModel::parent(QModelIndex const&) const () from /opt/Qt5.5.1/5.5/gcc_64/lib/libQt5Core.so.5
    No symbol table info available.
    #1  0x00007ffff2ffa2c3 in QPersistentModelIndex::parent() const () from /opt/Qt5.5.1/5.5/gcc_64/lib/libQt5Core.so.5
    No symbol table info available.
    #2  0x00007ffff3013bfd in ?? () from /opt/Qt5.5.1/5.5/gcc_64/lib/libQt5Core.so.5
    No symbol table info available.
    #3  0x00007ffff300db70 in QItemSelection::merge(QItemSelection const&, QFlags<QItemSelectionModel::SelectionFlag>) () from /opt/Qt5.5.1/5.5/gcc_64/lib/libQt5Core.so.5
    No symbol table info available.
    #4  0x00007ffff300e866 in QItemSelectionModel::selectedIndexes() const () from /opt/Qt5.5.1/5.5/gcc_64/lib/libQt5Core.so.5
    No symbol table info available.
    #5  0x00000000006370bf in TreeView::myClear (this=0x3662b50, selectionModel=0x3676fa0) at ../../../trunk/Ezavionics/View/Tree/TreeView.cpp:88
            index = {r = -12832, c = 32767, i = 140737251553716, m = 0x7fffffffce20}
            __for_range = <unknown type in /home/bruel/Documents/PAM/QT/PamFramework/builds/build-trunk/Ezavionics/Ezavionics, CU 0x3ff5581, DIE 0x40509bb>
            __for_begin = {i = 0x0}
            __for_end = {i = 0x7fffffffce20}
            nbSelect = 0
            __PRETTY_FUNCTION__ = "void TreeView::myClear(QItemSelectionModel*)"
    #6  0x0000000000636ff4 in TreeView::selectTreeItem (this=0x3662b50, treeItem=0x7f40d20) at ../../../trunk/Ezavionics/View/Tree/TreeView.cpp:64
            selectionModel = 0x3676fa0
            proxyModelIndex = {r = 0, c = 0, i = 133135904, m = 0x23d8c90}
            proxyModel = 0x23d8c90
    #7  0x00000000007ef5da in TreeView::qt_static_metacall (_o=0x3662b50, _c=QMetaObject::InvokeMetaMethod, _id=1, _a=0x7fffffffcff0) at debug/moc_TreeView.cpp:81
            _t = 0x3662b50
    #8  0x00007ffff308435e in QMetaObject::activate(QObject*, int, int, void**) () from /opt/Qt5.5.1/5.5/gcc_64/lib/libQt5Core.so.5
    No symbol table info available.
    #9  0x00000000007e4af6 in ActionDispatcher::selectTreeItemRequested (this=0xeb9c40, _t1=0x7f40d20, _t2=false) at debug/moc_ActionDispatcher.cpp:308
            _a = {0x0, 0x7fffffffcfe0, 0x7fffffffcfdc}
    #10 0x0000000000463ee2 in ActionDispatcher::selectTreeRepresentation (this=0xeb9c40, eltView=0x7aab650) at ../../../trunk/Ezavionics/Action/ActionDispatcher.cpp:469
            treeItems = {q_hash = {{d = 0x7f402b0, e = 0x7f402b0}}}
            it = {i = {i = 0x7f40c50}}
            itEnd = {i = {i = 0x7f402b0}}
            treeItem = 0x7f40d20
            __PRETTY_FUNCTION__ = "void ActionDispatcher::selectTreeRepresentation(ElementView*)"
    #11 0x0000000000462ff5 in ActionDispatcher::selectElementView (this=0xeb9c40, elementView=0x7aab650, forceHighlight=false) at ../../../trunk/Ezavionics/Action/ActionDispatcher.cpp:309
            __PRETTY_FUNCTION__ = "void ActionDispatcher::selectElementView(ElementView*, bool)"
    #12 0x00000000006cd35d in DiagramScene::mouseReleaseEvent (this=0x364b9c0, event=0x7fffffffd5c0) at ../../../trunk/Ezavionics/View/Graphics/diagramscene.cpp:81
            eltView = 0x7aab650
            qItem = 0x81a6c20
    


  • I've finally found a workaround for the issue :)
    Basically before moving my item I send a signal intercepted directly by the TreeView that will clear the SelectionModel and thus all its PersistentIndex.

    It's quite vague for me how I could use properly begin/endMove because I'm not sure at which level to do it. On the Proxy, on the Model? Moreover when I fill my tree, I do it recursively going back up, which means, creating Items and if the parent doesn't exist I create the Parent Item and insert a row under the item (not directly on the Model...). Only the main stucture of my Tree is created directly on the Model.

    I find this way not so clean so I'm still open to suggestion to do it properly.
    Cheers


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.