Skip to content
Snippets Groups Projects
messagemodel.cpp 11.1 KiB
Newer Older
/********************************************************************************************
 *                                                                                          *
 * Copyright (C) 2017 Armin Felder, Dennis Beier                                            *
 * This file is part of RocketChatMobileEngine <https://git.fairkom.net/chat/fairchat>.     *
 *                                                                                          *
 * RocketChatMobileEngine is free software: you can redistribute it and/or modify           *
 * it under the terms of the GNU General Public License as published by                     *
 * the Free Software Foundation, either version 3 of the License, or                        *
 * (at your option) any later version.                                                      *
 *                                                                                          *
 * RocketChatMobileEngine is distributed in the hope that it will be useful,                *
 * but WITHOUT ANY WARRANTY; without even the implied warranty of                           *
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                            *
 * GNU General Public License for more details.                                             *
 *                                                                                          *
 * You should have received a copy of the GNU General Public License                        *
 * along with RocketChatMobileEngine. If not, see <http://www.gnu.org/licenses/>.           *
 *                                                                                          *
 ********************************************************************************************/



Armin Felder's avatar
Armin Felder committed
#include "messagemodel.h"

#include <repos/entities/rocketchatreplymessage.h>

Armin Felder's avatar
Armin Felder committed
MessagesModel::MessagesModel()
{
Armin Felder's avatar
Armin Felder committed
    duplicateCheck.reserve( 10000 );
Armin Felder's avatar
Armin Felder committed
}

