File indexing completed on 2024-05-12 16:27:33

0001 /*
0002    SPDX-FileCopyrightText: 2020-2024 Laurent Montel <montel@kde.org>
0003 
0004    SPDX-License-Identifier: LGPL-2.0-or-later
0005 */
0006 
0007 #include "messagelinewidget.h"
0008 #if QT_VERSION > QT_VERSION_CHECK(6, 0, 0)
0009 #include "dialogs/createsoundmessagewizard.h"
0010 #include "dialogs/createvideomessagewizard.h"
0011 #endif
0012 #include "messagemaximumsizedialog/messagemaximumsizedialog.h"
0013 #include "messagetextedit.h"
0014 #include "misc/emoticonmenuwidget.h"
0015 #include "ownuser/ownuserpreferences.h"
0016 #include "rocketchataccount.h"
0017 #include "ruqolaglobalconfig.h"
0018 #include "ruqolaserverconfig.h"
0019 #include "ruqolawidgets_debug.h"
0020 
0021 #include <KLocalizedString>
0022 #include <KMessageBox>
0023 #include <QMimeDatabase>
0024 
0025 #include <KIO/Global>
0026 #include <QClipboard>
0027 #include <QDir>
0028 #include <QGuiApplication>
0029 #include <QHBoxLayout>
0030 #include <QImageWriter>
0031 #include <QMenu>
0032 #include <QMimeData>
0033 #include <QScreen>
0034 #include <QTemporaryFile>
0035 #include <QToolButton>
0036 #include <QWidgetAction>
0037 
0038 MessageLineWidget::MessageLineWidget(QWidget *parent)
0039     : QWidget(parent)
0040     , mMessageTextEdit(new MessageTextEdit(this))
0041     , mSendFileButton(new QToolButton(this))
0042     , mEmoticonButton(new QToolButton(this))
0043     , mSendMessageButton(new QToolButton(this))
0044     , mVideoMessageButton(new QToolButton(this))
0045     , mSoundMessageButton(new QToolButton(this))
0046 {
0047     auto mainLayout = new QHBoxLayout(this);
0048     mainLayout->setObjectName(QStringLiteral("mainLayout"));
0049     mainLayout->setContentsMargins({});
0050     mainLayout->setSpacing(0);
0051 
0052     mMessageTextEdit->setObjectName(QStringLiteral("mMessageTextEdit"));
0053     mainLayout->addWidget(mMessageTextEdit);
0054     connect(mMessageTextEdit, &MessageTextEdit::sendMessage, this, &MessageLineWidget::slotSendMessage);
0055     connect(mMessageTextEdit, &MessageTextEdit::keyPressed, this, &MessageLineWidget::keyPressedInLineEdit);
0056     connect(mMessageTextEdit, &MessageTextEdit::textEditing, this, &MessageLineWidget::slotTextEditing);
0057     connect(mMessageTextEdit, &MessageTextEdit::textClicked, this, &MessageLineWidget::textEditClicked);
0058 
0059     mSendFileButton->setAutoRaise(true);
0060     mSendFileButton->setObjectName(QStringLiteral("mSendFileButton"));
0061     mainLayout->addWidget(mSendFileButton);
0062 #ifndef QT_NO_ACCESSIBILITY
0063     mSendFileButton->setAccessibleName(i18n("Attach File"));
0064 #endif
0065 
0066     mSendFileButton->setIcon(QIcon::fromTheme(QStringLiteral("document-send-symbolic")));
0067     connect(mSendFileButton, &QToolButton::clicked, this, &MessageLineWidget::slotSendFile);
0068 
0069     mVideoMessageButton->setAutoRaise(true);
0070     mVideoMessageButton->setObjectName(QStringLiteral("mVideoMessageButton"));
0071 #ifndef QT_NO_ACCESSIBILITY
0072     mVideoMessageButton->setAccessibleName(i18n("Video Message"));
0073 #endif
0074 
0075     mainLayout->addWidget(mVideoMessageButton);
0076     mVideoMessageButton->setIcon(QIcon::fromTheme(QStringLiteral("camera-video")));
0077     connect(mVideoMessageButton, &QToolButton::clicked, this, &MessageLineWidget::slotSendVideoMessage);
0078 
0079     mSoundMessageButton->setAutoRaise(true);
0080     mSoundMessageButton->setObjectName(QStringLiteral("mSoundMessageButton"));
0081 #ifndef QT_NO_ACCESSIBILITY
0082     mSoundMessageButton->setAccessibleName(i18n("Sound Message"));
0083 #endif
0084 
0085     mainLayout->addWidget(mSoundMessageButton);
0086     mSoundMessageButton->setIcon(QIcon::fromTheme(QStringLiteral("audio-input-microphone")));
0087     connect(mSoundMessageButton, &QToolButton::clicked, this, &MessageLineWidget::slotSendSoundMessage);
0088 
0089     mEmoticonButton->setAutoRaise(true);
0090     mEmoticonButton->setObjectName(QStringLiteral("mEmoticonButton"));
0091     mEmoticonButton->setIcon(QIcon::fromTheme(QStringLiteral("smiley-add")));
0092     mEmoticonButton->setPopupMode(QToolButton::InstantPopup);
0093 #ifndef QT_NO_ACCESSIBILITY
0094     mEmoticonButton->setAccessibleName(i18n("Add Emoticon"));
0095 #endif
0096     mainLayout->addWidget(mEmoticonButton);
0097 
0098     mSendMessageButton->setAutoRaise(true);
0099     mSendMessageButton->setObjectName(QStringLiteral("mSendMessageButton"));
0100     mSendMessageButton->setIcon(QIcon::fromTheme(QStringLiteral("mail-sent")));
0101 #ifndef QT_NO_ACCESSIBILITY
0102     mSendMessageButton->setAccessibleName(i18n("Send Message"));
0103 #endif
0104     mainLayout->addWidget(mSendMessageButton);
0105     mSendMessageButton->setEnabled(false);
0106     connect(mSendMessageButton, &QToolButton::clicked, this, [this]() {
0107         slotSendMessage(mMessageTextEdit->text());
0108         mMessageTextEdit->clear();
0109     });
0110 
0111     auto emoticonMenu = new QMenu(this);
0112     auto action = new QWidgetAction(emoticonMenu);
0113     mEmoticonMenuWidget = new EmoticonMenuWidget(this);
0114     action->setDefaultWidget(mEmoticonMenuWidget);
0115     emoticonMenu->addAction(action);
0116     mEmoticonButton->setMenu(emoticonMenu);
0117     connect(emoticonMenu, &QMenu::aboutToShow, mEmoticonMenuWidget, &EmoticonMenuWidget::forceLineEditFocus);
0118     connect(mEmoticonMenuWidget, &EmoticonMenuWidget::insertEmojiIdentifier, mMessageTextEdit, &MessageTextEdit::insertEmoji);
0119     connect(mMessageTextEdit, &MessageTextEdit::handleMimeData, this, &MessageLineWidget::handleMimeData);
0120 
0121     setFocusProxy(mMessageTextEdit);
0122 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
0123     mVideoMessageButton->setVisible(false);
0124     mSoundMessageButton->setVisible(false);
0125 #endif
0126 }
0127 
0128 MessageLineWidget::~MessageLineWidget() = default;
0129 
0130 void MessageLineWidget::slotSendMessage(const QString &msg)
0131 {
0132     if (!msg.isEmpty()) {
0133         if (mMessageIdBeingEdited.isEmpty() && mQuotePermalink.isEmpty()) {
0134             if (msg.startsWith(QLatin1Char('/'))) {
0135                 // a command ?
0136                 if (mCurrentRocketChatAccount->runCommand(msg, roomId(), mThreadMessageId)) {
0137                     setMode(MessageLineWidget::EditingMode::NewMessage);
0138                     return;
0139                 }
0140             }
0141             if (msg.size() > mCurrentRocketChatAccount->messageMaximumAllowedSize()) {
0142                 if (mCurrentRocketChatAccount->messageAllowConvertLongMessagesToAttachment()) {
0143                     if (KMessageBox::ButtonCode::PrimaryAction
0144                         == KMessageBox::questionTwoActions(this,
0145                                                            i18n("Do you want to convert this big text as attachment?"),
0146                                                            i18nc("@title:window", "Message Too Big"),
0147                                                            KStandardGuiItem::ok(),
0148                                                            KStandardGuiItem::cancel())) {
0149                         QPointer<MessageMaximumSizeDialog> dlg = new MessageMaximumSizeDialog(this);
0150                         if (dlg->exec()) {
0151                             QTemporaryFile tempFile(QDir::tempPath() + QStringLiteral("/XXXXXX.txt"));
0152                             tempFile.setAutoRemove(false);
0153                             if (tempFile.open()) {
0154                                 QTextStream stream(&tempFile);
0155 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
0156                                 stream.setCodec("UTF-8");
0157 #endif
0158                                 stream << msg;
0159                                 tempFile.close();
0160 
0161                                 QFile f(tempFile.fileName());
0162                                 if (!f.rename(dlg->fileName())) {
0163                                     qCWarning(RUQOLAWIDGETS_LOG) << "Rename file failed" << tempFile.fileName() << " dlg->fileName()" << dlg->fileName();
0164                                 }
0165                                 UploadFileDialog::UploadFileInfo uploadFileInfo;
0166                                 uploadFileInfo.description = dlg->description();
0167                                 uploadFileInfo.fileUrl = QUrl::fromLocalFile(f.fileName());
0168                                 uploadFileInfo.deleteTemporaryFile = true;
0169                                 sendFile(uploadFileInfo);
0170                             }
0171                         }
0172                         delete dlg;
0173                         // We need to send as file here.
0174                         return;
0175                     } else {
0176                         return;
0177                     }
0178                 } else {
0179                     return;
0180                 }
0181             }
0182             if (mThreadMessageId.isEmpty()) {
0183                 mCurrentRocketChatAccount->sendMessage(roomId(), msg);
0184             } else {
0185                 mCurrentRocketChatAccount->replyOnThread(roomId(), mThreadMessageId, msg);
0186                 if (!mReplyInThreadDialogBox) {
0187                     setThreadMessageId({});
0188                 }
0189             }
0190         } else if (!mMessageIdBeingEdited.isEmpty()) {
0191             // TODO check message size
0192             mCurrentRocketChatAccount->updateMessage(roomId(), mMessageIdBeingEdited, msg);
0193             clearMessageIdBeingEdited();
0194         } else if (!mQuotePermalink.isEmpty()) {
0195             const QString newMessage = QStringLiteral("[ ](%1) %2").arg(mQuotePermalink, msg);
0196             if (mThreadMessageId.isEmpty()) {
0197                 mCurrentRocketChatAccount->sendMessage(roomId(), newMessage);
0198             } else {
0199                 mCurrentRocketChatAccount->replyOnThread(roomId(), mThreadMessageId, newMessage);
0200                 if (!mReplyInThreadDialogBox) {
0201                     setThreadMessageId({});
0202                 }
0203             }
0204             setQuoteMessage({}, {});
0205             clearMessageIdBeingEdited();
0206         }
0207         setMode(MessageLineWidget::EditingMode::NewMessage);
0208     }
0209 }
0210 
0211 void MessageLineWidget::sendFile(const UploadFileDialog::UploadFileInfo &uploadFileInfo)
0212 {
0213     RocketChatRestApi::UploadFileJob::UploadFileInfo info;
0214     info.description = uploadFileInfo.description;
0215     info.messageText = QString();
0216     info.filenameUrl = uploadFileInfo.fileUrl;
0217     info.roomId = roomId();
0218     info.threadMessageId = mThreadMessageId;
0219     info.fileName = uploadFileInfo.fileName;
0220     info.deleteTemporaryFile = uploadFileInfo.deleteTemporaryFile;
0221 
0222     Q_EMIT createUploadJob(info);
0223 }
0224 
0225 void MessageLineWidget::setQuoteMessage(const QString &permalink, const QString &text)
0226 {
0227     clearMessageIdBeingEdited();
0228     mQuotePermalink = permalink;
0229     mQuoteText = text;
0230     Q_EMIT quoteMessageChanged(mQuotePermalink, text);
0231 }
0232 
0233 void MessageLineWidget::clearEditingMode()
0234 {
0235     // Remove old mark as editing
0236     MessagesModel *model = messageModel();
0237     const QModelIndex index = model->indexForMessage(mMessageIdBeingEdited);
0238     if (index.isValid()) {
0239         model->setData(index, false, MessagesModel::MessageInEditMode);
0240     }
0241 }
0242 
0243 QString MessageLineWidget::quoteText() const
0244 {
0245     return mQuoteText;
0246 }
0247 
0248 QString MessageLineWidget::quotePermalink() const
0249 {
0250     return mQuotePermalink;
0251 }
0252 
0253 void MessageLineWidget::clearMessageIdBeingEdited()
0254 {
0255     MessagesModel *model = messageModel();
0256     if (!mMessageIdBeingEdited.isEmpty()) {
0257         const QModelIndex index = model->indexForMessage(mMessageIdBeingEdited);
0258         if (index.isValid()) {
0259             model->setData(index, false, MessagesModel::MessageInEditMode);
0260         }
0261         mMessageIdBeingEdited.clear();
0262     }
0263     mQuotePermalink.clear();
0264     mQuoteText.clear();
0265     setText(QString());
0266     setMode(MessageLineWidget::EditingMode::NewMessage);
0267 }
0268 
0269 void MessageLineWidget::setEditMessage(const QString &messageId, const QString &text)
0270 {
0271     // Remove old mark as editing
0272     clearEditingMode();
0273     mMessageIdBeingEdited = messageId;
0274     if (!mMessageIdBeingEdited.isEmpty()) {
0275         MessagesModel *model = messageModel();
0276         const QModelIndex index = model->indexForMessage(mMessageIdBeingEdited);
0277         if (index.isValid()) {
0278             model->setData(index, true, MessagesModel::MessageInEditMode);
0279         }
0280     }
0281     setMode(messageId.isEmpty() ? MessageLineWidget::EditingMode::NewMessage : MessageLineWidget::EditingMode::EditMessage);
0282     setText(text);
0283     setFocus();
0284 }
0285 
0286 void MessageLineWidget::slotPublicSettingChanged()
0287 {
0288     mSendFileButton->setVisible(mCurrentRocketChatAccount->uploadFileEnabled());
0289 #if QT_VERSION > QT_VERSION_CHECK(6, 0, 0)
0290     mSoundMessageButton->setVisible(mCurrentRocketChatAccount->audioRecorderEnabled());
0291     mVideoMessageButton->setVisible(mCurrentRocketChatAccount->videoRecorderEnabled());
0292 #endif
0293 }
0294 
0295 void MessageLineWidget::slotOwnUserPreferencesChanged()
0296 {
0297     mEmoticonButton->setVisible(mCurrentRocketChatAccount->ownUserPreferences().useEmojis());
0298 }
0299 
0300 void MessageLineWidget::slotPrivateSettingsChanged()
0301 {
0302 #if QT_VERSION > QT_VERSION_CHECK(6, 0, 0)
0303     mSoundMessageButton->setVisible(mCurrentRocketChatAccount->audioRecorderEnabled());
0304     mVideoMessageButton->setVisible(mCurrentRocketChatAccount->videoRecorderEnabled());
0305 #endif
0306 }
0307 
0308 void MessageLineWidget::setCurrentRocketChatAccount(RocketChatAccount *account, bool threadMessageDialog)
0309 {
0310     if (mCurrentRocketChatAccount) {
0311         disconnect(mCurrentRocketChatAccount, &RocketChatAccount::privateSettingsChanged, this, &MessageLineWidget::slotPrivateSettingsChanged);
0312     }
0313     mCurrentRocketChatAccount = account;
0314     connect(mCurrentRocketChatAccount, &RocketChatAccount::privateSettingsChanged, this, &MessageLineWidget::slotPrivateSettingsChanged);
0315     mMessageTextEdit->setCurrentRocketChatAccount(account, threadMessageDialog);
0316     mEmoticonMenuWidget->setCurrentRocketChatAccount(account);
0317 }
0318 
0319 void MessageLineWidget::setText(const QString &text)
0320 {
0321     mMessageTextEdit->changeText(text, text.length());
0322 }
0323 
0324 QString MessageLineWidget::text() const
0325 {
0326     return mMessageTextEdit->text();
0327 }
0328 
0329 MessageTextEdit *MessageLineWidget::messageTextEdit() const
0330 {
0331     return mMessageTextEdit;
0332 }
0333 
0334 void MessageLineWidget::slotSendSoundMessage()
0335 {
0336 #if QT_VERSION > QT_VERSION_CHECK(6, 0, 0)
0337     QPointer<CreateSoundMessageWizard> dlg = new CreateSoundMessageWizard(mCurrentRocketChatAccount, this);
0338     if (dlg->exec()) {
0339         const CreateSoundMessageWizard::CreateSoundMessageInfo info = dlg->soundMessageInfo();
0340         UploadFileDialog::UploadFileInfo result;
0341         result.description = info.mDescription;
0342         result.fileUrl = info.mFileUrl;
0343         result.fileName = info.mFileName;
0344         result.deleteTemporaryFile = true;
0345         sendFile(result);
0346     }
0347     delete dlg;
0348 #endif
0349 }
0350 
0351 void MessageLineWidget::slotSendVideoMessage()
0352 {
0353 #if QT_VERSION > QT_VERSION_CHECK(6, 0, 0)
0354     QPointer<CreateVideoMessageWizard> dlg = new CreateVideoMessageWizard(mCurrentRocketChatAccount, this);
0355     if (dlg->exec()) {
0356         const CreateVideoMessageWizard::CreateVideoMessageInfo info = dlg->videoMessageInfo();
0357         if (info.isValid()) {
0358             UploadFileDialog::UploadFileInfo result;
0359             result.description = info.mDescription;
0360             result.fileUrl = info.mFileUrl;
0361             result.deleteTemporaryFile = true;
0362             result.fileName = info.mFileName;
0363             sendFile(result);
0364         }
0365     }
0366     delete dlg;
0367 #endif
0368 }
0369 
0370 void MessageLineWidget::slotSendFile()
0371 {
0372     QPointer<UploadFileDialog> dlg = new UploadFileDialog(this);
0373     QStringList whiteList = mCurrentRocketChatAccount->ruqolaServerConfig()->mediaWhiteList();
0374     const QStringList blackList = mCurrentRocketChatAccount->ruqolaServerConfig()->mediaBlackList();
0375     for (const auto &mediaType : blackList) {
0376         if (whiteList.contains(mediaType)) {
0377             whiteList.removeAll(mediaType);
0378         }
0379     }
0380     // Disable for the moment dlg->setAuthorizedMediaTypes(whiteList);
0381     // qDebug() << " whiteList " << whiteList << " blackList " << blackList;
0382     if (dlg->exec()) {
0383         const UploadFileDialog::UploadFileInfo result = dlg->fileInfo();
0384         if (result.fileUrl.isLocalFile()) {
0385             const QFileInfo info(result.fileUrl.toLocalFile());
0386             const qint64 maximumFileSize = mCurrentRocketChatAccount->ruqolaServerConfig()->fileMaxFileSize();
0387             if (info.size() > maximumFileSize) {
0388                 KMessageBox::error(this, i18n("File selected is too big (Maximum size %1)", KIO::convertSize(maximumFileSize)), i18n("File upload"));
0389                 delete dlg;
0390                 return;
0391             }
0392             auto invalidMedia = [this, dlg]() {
0393                 KMessageBox::error(this, i18n("Server doesn't authorized this file (invalid mimetype)"));
0394                 delete dlg;
0395             };
0396 
0397             QMimeDatabase mimeDatabase;
0398             const QString mimeTypeName = mimeDatabase.mimeTypeForFile(result.fileUrl.toLocalFile()).name();
0399 #if 0 // Disable for the moment "image/*" is not a valid MIME type for example
0400             qDebug() << " mimeTypeName" << mimeTypeName << " whiteList " << whiteList;
0401             if (!whiteList.isEmpty()) {
0402                 if (!whiteList.contains(mimeTypeName)) {
0403                     invalidMedia();
0404                     return;
0405                 }
0406             }
0407 #endif
0408             if (blackList.contains(mimeTypeName)) {
0409                 invalidMedia();
0410                 return;
0411             }
0412         }
0413 
0414         sendFile(result);
0415     }
0416     delete dlg;
0417 }
0418 
0419 QString MessageLineWidget::threadMessageId() const
0420 {
0421     return mThreadMessageId;
0422 }
0423 
0424 void MessageLineWidget::setThreadMessageId(const QString &threadMessageId, const QString &text, bool replyInDialogBox)
0425 {
0426     mReplyInThreadDialogBox = replyInDialogBox;
0427 
0428     if (mThreadMessageId == threadMessageId) {
0429         return;
0430     }
0431 
0432     mThreadMessageId = threadMessageId;
0433     Q_EMIT threadMessageIdChanged(mThreadMessageId, text);
0434 }
0435 
0436 MessageLineWidget::EditingMode MessageLineWidget::mode() const
0437 {
0438     return mMode;
0439 }
0440 
0441 void MessageLineWidget::setMode(EditingMode mode)
0442 {
0443     if (mMode != mode) {
0444         mMode = mode;
0445         switch (mMode) {
0446         case EditingMode::NewMessage:
0447             mSendMessageButton->setIcon(QIcon::fromTheme(QStringLiteral("mail-sent")));
0448             break;
0449         case EditingMode::EditMessage:
0450             mSendMessageButton->setIcon(QIcon::fromTheme(QStringLiteral("edit-symbolic")));
0451             break;
0452         }
0453     }
0454 }
0455 
0456 void MessageLineWidget::slotTextEditing(bool clearNotification)
0457 {
0458     mSendMessageButton->setEnabled(!clearNotification);
0459     mCurrentRocketChatAccount->textEditing(roomId(), clearNotification);
0460 }
0461 
0462 QString MessageLineWidget::messageIdBeingEdited() const
0463 {
0464     return mMessageIdBeingEdited;
0465 }
0466 
0467 void MessageLineWidget::setMessageIdBeingEdited(const QString &messageIdBeingEdited)
0468 {
0469     mMessageIdBeingEdited = messageIdBeingEdited;
0470 }
0471 
0472 QString MessageLineWidget::roomId() const
0473 {
0474     return mMessageTextEdit->roomId();
0475 }
0476 
0477 void MessageLineWidget::setRoomId(const QString &roomId)
0478 {
0479     mMessageTextEdit->setRoomId(roomId);
0480 }
0481 
0482 bool MessageLineWidget::handleMimeData(const QMimeData *mimeData)
0483 {
0484     auto uploadFile = [this](const QUrl &url, const QPixmap &pix) {
0485         QPointer<UploadFileDialog> dlg = new UploadFileDialog(this);
0486         dlg->setFileUrl(url);
0487         dlg->setPixmap(pix);
0488         if (dlg->exec()) {
0489             const UploadFileDialog::UploadFileInfo uploadFileInfo = dlg->fileInfo();
0490             sendFile(uploadFileInfo);
0491         }
0492         delete dlg;
0493     };
0494     if (mimeData->hasUrls()) {
0495         const QList<QUrl> urls = mimeData->urls();
0496         for (const QUrl &url : urls) {
0497             if (url.isLocalFile()) {
0498                 uploadFile(url, QPixmap());
0499             }
0500         }
0501         return true;
0502     } else if (mimeData->hasImage()) {
0503         QTemporaryFile tempFile(QDir::tempPath() + QLatin1String("/XXXXXX.png"));
0504         if (tempFile.open()) {
0505             const auto image = mimeData->imageData().value<QImage>();
0506             QImageWriter writer(&tempFile, "PNG");
0507             if (writer.write(image)) {
0508                 const QUrl url = QUrl::fromLocalFile(tempFile.fileName());
0509                 tempFile.close();
0510                 const QSize pixmapAvatarSize = QSize(120, 120) * screen()->devicePixelRatio();
0511                 uploadFile(url, QPixmap::fromImage(image).scaled(pixmapAvatarSize, Qt::KeepAspectRatio));
0512                 return true;
0513             }
0514         }
0515     }
0516     return false;
0517 }
0518 
0519 MessagesModel *MessageLineWidget::messageModel() const
0520 {
0521     MessagesModel *model =
0522         mThreadMessageId.isEmpty() ? mCurrentRocketChatAccount->messageModelForRoom(roomId()) : mCurrentRocketChatAccount->threadMessageModel();
0523     Q_ASSERT(model);
0524     return model;
0525 }
0526 
0527 void MessageLineWidget::keyPressedInLineEdit(QKeyEvent *ev)
0528 {
0529     const int key = ev->key();
0530     if (key == Qt::Key_Escape) {
0531         if (!mMessageIdBeingEdited.isEmpty() || !mQuotePermalink.isEmpty()) {
0532             clearMessageIdBeingEdited();
0533             ev->accept();
0534         } else {
0535             Q_EMIT keyPressed(ev);
0536         }
0537     } else if (ev->matches(QKeySequence::Paste)) {
0538         const QMimeData *mimeData = qApp->clipboard()->mimeData();
0539         if (handleMimeData(mimeData)) {
0540             ev->accept();
0541         }
0542     } else if ((key == Qt::Key_Up || key == Qt::Key_Down) && ev->modifiers() & Qt::AltModifier) {
0543         MessagesModel *model = messageModel();
0544         auto isEditable = [this](const Message &msg) {
0545             return mCurrentRocketChatAccount->isMessageEditable(msg);
0546         };
0547         if (key == Qt::Key_Up) {
0548             const Message &msg = model->findLastMessageBefore(mMessageIdBeingEdited, isEditable);
0549             setEditMessage(msg.messageId(), msg.originalMessageOrAttachmentDescription());
0550         } else {
0551             const Message &msg = model->findNextMessageAfter(mMessageIdBeingEdited, isEditable);
0552             setEditMessage(msg.messageId(), msg.originalMessageOrAttachmentDescription());
0553         }
0554         ev->accept();
0555     } else {
0556         Q_EMIT keyPressed(ev);
0557     }
0558 }
0559 
0560 void MessageLineWidget::textEditClicked()
0561 {
0562     if (RuqolaGlobalConfig::self()->markAsReadOnTextClicked()) {
0563         mCurrentRocketChatAccount->markRoomAsRead(roomId());
0564     }
0565 }
0566 
0567 #include "moc_messagelinewidget.cpp"