Exposing QAbstractListModel to QML SegFault



  • Hello everyone!

    I have strange behavior in Qt 5.2. I'm trying to expose QAbstractListModel to QML, but after adding items to it it shows SegFault.
    main.cpp

    qmlRegisterType<AttachmentsToSendModel>("VKModels",1,0,"AttachmentsToSendModel");
    

    AttachmentsToSendModel.cpp

    #include "attachmentstosendmodel.h"
    
    AttachmentsToSendModel::AttachmentsToSendModel(QObject *parent)
    {
        setParent(parent);
        roles=roleNames();
        beginInsertRows(QModelIndex(),rowCount(),rowCount());
        AttachmentToSendItem* itm = new AttachmentToSendItem(this);
        QQmlEngine::setObjectOwnership(itm, QQmlEngine::CppOwnership);
        itm->setSource("file:///home/nemo/Pictures/SK/NwC1iub1wog.jpg");
        itm->setType(static_cast<AttachmentToSendItem::FileType>(0));
        Items.append(itm);
        endInsertRows();
    
    }
    
    AttachmentsToSendModel::~AttachmentsToSendModel()
    {
        qDebug()<<"Killed";
    }
    
    void AttachmentsToSendModel::addAttachment(QString source, int Type)
    {
        qDebug()<<source;
     beginInsertRows(QModelIndex(),rowCount(),rowCount());
     AttachmentToSendItem* itm = new AttachmentToSendItem(this);
     QQmlEngine::setObjectOwnership(itm, QQmlEngine::CppOwnership);
     itm->setSource(source);
     itm->setType(static_cast<AttachmentToSendItem::FileType>(Type));
     Items.append(itm);
     endInsertRows();
    }
    
    
    QModelIndex AttachmentsToSendModel::index(int row, int column, const QModelIndex &parent) const
    {
    }
    
    int AttachmentsToSendModel::rowCount(const QModelIndex &parent) const
    {
        return Items.count();
    }
    
    QVariant AttachmentsToSendModel::data(const QModelIndex &index, int role) const
    {
        if(!index.isValid())
            return QVariant();
        if(index.row()>=Items.size())
            return QVariant();
        if(role==TYPE)
            return Items.at(index.row())->Type();
        if(role==SOURCE)
        {
            qDebug()<<Items.at(index.row())->Source();
    //        return Items.at(index.row())->Source();
        }
        if(role==URL)
            qDebug()<<Items.at(index.row())->Url();
        if(role==STATUS)
            qDebug()<<Items.at(index.row())->Status();
        if(role==PROGRESS)
            qDebug()<<Items.at(index.row())->progress();
        if(role==TOTAL)
            qDebug()<<Items.at(index.row())->total();
     //   const RecursingWallItem* Wi = Items.at(index.row());
    
        return QVariant();
    
    }
    
    //bool AttachmentsToSendModel::insertRows(int row, int count, const QModelIndex &parent)
    //{
    //}
    
    //bool AttachmentsToSendModel::removeRows(int row, int count, const QModelIndex &parent)
    //{
    //    beginRemoveRows(QModelIndex(),row,count);
    //    for(int i=0;i<count;i++)
    //    {
    //        Items.at(row+i)->deleteLater();
    //        Items.removeAt(row+i);
    //    }
    //    qDebug()<<"deleting Attach";
    //    endRemoveRows();
    
    //}
    
    QHash<int, QByteArray> AttachmentsToSendModel::roleNames() const
    {
        QHash<int, QByteArray> roles;
    
        roles[TYPE] = "type";
        roles[SOURCE] = "c_source";
        roles[STATUS]="c_status";
        roles[URL] = "url";
        roles[PROGRESS] = "progress";
        roles[TOTAL] = "total";
    
        return roles;
    
    
    }
    

    AttachmentsToSendItem.h

    #ifndef ATTACHMENTTOSENDITEM_H
    #define ATTACHMENTTOSENDITEM_H
    
    #include <QObject>
    #include <QDebug>
    
    class AttachmentToSendItem : public QObject
    {
        Q_OBJECT
    
    public:
        explicit AttachmentToSendItem(QObject* parent=0);
        AttachmentToSendItem(QString source, int type);
        ~AttachmentToSendItem();
        Q_ENUMS(FileType)
        Q_PROPERTY(QString Url READ Url WRITE setUrl NOTIFY UrlChanged)
        Q_PROPERTY(int progress READ progress WRITE setProgress NOTIFY progressChanged)
        Q_PROPERTY(int total READ total WRITE setTotal NOTIFY totalChanged)
        Q_PROPERTY(QString Source READ Source WRITE setSource NOTIFY SourceChanged)
        Q_PROPERTY(FileType Type READ Type WRITE setType NOTIFY TypeChanged)
        Q_PROPERTY(int Status READ Status WRITE setStatus NOTIFY StatusChanged)
        enum FileType {
            PHOTO,
            VIDEO,
            AUDIO,
            DOC,
            WALL
        };
        QString Url() const;
    
        int progress() const;
    
        int total() const;
    
        QString Source() const;
    
        FileType Type() const;
    
        int Status() const;
    
    signals:
    
        void UrlChanged(QString Url);
    
        void progressChanged(int progress);
    
        void totalChanged(int total);
    
        void SourceChanged(QString Source);
    
        void TypeChanged(FileType Type);
    
        void StatusChanged(int Status);
    
    public slots:
        void setUrl(QString Url);
        void setProgress(int progress);
    
        void setTotal(int total);
    
        void setSource(QString Source);
    
        void setType(FileType Type);
    
        void setStatus(int Status);
    
    private:
        QString m_Url="";
        int m_progress=0;
        int m_total;
        QString m_Source;
        FileType m_Type;
        int m_Status=2;
    };
    
    #endif // ATTACHMENTTOSENDITEM_H
    

    AttachmentToSendItem.cpp

    #include "attachmenttosenditem.h"
    
    
    AttachmentToSendItem::AttachmentToSendItem(QObject *parent)
    {
        setParent(parent);
    }
    
    AttachmentToSendItem::AttachmentToSendItem(QString source,int type)
    {
        setSource(source);
        setType(static_cast<FileType>(type));
    }
    
    AttachmentToSendItem::~AttachmentToSendItem()
    {
        qDebug()<<"Killed";
    }
    
    QString AttachmentToSendItem::Url() const
    {
        return m_Url;
    }
    
    int AttachmentToSendItem::progress() const
    {
        return m_progress;
    }
    
    int AttachmentToSendItem::total() const
    {
        return m_total;
    }
    
    QString AttachmentToSendItem::Source() const
    {
        return m_Source;
    }
    
    AttachmentToSendItem::FileType AttachmentToSendItem::Type() const
    {
        return m_Type;
    }
    
    int AttachmentToSendItem::Status() const
    {
        return m_Status;
    }
    
    void AttachmentToSendItem::setUrl(QString Url)
    {
        if (m_Url == Url)
            return;
        
        m_Url = Url;
        emit UrlChanged(Url);
    }
    
    void AttachmentToSendItem::setProgress(int progress)
    {
        if (m_progress == progress)
            return;
        
        m_progress = progress;
        emit progressChanged(progress);
    }
    
    void AttachmentToSendItem::setTotal(int total)
    {
        if (m_total == total)
            return;
        
        m_total = total;
        emit totalChanged(total);
    }
    
    void AttachmentToSendItem::setSource(QString Source)
    {
        if (m_Source == Source)
            return;
        
        m_Source = Source;
        emit SourceChanged(Source);
    }
    
    void AttachmentToSendItem::setType(AttachmentToSendItem::FileType Type)
    {
        if (m_Type == Type)
            return;
    
        m_Type = Type;
        emit TypeChanged(Type);
    }
    
    void AttachmentToSendItem::setStatus(int Status)
    {
        if (m_Status == Status)
            return;
        
        m_Status = Status;
        emit StatusChanged(Status);
    }
    

    .qml

    
    import QtQuick 2.0
    import Sailfish.Silica 1.0
    import QtMultimedia 5.0
    import VKModels 1.0
    import ".."
    import "../items"
    import QtDocGallery 5.0
    import org.nemomobile.thumbnailer 1.0
    
    
    Page{
        id:page
    
        property string headertitle;
        property int chat_id;
        property bool isMulti:false
        property string sobesed_photo;
        onStatusChanged: {
            if(status == PageStatus.Active)
                historyModel.isActive = true;
            else if(status == PageStatus.Activating)
                historyModel.isActive = true;
    
            historyModel.isActive = false;
        }
        Component.onCompleted: {
            historyModel.clear_Messages();
            globalSettings.companionId=chat_id;
            vkapi.messages_getHistory(chat_id,0,20,-1);
        }
        Component.onDestruction:
        {
            globalSettings.companionId=0;
        }
    
        Drawer{
            id:attachDrawer
            open:false
            dock:Dock.Bottom
            anchors.fill: parent
            PageHeader{
                id:name_info
                title:headertitle
                anchors {
                    leftMargin: 10
                }
            }
            SilicaListView {
                id: listView
                model: historyModel
                anchors.bottom: sendArea.top
                verticalLayoutDirection: ListView.BottomToTop
    
                PullDownMenu {
                    id:pulley
                    MenuItem {
                        text: "добавить прошлые записи"
                        onClicked:
                        {
                            vkapi.messages_getHistory(chat_id,listView.count,20,-1)
                        }
                    }
                }
    
                width: parent.width
                height: parent.height-name_info.height
                spacing: 30
                anchors {
                    top:name_info.bottom
                }
                clip:true
                delegate:MessageItem{
                    isOut:out
                    author: isMulti?first_name+ " "+last_name:""
                    fwdMsg: historyModel.getFwdMessage(id)
                    attachWallpost: historyModel.getFwdPost(id)
                }
    
            }
    
            Item{
                id:sendArea
                anchors.bottom: parent.bottom
                //            anchors.left:parent.left
                width: parent.width
                height: messageArea.height+attachmentstoSend.height+Theme.paddingSmall
    //! If model empty everything ok, but if it has items -> SegFault
                SilicaListView{
                    id:attachmentstoSend
                    width:parent.width
                    height: model.count>0?Theme.itemSizeMedium:0
                    anchors.bottom: messageArea.top
                    model:c_attachmentsModelToSend
                    orientation:Qt.Horizontal
                    spacing:5
                    delegate: Image{
                        width:Theme.itemSizeMedium
                        height:width
                        sourceSize: Qt.size(width,height)
                        source:"image://nemoThumbnail/"+c_source
                        IconButton{
                        icon.source: "image://theme/icon-s-clear-opaque-cross?"+Theme.highlightColor
                        anchors.centerIn: parent
                        //onClicked: c_attachmentsModelToSend.(index)
                        }
                        Rectangle{
                        color:"black"
                        visible: c_status>0
                        opacity: 0.5
                        }
                       BusyIndicator{
                           size: BusyIndicatorSize.Medium
                                   anchors.centerIn: parent
                                   running: c_status>0
    
                       }
                    }
                }
                IconButton {
                    id:skrepkaWizard
                    icon.source: "image://theme/icon-m-attach"
                    highlighted: false
                    anchors.bottom: messageArea.bottom
                    anchors.right:messageArea.left
                    anchors.bottomMargin: 25
                    onClicked: attachDrawer.open=true
                }
                TextArea {
                    id:messageArea
    
                    anchors.bottom: parent.bottom
                    anchors.right: sendButton.left
    
                    height:  Math.min(Theme.itemSizeExtraLarge,implicitHeight)//Math.max(page.height/5, Math.min(page.height/3,implicitHeight))
                    width:parent.width-sendButton.width- skrepkaWizard.width
                }
    
                IconButton {
                    id:sendButton
                    icon.source: "image://theme/icon-m-message"
                    highlighted: false
                    anchors.bottom: messageArea.bottom
                    //                anchors.left:messageArea.right
                    anchors.right:parent.right
                    anchors.bottomMargin: 25
    
                    onClicked: {
                        console.log(parent.width,sendButton.width,messageArea.width)
                        vkapi.messages_send(chat_id,messageArea.text)
                        messageArea.selectAll()
                        messageArea.text=""
                        highlighted=!highlighted
    
                        //       historyModel.clear_Messages()
                        //       vkapi.messages_getHistory(chat_id,false,20,0)
    
                    }
                }
            }
    
    
            MouseArea {
                enabled: attachDrawer.open
                anchors.fill: listView
                onClicked: attachDrawer.open = false
            }
    
    
            background:Loader{
                id:attachLoader
                anchors.fill: parent
                source:"../items/AttachComponent.qml"
    
            }
        }
    
    
        MessageModel{
            id:historyModel
            Component.onCompleted:
            {
                historyModel.DataProvider=c_dataProvider
                historyModel.userId=chat_id
            }
        }
        DocumentGalleryModel {
            id: galleryModel
            rootType: DocumentGallery.Image
            properties: [ "url", "title", "dateTaken" ]
            autoUpdate: true
            sortProperties: ["-dateTaken"]
        }
        ListModel{
            id:attachmentsModelToSend
        }
    
        Connections {
            target: attachLoader.item
            onS_items: {
                console.log(items)
                var types = ["photo","video","place","audio","doc","photoVK","videoVK"];
                for(var i=0;i<items.length;i++)
                {
                    console.log(items[i]);
                    var file = galleryModel.get(items[i].id).url;
                    console.log(file)
                    attachmentsModelToSend.append({"url":"image://nemoThumbnail/"+galleryModel.get(items[i].id).url,"type":types[items[i].type],"status":2})
                    c_attachmentsModelToSend.addAttachment(file,types[items[i].type])
                }
            }
        }
    }
    
    

    I understand that issue somehow has problem near ownership of QObject. But I can't find it.
    Please help.


  • Moderators

    @blacky_i Since you have used qmlRegisterType you need to instantiate the type in QML.

    VKModels {
      id: vkModels
    }
    

    Is it done already? I found it missing in your code.
    http://doc.qt.io/qt-5/qtquick-modelviewsdata-cppmodels.html#exposing-c-data-models-to-qml



  • but VKModels is used as import in the beginning of QML...

    AttachmentsToSendModel is creating in here


  • Moderators

    @blacky_i import doesnot create it. It just makes aware about the type to the engine.
    See the example in the link posted earlier.



  • Oh shoot! i posted wrong qml file! here I am creating AttachmentsToSendModel

    
    import QtQuick 2.0
    import Sailfish.Silica 1.0
    import QtMultimedia 5.0
    import VKModels 1.0
    import ".."
    import "../items"
    import QtDocGallery 5.0
    import org.nemomobile.thumbnailer 1.0
    
    
    Page{
        id:page
    
    
        signal addAttach(var src,var type);
        property string headertitle;
        property int chat_id;
        property bool isMulti:false
        property string sobesed_photo;
        onStatusChanged: {
            if(status == PageStatus.Active)
                historyModel.isActive = true;
            else if(status == PageStatus.Activating)
                historyModel.isActive = true;
    
            historyModel.isActive = false;
        }
        Component.onCompleted: {
            historyModel.clear_Messages();
            globalSettings.companionId=chat_id;
            vkapi.messages_getHistory(chat_id,0,20,-1);
        }
        Component.onDestruction:
        {
            globalSettings.companionId=0;
        }
    
        Drawer{
            id:attachDrawer
            open:false
            dock:Dock.Bottom
            anchors.fill: parent
            PageHeader{
                id:name_info
                title:headertitle
                anchors {
                    leftMargin: 10
                }
            }
            SilicaListView {
                id: listView
                model: historyModel
                anchors.bottom: sendArea.top
                verticalLayoutDirection: ListView.BottomToTop
    
                PullDownMenu {
                    id:pulley
                    MenuItem {
                        text: "добавить прошлые записи"
                        onClicked:
                        {
                            vkapi.messages_getHistory(chat_id,listView.count,20,-1)
                        }
                    }
                }
    
                width: parent.width
                height: parent.height-name_info.height
                spacing: 30
                anchors {
                    top:name_info.bottom
                }
                clip:true
                delegate:MessageItem{
                    isOut:out
                    author: isMulti?first_name+ " "+last_name:""
                    fwdMsg: historyModel.getFwdMessage(id)
                    attachWallpost: historyModel.getFwdPost(id)
                }
    
            }
    
            Item{
                id:sendArea
                anchors.bottom: parent.bottom
                //            anchors.left:parent.left
                width: parent.width
                height: messageArea.height+attachmentstoSend.height+Theme.paddingSmall
                SilicaListView{
                    id:attachmentstoSend
                    width:parent.width
                    height: model.count>0?Theme.itemSizeMedium:0
                    anchors.bottom: messageArea.top
                    model:c_attachmentsModelToSend
                    orientation:Qt.Horizontal
                    spacing:5
                    delegate: Image{
                        width:Theme.itemSizeMedium
                        height:width
                        sourceSize: Qt.size(width,height)
                        source:"image://nemoThumbnail/"+c_source
                        IconButton{
                        icon.source: "image://theme/icon-s-clear-opaque-cross?"+Theme.highlightColor
                        anchors.centerIn: parent
                        //onClicked: c_attachmentsModelToSend.(index)
                        }
                        Rectangle{
                        color:"black"
                        visible: c_status>0
                        opacity: 0.5
                        }
                       BusyIndicator{
                           size: BusyIndicatorSize.Medium
                                   anchors.centerIn: parent
                                   running: c_status>0
    
                       }
                    }
                }
                IconButton {
                    id:skrepkaWizard
                    icon.source: "image://theme/icon-m-attach"
                    highlighted: false
                    anchors.bottom: messageArea.bottom
                    anchors.right:messageArea.left
                    anchors.bottomMargin: 25
                    onClicked: attachDrawer.open=true
                }
                TextArea {
                    id:messageArea
    
                    anchors.bottom: parent.bottom
                    anchors.right: sendButton.left
    
                    height:  Math.min(Theme.itemSizeExtraLarge,implicitHeight)//Math.max(page.height/5, Math.min(page.height/3,implicitHeight))
                    width:parent.width-sendButton.width- skrepkaWizard.width
                }
    
                IconButton {
                    id:sendButton
                    icon.source: "image://theme/icon-m-message"
                    highlighted: false
                    anchors.bottom: messageArea.bottom
                    //                anchors.left:messageArea.right
                    anchors.right:parent.right
                    anchors.bottomMargin: 25
    
                    onClicked: {
                        console.log(parent.width,sendButton.width,messageArea.width)
                        vkapi.messages_send(chat_id,messageArea.text)
                        messageArea.selectAll()
                        messageArea.text=""
                        highlighted=!highlighted
    
                        //       historyModel.clear_Messages()
                        //       vkapi.messages_getHistory(chat_id,false,20,0)
    
                    }
                }
            }
    
    
            MouseArea {
                enabled: attachDrawer.open
                anchors.fill: listView
                onClicked: attachDrawer.open = false
            }
    
    
            background:Loader{
                id:attachLoader
                anchors.fill: parent
                source:"../items/AttachComponent.qml"
    
            }
        }
    
    
        MessageModel{
            id:historyModel
            Component.onCompleted:
            {
                historyModel.DataProvider=c_dataProvider
                historyModel.userId=chat_id
            }
        }
        DocumentGalleryModel {
            id: galleryModel
            rootType: DocumentGallery.Image
            properties: [ "url", "title", "dateTaken" ]
            autoUpdate: true
            sortProperties: ["-dateTaken"]
        }
        AttachmentsToSendModel{
        id:c_attachmentsModelToSend
        }
    
    
    
        Connections {
            target: attachLoader.item
            onS_items: {
                console.log(items)
                var types = ["photo","video","place","audio","doc","photoVK","videoVK"];
                for(var i=0;i<items.length;i++)
                {
                    console.log(items[i]);
                    var file = galleryModel.get(items[i].id).url;
                    console.log(file)
                    c_attachmentsModelToSend.addAttachment(file,types[items[i].type])
                }
            }
        }
    }
    
    

    error still the same. If Items in model >0, then SegFault
    If in AttachmentToSendModel.cpp use List<AttachmentToSendItem> Items instead of List<AttachmentToSendItem*> Items as collection, After adding new item it deletes immediately and calling SegFault.



  • Strange, but SegFault is gone.
    I removed realization of QModelIndex AttachmentsToSendModel::index(int row, int column, const QModelIndex &parent) and SegFault is gone.
    Any ideas why?



  • this

    QModelIndex AttachmentsToSendModel::index(int row, int column, const QModelIndex &parent) const
    {
    }
    

    should not even compile, you need to return something...



  • I understand my stupid errror. Problem solved.


Log in to reply
 

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