2014-11-16 19:58:43 +08:00
|
|
|
|
/*
|
2018-04-13 04:02:28 +08:00
|
|
|
|
Copyright © 2014-2018 by The qTox Project Contributors
|
2015-06-06 09:40:08 +08:00
|
|
|
|
|
2014-11-16 19:58:43 +08:00
|
|
|
|
This file is part of qTox, a Qt-based graphical interface for Tox.
|
|
|
|
|
|
2015-06-06 09:40:08 +08:00
|
|
|
|
qTox is libre software: you can redistribute it and/or modify
|
2014-11-16 19:58:43 +08:00
|
|
|
|
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.
|
2015-06-06 09:40:08 +08:00
|
|
|
|
|
|
|
|
|
qTox is distributed in the hope that it will be useful,
|
2014-11-16 19:58:43 +08:00
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
2015-06-06 09:40:08 +08:00
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
GNU General Public License for more details.
|
2014-11-16 19:58:43 +08:00
|
|
|
|
|
2015-06-06 09:40:08 +08:00
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
|
along with qTox. If not, see <http://www.gnu.org/licenses/>.
|
2014-11-16 19:58:43 +08:00
|
|
|
|
*/
|
|
|
|
|
|
2014-11-12 21:11:25 +08:00
|
|
|
|
#include "chatmessage.h"
|
2015-01-03 22:03:33 +08:00
|
|
|
|
#include "chatlinecontentproxy.h"
|
2017-02-06 23:20:45 +08:00
|
|
|
|
#include "textformatter.h"
|
2015-01-03 22:03:33 +08:00
|
|
|
|
#include "content/filetransferwidget.h"
|
|
|
|
|
#include "content/image.h"
|
2015-01-20 02:04:19 +08:00
|
|
|
|
#include "content/notificationicon.h"
|
2017-02-26 19:52:45 +08:00
|
|
|
|
#include "content/spinner.h"
|
|
|
|
|
#include "content/text.h"
|
|
|
|
|
#include "content/timestamp.h"
|
2018-09-10 19:19:22 +08:00
|
|
|
|
#include "src/widget/style.h"
|
2014-11-12 21:11:25 +08:00
|
|
|
|
|
2016-01-23 18:49:11 +08:00
|
|
|
|
#include <QDebug>
|
2018-10-22 08:01:05 +08:00
|
|
|
|
#include <QCryptographicHash>
|
2016-01-23 18:49:11 +08:00
|
|
|
|
|
2016-12-19 10:26:26 +08:00
|
|
|
|
#include "src/persistence/settings.h"
|
|
|
|
|
#include "src/persistence/smileypack.h"
|
2015-01-03 03:07:45 +08:00
|
|
|
|
|
2015-01-11 05:21:33 +08:00
|
|
|
|
#define NAME_COL_WIDTH 90.0
|
2015-01-05 21:06:14 +08:00
|
|
|
|
#define TIME_COL_WIDTH 90.0
|
2014-11-12 23:45:24 +08:00
|
|
|
|
|
2018-10-22 08:01:05 +08:00
|
|
|
|
|
2015-01-05 01:21:35 +08:00
|
|
|
|
ChatMessage::ChatMessage()
|
2014-11-12 23:45:24 +08:00
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
2017-02-26 19:52:45 +08:00
|
|
|
|
ChatMessage::Ptr ChatMessage::createChatMessage(const QString& sender, const QString& rawMessage,
|
2018-10-23 00:23:41 +08:00
|
|
|
|
MessageType type, bool isMe, const QDateTime& date, bool colorizeName)
|
2015-01-03 22:03:33 +08:00
|
|
|
|
{
|
2015-01-05 01:21:35 +08:00
|
|
|
|
ChatMessage::Ptr msg = ChatMessage::Ptr(new ChatMessage);
|
2015-01-03 22:03:33 +08:00
|
|
|
|
|
2015-02-16 22:22:29 +08:00
|
|
|
|
QString text = rawMessage.toHtmlEscaped();
|
2015-02-15 17:51:54 +08:00
|
|
|
|
QString senderText = sender;
|
|
|
|
|
|
2019-02-20 21:42:53 +08:00
|
|
|
|
const QColor actionColor = Style::getColor(Style::Action);
|
2015-01-04 02:05:38 +08:00
|
|
|
|
|
2017-02-26 19:52:45 +08:00
|
|
|
|
// smileys
|
2015-03-21 02:38:10 +08:00
|
|
|
|
if (Settings::getInstance().getUseEmoticons())
|
2015-01-04 02:05:38 +08:00
|
|
|
|
text = SmileyPack::getInstance().smileyfied(text);
|
|
|
|
|
|
2017-02-26 19:52:45 +08:00
|
|
|
|
// quotes (green text)
|
2017-03-02 02:47:08 +08:00
|
|
|
|
text = detectQuotes(text, type);
|
2018-02-25 12:35:47 +08:00
|
|
|
|
text = highlightURI(text);
|
2015-01-03 22:03:33 +08:00
|
|
|
|
|
2017-02-26 19:52:45 +08:00
|
|
|
|
// text styling
|
2017-02-19 22:48:44 +08:00
|
|
|
|
Settings::StyleType styleType = Settings::getInstance().getStylePreference();
|
2017-02-26 19:52:45 +08:00
|
|
|
|
if (styleType != Settings::StyleType::NONE) {
|
2017-07-08 19:20:37 +08:00
|
|
|
|
text = applyMarkdown(text, styleType == Settings::StyleType::WITH_CHARS);
|
2017-02-06 23:20:45 +08:00
|
|
|
|
}
|
|
|
|
|
|
2016-01-21 18:50:51 +08:00
|
|
|
|
|
2017-02-26 19:52:45 +08:00
|
|
|
|
switch (type) {
|
2016-07-10 19:43:50 +08:00
|
|
|
|
case NORMAL:
|
|
|
|
|
text = wrapDiv(text, "msg");
|
|
|
|
|
break;
|
2015-02-15 17:51:54 +08:00
|
|
|
|
case ACTION:
|
|
|
|
|
senderText = "*";
|
2015-10-02 06:06:06 +08:00
|
|
|
|
text = wrapDiv(QString("%1 %2").arg(sender.toHtmlEscaped(), text), "action");
|
2015-01-03 22:03:33 +08:00
|
|
|
|
msg->setAsAction();
|
2015-02-15 17:51:54 +08:00
|
|
|
|
break;
|
|
|
|
|
case ALERT:
|
|
|
|
|
text = wrapDiv(text, "alert");
|
|
|
|
|
break;
|
2015-01-04 02:06:10 +08:00
|
|
|
|
}
|
2015-01-03 22:03:33 +08:00
|
|
|
|
|
2015-02-15 17:51:54 +08:00
|
|
|
|
// Note: Eliding cannot be enabled for RichText items. (QTBUG-17207)
|
2016-06-29 05:59:21 +08:00
|
|
|
|
QFont baseFont = Settings::getInstance().getChatMessageFont();
|
|
|
|
|
QFont authorFont = baseFont;
|
|
|
|
|
if (isMe)
|
|
|
|
|
authorFont.setBold(true);
|
|
|
|
|
|
2019-02-20 21:42:53 +08:00
|
|
|
|
QColor color = Style::getColor(Style::Black);
|
2018-10-25 08:44:11 +08:00
|
|
|
|
QColor authorColor;
|
2018-10-22 08:01:05 +08:00
|
|
|
|
|
2018-10-23 00:23:41 +08:00
|
|
|
|
if (colorizeName && Settings::getInstance().getEnableGroupChatsColor())
|
2018-10-22 08:01:05 +08:00
|
|
|
|
{
|
2018-10-24 06:17:06 +08:00
|
|
|
|
QByteArray hash = QCryptographicHash::hash((sender.toUtf8()), QCryptographicHash::Sha256);
|
2018-10-22 08:01:05 +08:00
|
|
|
|
quint8 *data = (quint8*)hash.data();
|
|
|
|
|
|
2018-10-25 08:44:11 +08:00
|
|
|
|
authorColor.setHsv(data[0], 255, 196);
|
2018-10-22 08:01:05 +08:00
|
|
|
|
|
|
|
|
|
if (!isMe)
|
2018-10-24 06:17:06 +08:00
|
|
|
|
{
|
2018-10-25 08:44:11 +08:00
|
|
|
|
color = authorColor;
|
2018-10-24 06:17:06 +08:00
|
|
|
|
}
|
2018-10-22 08:01:05 +08:00
|
|
|
|
}
|
|
|
|
|
|
2017-02-26 19:52:45 +08:00
|
|
|
|
msg->addColumn(new Text(senderText, authorFont, true, sender,
|
2018-10-22 08:01:05 +08:00
|
|
|
|
type == ACTION ? actionColor : color),
|
2017-02-26 19:52:45 +08:00
|
|
|
|
ColumnFormat(NAME_COL_WIDTH, ColumnFormat::FixedSize, ColumnFormat::Right));
|
|
|
|
|
msg->addColumn(new Text(text, baseFont, false, ((type == ACTION) && isMe)
|
|
|
|
|
? QString("%1 %2").arg(sender, rawMessage)
|
|
|
|
|
: rawMessage),
|
|
|
|
|
ColumnFormat(1.0, ColumnFormat::VariableSize));
|
2018-09-10 19:19:22 +08:00
|
|
|
|
msg->addColumn(new Spinner(Style::getImagePath("chatArea/spinner.svg"), QSize(16, 16), 360.0 / 1.6),
|
2017-02-26 19:52:45 +08:00
|
|
|
|
ColumnFormat(TIME_COL_WIDTH, ColumnFormat::FixedSize, ColumnFormat::Right));
|
2015-01-03 22:03:33 +08:00
|
|
|
|
|
2015-03-21 02:38:10 +08:00
|
|
|
|
if (!date.isNull())
|
2015-01-03 22:03:33 +08:00
|
|
|
|
msg->markAsSent(date);
|
|
|
|
|
|
|
|
|
|
return msg;
|
|
|
|
|
}
|
|
|
|
|
|
2017-02-26 19:52:45 +08:00
|
|
|
|
ChatMessage::Ptr ChatMessage::createChatInfoMessage(const QString& rawMessage,
|
|
|
|
|
SystemMessageType type, const QDateTime& date)
|
2015-01-03 22:03:33 +08:00
|
|
|
|
{
|
2015-01-05 01:21:35 +08:00
|
|
|
|
ChatMessage::Ptr msg = ChatMessage::Ptr(new ChatMessage);
|
2015-02-16 22:22:29 +08:00
|
|
|
|
QString text = rawMessage.toHtmlEscaped();
|
2015-01-03 22:03:33 +08:00
|
|
|
|
|
2015-01-06 21:30:24 +08:00
|
|
|
|
QString img;
|
2017-02-26 19:52:45 +08:00
|
|
|
|
switch (type) {
|
|
|
|
|
case INFO:
|
2018-09-10 19:19:22 +08:00
|
|
|
|
img = Style::getImagePath("chatArea/info.svg");
|
2017-02-26 19:52:45 +08:00
|
|
|
|
break;
|
|
|
|
|
case ERROR:
|
2018-09-10 19:19:22 +08:00
|
|
|
|
img = Style::getImagePath("chatArea/error.svg");
|
2017-02-26 19:52:45 +08:00
|
|
|
|
break;
|
|
|
|
|
case TYPING:
|
2018-09-10 19:19:22 +08:00
|
|
|
|
img = Style::getImagePath("chatArea/typing.svg");
|
2017-02-26 19:52:45 +08:00
|
|
|
|
break;
|
2015-01-06 21:30:24 +08:00
|
|
|
|
}
|
|
|
|
|
|
2016-06-29 05:59:21 +08:00
|
|
|
|
QFont baseFont = Settings::getInstance().getChatMessageFont();
|
|
|
|
|
|
2017-02-26 19:52:45 +08:00
|
|
|
|
msg->addColumn(new Image(QSize(18, 18), img),
|
|
|
|
|
ColumnFormat(NAME_COL_WIDTH, ColumnFormat::FixedSize, ColumnFormat::Right));
|
2018-04-23 20:06:23 +08:00
|
|
|
|
msg->addColumn(new Text("<b>" + text + "</b>", baseFont, false, text),
|
2017-02-26 19:52:45 +08:00
|
|
|
|
ColumnFormat(1.0, ColumnFormat::VariableSize, ColumnFormat::Left));
|
|
|
|
|
msg->addColumn(new Timestamp(date, Settings::getInstance().getTimestampFormat(), baseFont),
|
|
|
|
|
ColumnFormat(TIME_COL_WIDTH, ColumnFormat::FixedSize, ColumnFormat::Right));
|
2015-01-03 22:03:33 +08:00
|
|
|
|
|
|
|
|
|
return msg;
|
|
|
|
|
}
|
|
|
|
|
|
2017-02-26 19:52:45 +08:00
|
|
|
|
ChatMessage::Ptr ChatMessage::createFileTransferMessage(const QString& sender, ToxFile file,
|
|
|
|
|
bool isMe, const QDateTime& date)
|
2015-01-03 22:03:33 +08:00
|
|
|
|
{
|
2015-01-05 01:21:35 +08:00
|
|
|
|
ChatMessage::Ptr msg = ChatMessage::Ptr(new ChatMessage);
|
2015-01-03 22:03:33 +08:00
|
|
|
|
|
2016-06-29 05:59:21 +08:00
|
|
|
|
QFont baseFont = Settings::getInstance().getChatMessageFont();
|
|
|
|
|
QFont authorFont = baseFont;
|
|
|
|
|
if (isMe)
|
|
|
|
|
authorFont.setBold(true);
|
|
|
|
|
|
2017-02-26 19:52:45 +08:00
|
|
|
|
msg->addColumn(new Text(sender, authorFont, true),
|
|
|
|
|
ColumnFormat(NAME_COL_WIDTH, ColumnFormat::FixedSize, ColumnFormat::Right));
|
2018-09-07 17:56:52 +08:00
|
|
|
|
msg->addColumn(new ChatLineContentProxy(new FileTransferWidget(nullptr, file), 320, 0.6f),
|
2017-02-26 19:52:45 +08:00
|
|
|
|
ColumnFormat(1.0, ColumnFormat::VariableSize));
|
|
|
|
|
msg->addColumn(new Timestamp(date, Settings::getInstance().getTimestampFormat(), baseFont),
|
|
|
|
|
ColumnFormat(TIME_COL_WIDTH, ColumnFormat::FixedSize, ColumnFormat::Right));
|
2015-01-03 22:03:33 +08:00
|
|
|
|
|
|
|
|
|
return msg;
|
|
|
|
|
}
|
|
|
|
|
|
2015-01-18 19:20:13 +08:00
|
|
|
|
ChatMessage::Ptr ChatMessage::createTypingNotification()
|
|
|
|
|
{
|
|
|
|
|
ChatMessage::Ptr msg = ChatMessage::Ptr(new ChatMessage);
|
|
|
|
|
|
2016-06-29 05:59:21 +08:00
|
|
|
|
QFont baseFont = Settings::getInstance().getChatMessageFont();
|
|
|
|
|
|
2017-02-26 19:52:45 +08:00
|
|
|
|
// Note: "[user]..." is just a placeholder. The actual text is set in
|
|
|
|
|
// ChatForm::setFriendTyping()
|
2015-05-24 21:21:15 +08:00
|
|
|
|
//
|
|
|
|
|
// FIXME: Due to circumstances, placeholder is being used in a case where
|
|
|
|
|
// user received typing notifications constantly since contact came online.
|
|
|
|
|
// This causes "[user]..." to be displayed in place of user nick, as long
|
|
|
|
|
// as user will keep typing. Issue #1280
|
2017-02-26 19:52:45 +08:00
|
|
|
|
msg->addColumn(new NotificationIcon(QSize(18, 18)),
|
|
|
|
|
ColumnFormat(NAME_COL_WIDTH, ColumnFormat::FixedSize, ColumnFormat::Right));
|
|
|
|
|
msg->addColumn(new Text("[user]...", baseFont, false, ""),
|
|
|
|
|
ColumnFormat(1.0, ColumnFormat::VariableSize, ColumnFormat::Left));
|
2015-01-25 21:06:06 +08:00
|
|
|
|
|
|
|
|
|
return msg;
|
|
|
|
|
}
|
|
|
|
|
|
2017-04-03 01:38:27 +08:00
|
|
|
|
/**
|
|
|
|
|
* @brief Create message placeholder while chatform restructures text
|
|
|
|
|
*
|
|
|
|
|
* It can take a while for chatform to resize large amounts of text, thus
|
|
|
|
|
* a message placeholder is needed to inform users about it.
|
|
|
|
|
*
|
|
|
|
|
* @return created message
|
|
|
|
|
*/
|
2015-01-25 21:06:06 +08:00
|
|
|
|
ChatMessage::Ptr ChatMessage::createBusyNotification()
|
|
|
|
|
{
|
|
|
|
|
ChatMessage::Ptr msg = ChatMessage::Ptr(new ChatMessage);
|
2016-06-29 05:59:21 +08:00
|
|
|
|
QFont baseFont = Settings::getInstance().getChatMessageFont();
|
|
|
|
|
baseFont.setPixelSize(baseFont.pixelSize() + 2);
|
|
|
|
|
baseFont.setBold(true);
|
2015-01-25 21:06:06 +08:00
|
|
|
|
|
2017-04-03 01:38:27 +08:00
|
|
|
|
msg->addColumn(new Text(QObject::tr("Reformatting text in progress.."), baseFont, false, ""),
|
2017-02-26 19:52:45 +08:00
|
|
|
|
ColumnFormat(1.0, ColumnFormat::VariableSize, ColumnFormat::Center));
|
2015-01-18 19:20:13 +08:00
|
|
|
|
|
|
|
|
|
return msg;
|
|
|
|
|
}
|
|
|
|
|
|
2017-02-26 19:52:45 +08:00
|
|
|
|
void ChatMessage::markAsSent(const QDateTime& time)
|
2014-11-12 21:11:25 +08:00
|
|
|
|
{
|
2016-06-29 05:59:21 +08:00
|
|
|
|
QFont baseFont = Settings::getInstance().getChatMessageFont();
|
|
|
|
|
|
2014-11-12 23:45:24 +08:00
|
|
|
|
// remove the spinner and replace it by $time
|
2016-06-29 05:59:21 +08:00
|
|
|
|
replaceContent(2, new Timestamp(time, Settings::getInstance().getTimestampFormat(), baseFont));
|
2014-11-12 21:11:25 +08:00
|
|
|
|
}
|
2014-11-14 01:27:32 +08:00
|
|
|
|
|
|
|
|
|
QString ChatMessage::toString() const
|
|
|
|
|
{
|
2015-01-05 01:21:35 +08:00
|
|
|
|
ChatLineContent* c = getContent(1);
|
2015-03-21 02:38:10 +08:00
|
|
|
|
if (c)
|
2015-01-05 01:21:35 +08:00
|
|
|
|
return c->getText();
|
|
|
|
|
|
|
|
|
|
return QString();
|
2014-11-14 01:27:32 +08:00
|
|
|
|
}
|
2014-12-14 04:11:03 +08:00
|
|
|
|
|
|
|
|
|
bool ChatMessage::isAction() const
|
|
|
|
|
{
|
|
|
|
|
return action;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ChatMessage::setAsAction()
|
|
|
|
|
{
|
|
|
|
|
action = true;
|
|
|
|
|
}
|
2015-01-03 22:03:33 +08:00
|
|
|
|
|
2015-01-05 01:21:35 +08:00
|
|
|
|
void ChatMessage::hideSender()
|
|
|
|
|
{
|
|
|
|
|
ChatLineContent* c = getContent(0);
|
2015-03-21 02:38:10 +08:00
|
|
|
|
if (c)
|
2015-01-05 01:21:35 +08:00
|
|
|
|
c->hide();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ChatMessage::hideDate()
|
|
|
|
|
{
|
|
|
|
|
ChatLineContent* c = getContent(2);
|
2015-03-21 02:38:10 +08:00
|
|
|
|
if (c)
|
2015-01-05 01:21:35 +08:00
|
|
|
|
c->hide();
|
|
|
|
|
}
|
|
|
|
|
|
2015-05-24 21:21:15 +08:00
|
|
|
|
QString ChatMessage::detectQuotes(const QString& str, MessageType type)
|
2015-01-03 22:03:33 +08:00
|
|
|
|
{
|
|
|
|
|
// detect text quotes
|
|
|
|
|
QStringList messageLines = str.split("\n");
|
|
|
|
|
QString quotedText;
|
2017-02-26 19:52:45 +08:00
|
|
|
|
for (int i = 0; i < messageLines.size(); ++i) {
|
2015-05-24 21:21:15 +08:00
|
|
|
|
// don't quote first line in action message. This makes co-existence of
|
|
|
|
|
// quotes and action messages possible, since only first line can cause
|
|
|
|
|
// problems in case where there is quote in it used.
|
2017-02-26 19:52:45 +08:00
|
|
|
|
if (QRegExp("^(>|>).*").exactMatch(messageLines[i])) {
|
2015-05-24 23:16:30 +08:00
|
|
|
|
if (i > 0 || type != ACTION)
|
2017-05-29 05:14:23 +08:00
|
|
|
|
quotedText += "<span class=quote>" + messageLines[i] + " </span>";
|
2015-05-24 23:16:30 +08:00
|
|
|
|
else
|
2015-05-24 21:21:15 +08:00
|
|
|
|
quotedText += messageLines[i];
|
2017-02-26 19:52:45 +08:00
|
|
|
|
} else {
|
2015-01-03 22:03:33 +08:00
|
|
|
|
quotedText += messageLines[i];
|
2015-05-24 21:21:15 +08:00
|
|
|
|
}
|
2015-01-03 22:03:33 +08:00
|
|
|
|
|
2017-02-26 19:52:45 +08:00
|
|
|
|
if (i < messageLines.size() - 1) {
|
2017-02-06 23:20:45 +08:00
|
|
|
|
quotedText += '\n';
|
2017-02-19 22:48:44 +08:00
|
|
|
|
}
|
2015-01-03 22:03:33 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return quotedText;
|
|
|
|
|
}
|
|
|
|
|
|
2017-02-26 19:52:45 +08:00
|
|
|
|
QString ChatMessage::wrapDiv(const QString& str, const QString& div)
|
2015-02-15 17:51:54 +08:00
|
|
|
|
{
|
2017-02-26 19:52:45 +08:00
|
|
|
|
return QString("<p class=%1>%2</p>").arg(div, /*QChar(0x200E) + */ QString(str));
|
2015-02-15 17:51:54 +08:00
|
|
|
|
}
|