File indexing completed on 2024-12-22 04:46:04

0001 /*
0002    SPDX-FileCopyrightText: 2022-2024 Laurent Montel <montel@kde.org>
0003 
0004    SPDX-License-Identifier: LGPL-2.0-or-later
0005 */
0006 
0007 #include "messagelistlayoutbase.h"
0008 #include "model/messagesmodel.h"
0009 #include "rocketchataccount.h"
0010 #include "room/delegate/messagelistdelegate.h"
0011 
0012 #include "room/delegate/messageattachmentdelegatehelperbase.h"
0013 #include "room/delegate/messageblockdelegatehelperbase.h"
0014 #include "room/delegate/messagedelegatehelperreactions.h"
0015 #include "room/delegate/messagedelegatehelpertext.h"
0016 #include "room/delegate/messagedelegatehelperurlpreview.h"
0017 #include "room/delegate/messagelistdelegate.h"
0018 
0019 MessageListLayoutBase::MessageListLayoutBase(MessageListDelegate *delegate)
0020     : mDelegate(delegate)
0021 {
0022 }
0023 
0024 MessageListLayoutBase::~MessageListLayoutBase() = default;
0025 
0026 RocketChatAccount *MessageListLayoutBase::rocketChatAccount() const
0027 {
0028     return mRocketChatAccount;
0029 }
0030 
0031 void MessageListLayoutBase::setRocketChatAccount(RocketChatAccount *newRocketChatAccount)
0032 {
0033     mRocketChatAccount = newRocketChatAccount;
0034 }
0035 
0036 bool MessageListLayoutBase::sameSenderAsPreviousMessage(const QModelIndex &index, const Message *message) const
0037 {
0038     if (index.row() < 1) {
0039         return false;
0040     }
0041 
0042     const auto previousIndex = index.siblingAtRow(index.row() - 1);
0043     const auto previousMessage = previousIndex.data(MessagesModel::MessagePointer).value<Message *>();
0044     Q_ASSERT(previousMessage);
0045 
0046     const int diffDate = mRocketChatAccount ? mRocketChatAccount->ruqolaServerConfig()->messageGroupingPeriod() * 1000 : 0;
0047     if ((message->userId() == previousMessage->userId()) && (message->threadMessageId() == previousMessage->threadMessageId())
0048         && (message->timeStamp() <= (previousMessage->timeStamp() + diffDate)))
0049         return true;
0050     return false;
0051 }
0052 
0053 QString MessageListLayoutBase::senderText(const Message *message) const
0054 {
0055     if (mRocketChatAccount) {
0056         QString displayName;
0057         if (mRocketChatAccount->useRealName() && !message->name().isEmpty()) {
0058             displayName = message->name();
0059         } else {
0060             if (!message->alias().isEmpty()) {
0061                 displayName = message->alias();
0062             } else {
0063                 displayName = message->username();
0064             }
0065         }
0066         return QLatin1Char('@') + displayName;
0067     } else {
0068         return QLatin1Char('@') + message->username();
0069     }
0070 }
0071 
0072 void MessageListLayoutBase::generateSenderInfo(Layout &layout, const Message *message, const QStyleOptionViewItem &option, const QModelIndex &index) const
0073 {
0074     layout.senderText = senderText(message);
0075     layout.senderFont = option.font;
0076     layout.senderFont.setBold(true);
0077     layout.sameSenderAsPreviousMessage = sameSenderAsPreviousMessage(index, message);
0078 }
0079 
0080 void MessageListLayoutBase::generateAttachmentBlockAndUrlPreviewLayout(MessageListDelegate *delegate,
0081                                                                        Layout &layout,
0082                                                                        const Message *message,
0083                                                                        int attachmentsY,
0084                                                                        int textLeft,
0085                                                                        int maxWidth,
0086                                                                        const QStyleOptionViewItem &option,
0087                                                                        const QModelIndex &index) const
0088 {
0089     if (message->attachments().isEmpty() && message->blocks().isEmpty() && message->urls().isEmpty()) {
0090         layout.reactionsY = attachmentsY;
0091     } else {
0092         int topAttachment = attachmentsY;
0093         if (!message->attachments().isEmpty()) {
0094             const auto attachments = message->attachments();
0095             QSize attachmentsSize;
0096             // TODO add spacing between attachment
0097             for (const MessageAttachment &msgAttach : attachments) {
0098                 const MessageAttachmentDelegateHelperBase *helper = delegate->attachmentsHelper(msgAttach);
0099                 if (attachmentsSize.isEmpty()) {
0100                     attachmentsSize = helper ? helper->sizeHint(msgAttach, index, maxWidth, option) : QSize(0, 0);
0101                     layout.attachmentsRectList.append(QRect(layout.senderRect.x(), topAttachment, attachmentsSize.width(), attachmentsSize.height()));
0102                     topAttachment += attachmentsSize.height();
0103                 } else {
0104                     const QSize attSize = helper ? helper->sizeHint(msgAttach, index, maxWidth, option) : QSize(0, 0);
0105                     layout.attachmentsRectList.append(QRect(layout.senderRect.x(), topAttachment, attSize.width(), attSize.height()));
0106                     attachmentsSize = QSize(qMax(attachmentsSize.width(), attSize.width()), attSize.height() + attachmentsSize.height());
0107                     topAttachment += attSize.height();
0108                 }
0109             }
0110             layout.attachmentsRect = QRect(textLeft, attachmentsY, attachmentsSize.width(), attachmentsSize.height());
0111         }
0112         int topBlock = topAttachment;
0113         if (!message->blocks().isEmpty()) {
0114             const auto blocks = message->blocks();
0115             QSize blocksSize;
0116             for (const Block &block : blocks) {
0117                 const MessageBlockDelegateHelperBase *helper = delegate->blocksHelper(block);
0118                 if (blocksSize.isEmpty()) {
0119                     blocksSize = helper ? helper->sizeHint(block, index, maxWidth, option) : QSize(0, 0);
0120                     layout.blocksRectList.append(QRect(layout.senderRect.x(), topBlock, blocksSize.width(), blocksSize.height()));
0121                     topBlock += blocksSize.height();
0122                 } else {
0123                     const QSize blockSize = helper ? helper->sizeHint(block, index, maxWidth, option) : QSize(0, 0);
0124                     layout.blocksRectList.append(QRect(layout.senderRect.x(), topBlock, blockSize.width(), blockSize.height()));
0125                     blocksSize = QSize(qMax(blocksSize.width(), blockSize.width()), blockSize.height() + blocksSize.height());
0126                     topBlock += blockSize.height();
0127                 }
0128             }
0129             // qDebug() << " topBlock " << topBlock;
0130             layout.blocksRect = QRect(textLeft, topBlock, blocksSize.width(), blocksSize.height());
0131         }
0132         if (mRocketChatAccount && mRocketChatAccount->previewEmbed()) {
0133             if (!message->urls().isEmpty()) {
0134                 const auto urls = message->urls();
0135                 QSize urlsPreviewSize;
0136                 int topUrlPreview = topBlock;
0137                 for (const MessageUrl &url : urls) {
0138                     if (url.hasPreviewUrl()) {
0139                         const MessageDelegateHelperUrlPreview *helperUrlPreview = delegate->helperUrlPreview();
0140                         if (urlsPreviewSize.isEmpty()) {
0141                             urlsPreviewSize = helperUrlPreview->sizeHint(url, index, maxWidth, option);
0142                             layout.messageUrlsRectList.append(QRect(layout.senderRect.x(), topUrlPreview, urlsPreviewSize.width(), urlsPreviewSize.height()));
0143                             topUrlPreview += urlsPreviewSize.height();
0144                         } else {
0145                             const QSize urlPreviewSize = helperUrlPreview->sizeHint(url, index, maxWidth, option);
0146                             layout.messageUrlsRectList.append(QRect(layout.senderRect.x(), topUrlPreview, urlPreviewSize.width(), urlPreviewSize.height()));
0147                             urlsPreviewSize = QSize(qMax(urlsPreviewSize.width(), urlPreviewSize.width()), urlPreviewSize.height() + urlsPreviewSize.height());
0148                             topUrlPreview += urlPreviewSize.height();
0149                         }
0150                     } else {
0151                         layout.messageUrlsRectList.append(QRect{});
0152                     }
0153                 }
0154                 // qDebug() << " topUrlPreview " << topUrlPreview;
0155                 layout.messageUrlsRect = QRect(textLeft, topUrlPreview, urlsPreviewSize.width(), urlsPreviewSize.height());
0156             }
0157         }
0158         layout.reactionsY = attachmentsY + layout.attachmentsRect.height() + layout.blocksRect.height() + layout.messageUrlsRect.height();
0159     }
0160 }