QVariant MessagesModel::data( const QModelIndex &index, int role ) const
{
    int row = index.row();

    QSharedPointer<RocketChatMessage> messageAtIndex =  messagesOfCurrentChannel.at( row );

Armin Felder's avatar
Armin Felder committed
    auto roleType  = static_cast<MessageRoles>( role );
Armin Felder's avatar
Armin Felder committed

Armin Felder's avatar
Armin Felder committed
    switch ( roleType ) {
        case MessageRoles::type:
            return messageAtIndex->getMessageType();
Armin Felder's avatar
Armin Felder committed

Armin Felder's avatar
Armin Felder committed
        case MessageRoles::text:
            return messageAtIndex->getMessageString();
Armin Felder's avatar
Armin Felder committed

Armin Felder's avatar
Armin Felder committed
        case MessageRoles::linkurl:
            if ( !messageAtIndex->getAttachments().empty() ) {
                return messageAtIndex->getAttachments().first()->getUrl();
            } else {
                qWarning() << "linkurl not found";
            }
Armin Felder's avatar
Armin Felder committed

Armin Felder's avatar
Armin Felder committed
            break;
Armin Felder's avatar
Armin Felder committed
        case MessageRoles::author:
            return messageAtIndex->getAuthor();
Armin Felder's avatar
Armin Felder committed

Armin Felder's avatar
Armin Felder committed
        case MessageRoles::authorId:
            return messageAtIndex->getAuthorId();
Armin Felder's avatar
Armin Felder committed

Armin Felder's avatar
Armin Felder committed
        case MessageRoles::date:
            return messageAtIndex->getFormattedDate();
Armin Felder's avatar
Armin Felder committed

Armin Felder's avatar
Armin Felder committed
        case MessageRoles::time:
            return messageAtIndex->getFormattedTime();
Armin Felder's avatar
Armin Felder committed

Armin Felder's avatar
Armin Felder committed
        case MessageRoles::ownMessage:
            return messageAtIndex->getOwnMessage();
Armin Felder's avatar
Armin Felder committed
        case MessageRoles::width:
            if ( !messageAtIndex->getAttachments().empty() ) {
                return messageAtIndex->getAttachments().first()->getWidth();
            } else {
                qWarning() << "width not found";
            }
Armin Felder's avatar
Armin Felder committed

Armin Felder's avatar
Armin Felder committed
            break;
Armin Felder's avatar
Armin Felder committed

Armin Felder's avatar
Armin Felder committed
        case MessageRoles::height:
            if ( !messageAtIndex->getAttachments().empty() ) {
                return messageAtIndex->getAttachments().first()->getHeight();
            } else {
                qWarning() << "height not found";
            }
Armin Felder's avatar
Armin Felder committed

Armin Felder's avatar
Armin Felder committed
            break;
Armin Felder's avatar
Armin Felder committed
        case MessageRoles::formattedDate:
            return messageAtIndex->getFormattedDate();

        case MessageRoles::formattedTime:
            return messageAtIndex->getFormattedTime();

        case MessageRoles::messageType:
            return messageAtIndex->getMessageType();

        case MessageRoles::blocked:
            return mBlockedUsers.contains( messageAtIndex->getAuthorId() );

        case MessageRoles::id:
            return messageAtIndex->getId();

        case   MessageRoles::replyMessage: {
                QList<QSharedPointer<RocketChatAttachment> > attachments = messageAtIndex->getAttachments();
Armin Felder's avatar
Armin Felder committed
                if ( attachments.size() ) {
                    QSharedPointer<RocketChatAttachment> first = attachments.first();
                    QSharedPointer<RocketChatReplyMessage> msg =  qSharedPointerCast<RocketChatReplyMessage>( first );
                    return msg->getMessageString();
                }
            }
            break;

        case MessageRoles::replyAutor: {
                QList<QSharedPointer<RocketChatAttachment> > attachments = messageAtIndex->getAttachments();

                if ( attachments.size() ) {
                    QSharedPointer<RocketChatAttachment> first = attachments.first();
                    QSharedPointer<RocketChatReplyMessage> msg =  qSharedPointerCast<RocketChatReplyMessage>( first );
                    return msg->getAuthor();
                }
            }
            break;

        case MessageRoles::replyUrl: {
                QString server = messageAtIndex->getServer();
                auto currentChannel = mChannelMap[current];
                QString type = currentChannel->getType();
                QString name = currentChannel->getName();

                if ( type == "p" ) {
                    type  = "group";
                } else if ( type == "c" ) {
                    type  = "channel";
                } else if ( type == "d" ) {
                    type  = "direct";
                    name = currentChannel->getUsername();
                }

                return server + "/" + type + "/" + name + "?msg=" + messageAtIndex->getId();
            }

        case MessageRoles::replyDate:
            //TODO: implement or remove!
            break;
Armin Felder's avatar
Armin Felder committed

Armin Felder's avatar
Armin Felder committed
    qWarning() << "MessagesModel data not found for row";
    return QVariant();
}

QString MessagesModel::getCurrent() const
{
    return current;
}

void MessagesModel::setCurrent( const QString &value )
{
    QMutexLocker( &this->mutex );
Armin Felder's avatar
Armin Felder committed
    current = value;
    beginResetModel();
Armin Felder's avatar
Armin Felder committed
    if ( mChannelMap.contains( value ) ) {
        messagesOfCurrentChannel = mChannelMap[value]->getMessageRepo()->timestampIndex().values().toVector();
        duplicateCheck.clear();

        for ( auto currentMessage : messagesOfCurrentChannel ) {
            duplicateCheck.insert( currentMessage->getId() );
        }
    } else {
        duplicateCheck.clear();
        messagesOfCurrentChannel.clear();
Armin Felder's avatar
Armin Felder committed
        /* QSharedPointer<RocketChatChannel> dummyChannel (new RocketChatChannel());
         dummyChannel->setRoomId(value);
         addChannel(dummyChannel); */
Armin Felder's avatar
Armin Felder committed
    }
Armin Felder's avatar
Armin Felder committed
    endResetModel();
    emit countChanged();
}

int MessagesModel::rowCount( const QModelIndex &parent ) const
{
    Q_UNUSED( parent );
    qDebug() << "number of messages in model" << messagesOfCurrentChannel.count();

    int count = 0;

    if ( messagesOfCurrentChannel.isEmpty() ) {
        return 0;
    }

    count = messagesOfCurrentChannel.count();

    return count;
}

Armin Felder's avatar
Armin Felder committed
int MessagesModel::getPositionOfMessage( const QString &pId )
Armin Felder's avatar
Armin Felder committed
{
    int pos = -1;
Armin Felder's avatar
Armin Felder committed

    for ( int i = 0; i < messagesOfCurrentChannel.size(); i++ ) {
        auto element = messagesOfCurrentChannel.at( i );

        if ( element->getId() == pId ) {
Armin Felder's avatar
Armin Felder committed
            pos = i;
            break;
        }
    }
Armin Felder's avatar
Armin Felder committed

Armin Felder's avatar
Armin Felder committed
    return pos;
}

bool MessagesModel::addChannel( const QSharedPointer<RocketChatChannel> &channel )
Armin Felder's avatar
Armin Felder committed
{
    QString id = channel->getRoomId();

    if ( mChannelMap.contains( id ) ) {
Armin Felder's avatar
Armin Felder committed
        return false;
    }

    mChannelMap.insert( id, channel );
Armin Felder's avatar
Armin Felder committed
    connect( channel.data(), &RocketChatChannel::messageAdded, this, [ = ]( const QString & id, qint64 timestamp ) {
        Q_UNUSED( id )
        onNewMessage( channel, timestamp );
    } );
Armin Felder's avatar
Armin Felder committed
    return true;
}

void MessagesModel::addBlockedUser( const QString &pUserId )
{
    beginResetModel();
    mBlockedUsers.insert( pUserId );
    endResetModel();
}

Armin Felder's avatar
Armin Felder committed
QHash<int, QByteArray> MessagesModel::roleNames() const
{
    QHash<int, QByteArray> roles;
Armin Felder's avatar
Armin Felder committed
    roles[static_cast<int>( MessageRoles::text )] = QByteArrayLiteral( "msg" );
    roles[static_cast<int>( MessageRoles::author )] = QByteArrayLiteral( "author" );
    roles[static_cast<int>( MessageRoles::authorId )] = QByteArrayLiteral( "authorId" );
    roles[static_cast<int>( MessageRoles::linkurl )] = QByteArrayLiteral( "linkurl" );
    roles[static_cast<int>( MessageRoles::type )] = QByteArrayLiteral( "type" );
    roles[static_cast<int>( MessageRoles::date )] = QByteArrayLiteral( "date" );
    roles[static_cast<int>( MessageRoles::time )] = QByteArrayLiteral( "time" );
    roles[static_cast<int>( MessageRoles::ownMessage )] = QByteArrayLiteral( "ownMessage" );
    roles[static_cast<int>( MessageRoles::height )] = QByteArrayLiteral( "height" );
    roles[static_cast<int>( MessageRoles::width )] = QByteArrayLiteral( "width" );
    roles[static_cast<int>( MessageRoles::formattedDate )] = QByteArrayLiteral( "formattedDate" );
    roles[static_cast<int>( MessageRoles::formattedTime )] = QByteArrayLiteral( "formattedTime" );
    roles[static_cast<int>( MessageRoles::messageType )] = QByteArrayLiteral( "messageType" );
    roles[static_cast<int>( MessageRoles::blocked )] = QByteArrayLiteral( "blocked" );
    roles[static_cast<int>( MessageRoles::id )] = QByteArrayLiteral( "id" );
    roles[static_cast<int>( MessageRoles::replyMessage )] = QByteArrayLiteral( "replyMessage" );
    roles[static_cast<int>( MessageRoles::replyAutor )] = QByteArrayLiteral( "replyAutor" );
    roles[static_cast<int>( MessageRoles::replyDate )] = QByteArrayLiteral( "replyDate" );
    roles[static_cast<int>( MessageRoles::replyUrl )] = QByteArrayLiteral( "replyUrl" );
Armin Felder's avatar
Armin Felder committed
    return roles;
}

void MessagesModel::onNewMessage( const QSharedPointer<RocketChatChannel> &channel, qint64 timestamp )
Armin Felder's avatar
Armin Felder committed
{
    QMutexLocker( &this->mutex );

    if ( timestamp == 0 ) {
        setCurrent( current );
Armin Felder's avatar
Armin Felder committed
    }
Armin Felder's avatar
Armin Felder committed
    if ( channel->getRoomId() == current ) {
        auto message = channel->getMessageRepo()->timestampIndex()[timestamp];
Armin Felder's avatar
Armin Felder committed
            return;
        }

        int row = messagesOfCurrentChannel.findPosition( message );

Armin Felder's avatar
Armin Felder committed
        if ( !duplicateCheck.contains( message->getId() ) ) {
            beginInsertRows( QModelIndex(), row, row );
            messagesOfCurrentChannel.insert( row, message );
            mInsertCount++;
            endInsertRows();
            duplicateCheck.insert( message->getId() );
        }

        if ( !buffered ) {
            mInsertCount = 0;
            emit countChanged();
        }
    }
}

void MessagesModel::onBeginInsertList( const QString &pChannelId )
Armin Felder's avatar
Armin Felder committed
{
    if ( pChannelId == current ) {
        buffered = true;
        mInsertCount = 0;
    }
}

void MessagesModel::onEndInsertList( const QString &pChannelId )
Armin Felder's avatar
Armin Felder committed
{
    if ( pChannelId == current ) {
        buffered = false;

        if ( mInsertCount ) {
            mInsertCount = 0;
            emit countChanged();
        }
    }
}

void MessagesModel::addChannelSlot( const QSharedPointer<RocketChatChannel> &channel )
Armin Felder's avatar
Armin Felder committed
{
    addChannel( channel );
Armin Felder's avatar
Armin Felder committed
}