mirror of
https://github.com/qTox/qTox.git
synced 2024-03-22 14:00:36 +08:00
Merge branch 'pr693'
This commit is contained in:
commit
9e7ee848e8
29
src/core.cpp
29
src/core.cpp
|
@ -268,6 +268,7 @@ void Core::start()
|
|||
tox_callback_file_data(tox, onFileDataCallback, this);
|
||||
tox_callback_avatar_info(tox, onAvatarInfoCallback, this);
|
||||
tox_callback_avatar_data(tox, onAvatarDataCallback, this);
|
||||
tox_callback_read_receipt(tox, onReadReceiptCallback, this);
|
||||
|
||||
toxav_register_callstate_callback(toxav, onAvInvite, av_OnInvite, this);
|
||||
toxav_register_callstate_callback(toxav, onAvStart, av_OnStart, this);
|
||||
|
@ -700,6 +701,11 @@ void Core::onAvatarDataCallback(Tox*, int32_t friendnumber, uint8_t,
|
|||
}
|
||||
}
|
||||
|
||||
void Core::onReadReceiptCallback(Tox*, int32_t friendnumber, uint32_t receipt, void *core)
|
||||
{
|
||||
emit static_cast<Core*>(core)->receiptRecieved(friendnumber, receipt);
|
||||
}
|
||||
|
||||
void Core::acceptFriendRequest(const QString& userId)
|
||||
{
|
||||
int friendId = tox_add_friend_norequest(tox, CUserId(userId).data());
|
||||
|
@ -739,23 +745,22 @@ void Core::requestFriendship(const QString& friendAddress, const QString& messag
|
|||
saveConfiguration();
|
||||
}
|
||||
|
||||
void Core::sendMessage(int friendId, const QString& message)
|
||||
int Core::sendMessage(int friendId, const QString& message)
|
||||
{
|
||||
QList<CString> cMessages = splitMessage(message);
|
||||
|
||||
for (auto &cMsg :cMessages)
|
||||
{
|
||||
int messageId = tox_send_message(tox, friendId, cMsg.data(), cMsg.size());
|
||||
if (messageId == 0)
|
||||
emit messageSentResult(friendId, message, messageId);
|
||||
}
|
||||
QMutexLocker ml(&messageSendMutex);
|
||||
CString cMessage(message);
|
||||
int receipt = tox_send_message(tox, friendId, cMessage.data(), cMessage.size());
|
||||
emit messageSentResult(friendId, message, receipt);
|
||||
return receipt;
|
||||
}
|
||||
|
||||
void Core::sendAction(int friendId, const QString &action)
|
||||
int Core::sendAction(int friendId, const QString &action)
|
||||
{
|
||||
QMutexLocker ml(&messageSendMutex);
|
||||
CString cMessage(action);
|
||||
int ret = tox_send_action(tox, friendId, cMessage.data(), cMessage.size());
|
||||
emit actionSentResult(friendId, action, ret);
|
||||
int receipt = tox_send_action(tox, friendId, cMessage.data(), cMessage.size());
|
||||
emit messageSentResult(friendId, action, receipt);
|
||||
return receipt;
|
||||
}
|
||||
|
||||
void Core::sendTyping(int friendId, bool typing)
|
||||
|
|
13
src/core.h
13
src/core.h
|
@ -45,6 +45,7 @@ public:
|
|||
static const QString TOX_EXT;
|
||||
static const QString CONFIG_FILE_NAME;
|
||||
static QString sanitize(QString name);
|
||||
static QList<CString> splitMessage(const QString &message);
|
||||
|
||||
QString getPeerName(const ToxID& id) const;
|
||||
|
||||
|
@ -92,10 +93,10 @@ public slots:
|
|||
void setStatusMessage(const QString& message);
|
||||
void setAvatar(uint8_t format, const QByteArray& data);
|
||||
|
||||
void sendMessage(int friendId, const QString& message);
|
||||
int sendMessage(int friendId, const QString& message);
|
||||
void sendGroupMessage(int groupId, const QString& message);
|
||||
void sendGroupAction(int groupId, const QString& message);
|
||||
void sendAction(int friendId, const QString& action);
|
||||
int sendAction(int friendId, const QString& action);
|
||||
void sendTyping(int friendId, bool typing);
|
||||
|
||||
void sendFile(int32_t friendId, QString Filename, QString FilePath, long long filesize);
|
||||
|
@ -154,7 +155,8 @@ signals:
|
|||
|
||||
void messageSentResult(int friendId, const QString& message, int messageId);
|
||||
void groupSentResult(int groupId, const QString& message, int result);
|
||||
void actionSentResult(int friendId, const QString& action, int success);
|
||||
|
||||
void receiptRecieved(int friedId, int receipt);
|
||||
|
||||
void failedToAddFriend(const QString& userId, const QString& errorInfo = QString());
|
||||
void failedToRemoveFriend(int friendId);
|
||||
|
@ -215,6 +217,7 @@ private:
|
|||
static void onFileDataCallback(Tox *tox, int32_t friendnumber, uint8_t filenumber, const uint8_t *data, uint16_t length, void *userdata);
|
||||
static void onAvatarInfoCallback(Tox* tox, int32_t friendnumber, uint8_t format, uint8_t *hash, void *userdata);
|
||||
static void onAvatarDataCallback(Tox* tox, int32_t friendnumber, uint8_t format, uint8_t *hash, uint8_t *data, uint32_t datalen, void *userdata);
|
||||
static void onReadReceiptCallback(Tox *tox, int32_t friendnumber, uint32_t receipt, void *core);
|
||||
|
||||
static void onAvInvite(void* toxav, int32_t call_index, void* core);
|
||||
static void onAvStart(void* toxav, int32_t call_index, void* core);
|
||||
|
@ -247,8 +250,6 @@ private:
|
|||
|
||||
void checkLastOnline(int friendId);
|
||||
|
||||
QList<CString> splitMessage(const QString &message);
|
||||
|
||||
private slots:
|
||||
void onFileTransferFinished(ToxFile file);
|
||||
|
||||
|
@ -262,7 +263,7 @@ private:
|
|||
int dhtServerId;
|
||||
static QList<ToxFile> fileSendQueue, fileRecvQueue;
|
||||
static ToxCall calls[];
|
||||
QMutex fileSendMutex;
|
||||
QMutex fileSendMutex, messageSendMutex;
|
||||
bool ready;
|
||||
|
||||
uint8_t* pwsaltedkeys[PasswordType::ptCounter]; // use the pw's hash as the "pw"
|
||||
|
|
|
@ -37,9 +37,10 @@ HistoryKeeper *HistoryKeeper::getInstance()
|
|||
{
|
||||
QList<QString> initLst;
|
||||
initLst.push_back(QString("CREATE TABLE IF NOT EXISTS history (id INTEGER PRIMARY KEY AUTOINCREMENT, timestamp INTEGER NOT NULL, ") +
|
||||
QString("chat_id INTEGER NOT NULL, sender INTEGER NOT NULL, sent_ok BOOLEAN NOT NULL DEFAULT TRUE, message TEXT NOT NULL);"));
|
||||
QString("chat_id INTEGER NOT NULL, sender INTEGER NOT NULL, message TEXT NOT NULL);"));
|
||||
initLst.push_back(QString("CREATE TABLE IF NOT EXISTS aliases (id INTEGER PRIMARY KEY AUTOINCREMENT, user_id TEXT UNIQUE NOT NULL);"));
|
||||
initLst.push_back(QString("CREATE TABLE IF NOT EXISTS chats (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT UNIQUE NOT NULL, ctype INTEGER NOT NULL);"));
|
||||
initLst.push_back(QString("CREATE TABLE IF NOT EXISTS sent_status (id INTEGER PRIMARY KEY AUTOINCREMENT, status INTEGER NOT NULL DEFAULT 0);"));
|
||||
|
||||
QString path(":memory:");
|
||||
GenericDdInterface *dbIntf;
|
||||
|
@ -107,8 +108,31 @@ HistoryKeeper::HistoryKeeper(GenericDdInterface *db_) :
|
|||
message
|
||||
*/
|
||||
|
||||
// for old tables:
|
||||
QSqlQuery ans = db->exec("select seq from sqlite_sequence where name=\"history\";");
|
||||
if (ans.first())
|
||||
{
|
||||
QSqlQuery ret = db->exec("select seq from sqlite_sequence where name=\"sent_status\";");
|
||||
int idCur = 0;
|
||||
if (ret.first())
|
||||
{
|
||||
idCur = ret.value(0).toInt();
|
||||
}
|
||||
|
||||
int idMax = ans.value(0).toInt();
|
||||
for (int i = idCur; i < idMax; i++)
|
||||
{
|
||||
QString cmd = QString("INSERT INTO sent_status (status) VALUES (1)");
|
||||
db->exec(cmd);
|
||||
}
|
||||
}
|
||||
|
||||
updateChatsID();
|
||||
updateAliases();
|
||||
|
||||
QSqlQuery sqlAnswer = db->exec("select seq from sqlite_sequence where name=\"history\";");
|
||||
sqlAnswer.first();
|
||||
messageID = sqlAnswer.value(0).toInt();
|
||||
}
|
||||
|
||||
HistoryKeeper::~HistoryKeeper()
|
||||
|
@ -116,7 +140,7 @@ HistoryKeeper::~HistoryKeeper()
|
|||
delete db;
|
||||
}
|
||||
|
||||
void HistoryKeeper::addChatEntry(const QString& chat, const QString& message, const QString& sender, const QDateTime &dt)
|
||||
int HistoryKeeper::addChatEntry(const QString& chat, const QString& message, const QString& sender, const QDateTime &dt, bool isSent)
|
||||
{
|
||||
int chat_id = getChatID(chat, ctSingle).first;
|
||||
int sender_id = getAliasID(sender);
|
||||
|
@ -124,6 +148,10 @@ void HistoryKeeper::addChatEntry(const QString& chat, const QString& message, co
|
|||
db->exec(QString("INSERT INTO history (timestamp, chat_id, sender, message)") +
|
||||
QString("VALUES (%1, %2, %3, '%4');")
|
||||
.arg(dt.toMSecsSinceEpoch()).arg(chat_id).arg(sender_id).arg(wrapMessage(message)));
|
||||
db->exec(QString("INSERT INTO sent_status (status) VALUES (%1)").arg(isSent));
|
||||
|
||||
messageID++;
|
||||
return messageID;
|
||||
}
|
||||
|
||||
QList<HistoryKeeper::HistMessage> HistoryKeeper::getChatHistory(HistoryKeeper::ChatType ct, const QString &chat,
|
||||
|
@ -139,8 +167,8 @@ QList<HistoryKeeper::HistMessage> HistoryKeeper::getChatHistory(HistoryKeeper::C
|
|||
QSqlQuery dbAnswer;
|
||||
if (ct == ctSingle)
|
||||
{
|
||||
dbAnswer = db->exec(QString("SELECT timestamp, user_id, message FROM history INNER JOIN aliases ON history.sender = aliases.id ") +
|
||||
QString("AND timestamp BETWEEN %1 AND %2 AND chat_id = %3;")
|
||||
dbAnswer = db->exec(QString("SELECT history.id, timestamp, user_id, message, status FROM history INNER JOIN aliases ON history.sender = aliases.id ") +
|
||||
QString("INNER JOIN sent_status ON history.id = sent_status.id AND timestamp BETWEEN %1 AND %2 AND chat_id = %3;")
|
||||
.arg(time64_from).arg(time64_to).arg(chat_id));
|
||||
} else {
|
||||
// no groupchats yet
|
||||
|
@ -148,12 +176,17 @@ QList<HistoryKeeper::HistMessage> HistoryKeeper::getChatHistory(HistoryKeeper::C
|
|||
|
||||
while (dbAnswer.next())
|
||||
{
|
||||
QString sender = dbAnswer.value(1).toString();
|
||||
QString message = unWrapMessage(dbAnswer.value(2).toString());
|
||||
qint64 timeInt = dbAnswer.value(0).toLongLong();
|
||||
qint64 id = dbAnswer.value(0).toLongLong();
|
||||
qint64 timeInt = dbAnswer.value(1).toLongLong();
|
||||
QString sender = dbAnswer.value(2).toString();
|
||||
QString message = unWrapMessage(dbAnswer.value(3).toString());
|
||||
bool isSent = true;
|
||||
if (!dbAnswer.value(4).isNull())
|
||||
isSent = dbAnswer.value(4).toBool();
|
||||
|
||||
QDateTime time = QDateTime::fromMSecsSinceEpoch(timeInt);
|
||||
|
||||
res.push_back({sender,message,time});
|
||||
res.push_back({id, sender,message,time,isSent});
|
||||
}
|
||||
|
||||
return res;
|
||||
|
@ -235,13 +268,15 @@ void HistoryKeeper::resetInstance()
|
|||
historyInstance = nullptr;
|
||||
}
|
||||
|
||||
void HistoryKeeper::addGroupChatEntry(const QString &chat, const QString &message, const QString &sender, const QDateTime &dt)
|
||||
int HistoryKeeper::addGroupChatEntry(const QString &chat, const QString &message, const QString &sender, const QDateTime &dt)
|
||||
{
|
||||
Q_UNUSED(chat)
|
||||
Q_UNUSED(message)
|
||||
Q_UNUSED(sender)
|
||||
Q_UNUSED(dt)
|
||||
// no groupchats yet
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
HistoryKeeper::ChatType HistoryKeeper::convertToChatType(int ct)
|
||||
|
@ -275,3 +310,8 @@ void HistoryKeeper::renameHistory(QString from, QString to)
|
|||
if (filePlain.exists())
|
||||
filePlain.rename(QDir(Settings::getInstance().getSettingsDirPath()).filePath(to + ".qtox_history"));
|
||||
}
|
||||
|
||||
void HistoryKeeper::markAsSent(int m_id)
|
||||
{
|
||||
db->exec(QString("UPDATE sent_status SET status = 1 WHERE id = %1;").arg(m_id));
|
||||
}
|
||||
|
|
|
@ -30,9 +30,11 @@ public:
|
|||
|
||||
struct HistMessage
|
||||
{
|
||||
qint64 id;
|
||||
QString sender;
|
||||
QString message;
|
||||
QDateTime timestamp;
|
||||
bool isSent;
|
||||
};
|
||||
|
||||
virtual ~HistoryKeeper();
|
||||
|
@ -44,9 +46,10 @@ public:
|
|||
static bool checkPassword();
|
||||
static void renameHistory(QString from, QString to);
|
||||
|
||||
void addChatEntry(const QString& chat, const QString& message, const QString& sender, const QDateTime &dt);
|
||||
void addGroupChatEntry(const QString& chat, const QString& message, const QString& sender, const QDateTime &dt);
|
||||
int addChatEntry(const QString& chat, const QString& message, const QString& sender, const QDateTime &dt, bool isSent);
|
||||
int addGroupChatEntry(const QString& chat, const QString& message, const QString& sender, const QDateTime &dt);
|
||||
QList<HistMessage> getChatHistory(ChatType ct, const QString &chat, const QDateTime &time_from, const QDateTime &time_to);
|
||||
void markAsSent(int m_id);
|
||||
|
||||
private:
|
||||
HistoryKeeper(GenericDdInterface *db_);
|
||||
|
@ -66,6 +69,7 @@ private:
|
|||
QMap<QString, int> aliases;
|
||||
QMap<QString, QPair<int, ChatType>> chats;
|
||||
bool isEncrypted;
|
||||
int messageID;
|
||||
};
|
||||
|
||||
#endif // HISTORYKEEPER_H
|
||||
|
|
|
@ -121,6 +121,7 @@ void Settings::load()
|
|||
autoAwayTime = s.value("autoAwayTime", 10).toInt();
|
||||
checkUpdates = s.value("checkUpdates", false).toBool();
|
||||
showInFront = s.value("showInFront", false).toBool();
|
||||
fauxOfflineMessaging = s.value("fauxOfflineMessaging", false).toBool();
|
||||
s.endGroup();
|
||||
|
||||
s.beginGroup("Widgets");
|
||||
|
@ -259,6 +260,7 @@ void Settings::save(QString path)
|
|||
s.setValue("autoAwayTime", autoAwayTime);
|
||||
s.setValue("checkUpdates", checkUpdates);
|
||||
s.setValue("showInFront", showInFront);
|
||||
s.setValue("fauxOfflineMessaging", fauxOfflineMessaging);
|
||||
s.endGroup();
|
||||
|
||||
s.beginGroup("Widgets");
|
||||
|
@ -849,3 +851,13 @@ void Settings::setFriendAlias(const ToxID &id, const QString &alias)
|
|||
it->alias = alias;
|
||||
}
|
||||
}
|
||||
|
||||
bool Settings::getFauxOfflineMessaging() const
|
||||
{
|
||||
return fauxOfflineMessaging;
|
||||
}
|
||||
|
||||
void Settings::setFauxOfflineMessaging(bool value)
|
||||
{
|
||||
fauxOfflineMessaging = value;
|
||||
}
|
||||
|
|
|
@ -199,6 +199,9 @@ public:
|
|||
QString getFriendAlias(const ToxID &id) const;
|
||||
void setFriendAlias(const ToxID &id, const QString &alias);
|
||||
|
||||
bool getFauxOfflineMessaging() const;
|
||||
void setFauxOfflineMessaging(bool value);
|
||||
|
||||
public:
|
||||
void save();
|
||||
void save(QString path);
|
||||
|
@ -218,6 +221,7 @@ private:
|
|||
int dhtServerId;
|
||||
bool dontShowDhtDialog;
|
||||
|
||||
bool fauxOfflineMessaging;
|
||||
bool enableIPv6;
|
||||
QString translation;
|
||||
static bool makeToxPortable;
|
||||
|
@ -281,6 +285,7 @@ private:
|
|||
|
||||
QHash<QString, friendProp> friendLst;
|
||||
|
||||
|
||||
signals:
|
||||
//void dataChanged();
|
||||
void dhtServerListChanged();
|
||||
|
|
|
@ -102,6 +102,10 @@ void ChatAreaWidget::insertMessage(ChatActionPtr msgAction, QTextCursor::MoveOpe
|
|||
checkSlider();
|
||||
|
||||
QTextTable *chatTextTable = getMsgTable(pos);
|
||||
msgAction->assignPlace(chatTextTable, this);
|
||||
msgAction->dispaly();
|
||||
|
||||
/*
|
||||
QTextCursor cur = chatTextTable->cellAt(0, 2).firstCursorPosition();
|
||||
cur.clearSelection();
|
||||
cur.setKeepPositionOnInsert(true);
|
||||
|
@ -110,8 +114,8 @@ void ChatAreaWidget::insertMessage(ChatActionPtr msgAction, QTextCursor::MoveOpe
|
|||
chatTextTable->cellAt(0, 2).firstCursorPosition().insertHtml(msgAction->getMessage());
|
||||
chatTextTable->cellAt(0, 4).firstCursorPosition().setBlockFormat(dateFormat);
|
||||
chatTextTable->cellAt(0, 4).firstCursorPosition().insertHtml(msgAction->getDate());
|
||||
|
||||
msgAction->setup(cur, this);
|
||||
*/
|
||||
|
||||
if (msgAction->isInteractive())
|
||||
messages.append(msgAction);
|
||||
|
|
|
@ -39,6 +39,7 @@
|
|||
#include "src/widget/croppinglabel.h"
|
||||
#include "src/misc/style.h"
|
||||
#include "src/misc/settings.h"
|
||||
#include "src/misc/cstring.h"
|
||||
|
||||
ChatForm::ChatForm(Friend* chatFriend)
|
||||
: f(chatFriend)
|
||||
|
@ -76,11 +77,12 @@ ChatForm::ChatForm(Friend* chatFriend)
|
|||
connect(volButton, SIGNAL(clicked()), this, SLOT(onVolMuteToggle()));
|
||||
connect(chatWidget, &ChatAreaWidget::onFileTranfertInterract, this, &ChatForm::onFileTansBtnClicked);
|
||||
connect(Core::getInstance(), &Core::fileSendFailed, this, &ChatForm::onFileSendFailed);
|
||||
connect(this, SIGNAL(chatAreaCleared()), this, SLOT(clearReciepts()));
|
||||
|
||||
setAcceptDrops(true);
|
||||
|
||||
if (Settings::getInstance().getEnableLogging())
|
||||
loadHistory(QDateTime::currentDateTime().addDays(-7));
|
||||
loadHistory(QDateTime::currentDateTime().addDays(-7), true);
|
||||
}
|
||||
|
||||
ChatForm::~ChatForm()
|
||||
|
@ -100,20 +102,36 @@ void ChatForm::onSendTriggered()
|
|||
if (msg.isEmpty())
|
||||
return;
|
||||
|
||||
QDateTime timestamp = QDateTime::currentDateTime();
|
||||
HistoryKeeper::getInstance()->addChatEntry(f->getToxID().publicKey, msg, Core::getInstance()->getSelfId().publicKey, timestamp);
|
||||
bool isAction = msg.startsWith("/me ");
|
||||
if (isAction)
|
||||
msg = msg = msg.right(msg.length() - 4);
|
||||
|
||||
if (msg.startsWith("/me "))
|
||||
QList<CString> splittedMsg = Core::splitMessage(msg);
|
||||
QDateTime timestamp = QDateTime::currentDateTime();
|
||||
|
||||
for (CString& c_msg : splittedMsg)
|
||||
{
|
||||
msg = msg.right(msg.length() - 4);
|
||||
addSelfMessage(msg, true, timestamp);
|
||||
emit sendAction(f->getFriendID(), msg);
|
||||
}
|
||||
else
|
||||
{
|
||||
addSelfMessage(msg, false, timestamp);
|
||||
emit sendMessage(f->getFriendID(), msg);
|
||||
QString qt_msg = CString::toString(c_msg.data(), c_msg.size());
|
||||
QString qt_msg_hist = qt_msg;
|
||||
if (isAction)
|
||||
qt_msg_hist = "/me " + qt_msg;
|
||||
|
||||
bool status = !Settings::getInstance().getFauxOfflineMessaging();
|
||||
|
||||
int id = HistoryKeeper::getInstance()->addChatEntry(f->getToxID().publicKey, qt_msg_hist,
|
||||
Core::getInstance()->getSelfId().publicKey, timestamp, status);
|
||||
|
||||
MessageActionPtr ma = addSelfMessage(msg, isAction, timestamp, false);
|
||||
|
||||
int rec;
|
||||
if (isAction)
|
||||
rec = Core::getInstance()->sendAction(f->getFriendID(), msg);
|
||||
else
|
||||
rec = Core::getInstance()->sendMessage(f->getFriendID(), msg);
|
||||
|
||||
registerReceipt(rec, id, ma);
|
||||
}
|
||||
|
||||
msgEdit->clear();
|
||||
}
|
||||
|
||||
|
@ -691,7 +709,7 @@ void ChatForm::onAvatarRemoved(int FriendId)
|
|||
avatar->setPixmap(QPixmap(":/img/contact_dark.png"), Qt::transparent);
|
||||
}
|
||||
|
||||
void ChatForm::loadHistory(QDateTime since)
|
||||
void ChatForm::loadHistory(QDateTime since, bool processUndelivered)
|
||||
{
|
||||
QDateTime now = QDateTime::currentDateTime();
|
||||
|
||||
|
@ -728,7 +746,21 @@ void ChatForm::loadHistory(QDateTime since)
|
|||
}
|
||||
|
||||
// Show each messages
|
||||
ChatActionPtr ca = genMessageActionAction(ToxID::fromString(it.sender), it.message, false, msgDateTime);
|
||||
MessageActionPtr ca = genMessageActionAction(ToxID::fromString(it.sender), it.message, false, msgDateTime);
|
||||
if (it.isSent)
|
||||
{
|
||||
ca->markAsSent();
|
||||
} else {
|
||||
if (processUndelivered)
|
||||
{
|
||||
int rec;
|
||||
if (ca->isAction())
|
||||
rec = Core::getInstance()->sendAction(f->getFriendID(), ca->getRawMessage());
|
||||
else
|
||||
rec = Core::getInstance()->sendMessage(f->getFriendID(), ca->getRawMessage());
|
||||
registerReceipt(rec, it.id, ca);
|
||||
}
|
||||
}
|
||||
historyMessages.append(ca);
|
||||
}
|
||||
std::swap(storedPrevId, previousId);
|
||||
|
@ -787,7 +819,6 @@ void ChatForm::updateTime()
|
|||
callDuration->setText(secondsToDHMS(timeElapsed.elapsed()/1000));
|
||||
}
|
||||
|
||||
|
||||
QString ChatForm::secondsToDHMS(quint32 duration)
|
||||
{
|
||||
QString res;
|
||||
|
@ -810,3 +841,53 @@ QString ChatForm::secondsToDHMS(quint32 duration)
|
|||
//I assume no one will ever have call longer than ~30days
|
||||
return cD + res.sprintf("%dd%02dh %02dm %02ds", days, hours, minutes, seconds);
|
||||
}
|
||||
|
||||
void ChatForm::registerReceipt(int receipt, int messageID, MessageActionPtr msg)
|
||||
{
|
||||
receipts[receipt] = messageID;
|
||||
undeliveredMsgs[messageID] = msg;
|
||||
}
|
||||
|
||||
void ChatForm::dischargeReceipt(int receipt)
|
||||
{
|
||||
auto it = receipts.find(receipt);
|
||||
if (it != receipts.end())
|
||||
{
|
||||
int mID = it.value();
|
||||
auto msgIt = undeliveredMsgs.find(mID);
|
||||
if (msgIt != undeliveredMsgs.end())
|
||||
{
|
||||
HistoryKeeper::getInstance()->markAsSent(mID);
|
||||
msgIt.value()->markAsSent();
|
||||
msgIt.value()->featureUpdate();
|
||||
undeliveredMsgs.erase(msgIt);
|
||||
}
|
||||
receipts.erase(it);
|
||||
}
|
||||
}
|
||||
|
||||
void ChatForm::clearReciepts()
|
||||
{
|
||||
receipts.clear();
|
||||
undeliveredMsgs.clear();
|
||||
}
|
||||
|
||||
void ChatForm::deliverOfflineMsgs()
|
||||
{
|
||||
if (!Settings::getInstance().getFauxOfflineMessaging())
|
||||
return;
|
||||
|
||||
QMap<int, MessageActionPtr> msgs = undeliveredMsgs;
|
||||
clearReciepts();
|
||||
|
||||
for (auto iter = msgs.begin(); iter != msgs.end(); iter++)
|
||||
{
|
||||
QString messageText = iter.value()->getRawMessage();
|
||||
int rec;
|
||||
if (iter.value()->isAction())
|
||||
rec = Core::getInstance()->sendAction(f->getFriendID(), messageText);
|
||||
else
|
||||
rec = Core::getInstance()->sendMessage(f->getFriendID(), messageText);
|
||||
registerReceipt(rec, iter.key(), iter.value());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include <QLabel>
|
||||
#include <QTimer>
|
||||
#include <QElapsedTimer>
|
||||
#include <QSet>
|
||||
|
||||
struct Friend;
|
||||
class FileTransferInstance;
|
||||
|
@ -36,6 +37,8 @@ public:
|
|||
~ChatForm();
|
||||
void setStatusMessage(QString newMessage);
|
||||
|
||||
void dischargeReceipt(int receipt);
|
||||
|
||||
signals:
|
||||
void sendFile(int32_t friendId, QString, QString, long long);
|
||||
void startCall(int friendId);
|
||||
|
@ -47,6 +50,8 @@ signals:
|
|||
void volMuteToggle(int callId);
|
||||
|
||||
public slots:
|
||||
void deliverOfflineMsgs();
|
||||
void clearReciepts();
|
||||
void startFileSend(ToxFile file);
|
||||
void onFileRecvRequest(ToxFile file);
|
||||
void onAvInvite(int FriendId, int CallId, bool video);
|
||||
|
@ -80,10 +85,11 @@ private slots:
|
|||
void updateTime();
|
||||
|
||||
protected:
|
||||
void loadHistory(QDateTime since);
|
||||
void loadHistory(QDateTime since, bool processUndelivered = false);
|
||||
// drag & drop
|
||||
void dragEnterEvent(QDragEnterEvent* ev);
|
||||
void dropEvent(QDropEvent* ev);
|
||||
void registerReceipt(int receipt, int messageID, MessageActionPtr msg);
|
||||
|
||||
private:
|
||||
Friend* f;
|
||||
|
@ -100,6 +106,8 @@ private:
|
|||
void startCounter();
|
||||
void stopCounter();
|
||||
QString secondsToDHMS(quint32 duration);
|
||||
QHash<int, int> receipts;
|
||||
QMap<int, MessageActionPtr> undeliveredMsgs;
|
||||
};
|
||||
|
||||
#endif // CHATFORM_H
|
||||
|
|
|
@ -149,6 +149,8 @@ GenericChatForm::GenericChatForm(QWidget *parent) :
|
|||
chatWidget->document()->setDefaultStyleSheet(Style::getStylesheet(":ui/chatArea/innerStyle.css"));
|
||||
chatWidget->setStyleSheet(Style::getStylesheet(":/ui/chatArea/chatArea.css"));
|
||||
headWidget->setStyleSheet(Style::getStylesheet(":/ui/chatArea/chatHead.css"));
|
||||
|
||||
ChatAction::setupFormat();
|
||||
}
|
||||
|
||||
bool GenericChatForm::isEmpty()
|
||||
|
@ -199,20 +201,28 @@ void GenericChatForm::onSaveLogClicked()
|
|||
*/
|
||||
void GenericChatForm::addMessage(const QString& author, const QString &message, bool isAction, const QDateTime &datetime)
|
||||
{
|
||||
ChatActionPtr ca = genMessageActionAction(author, message, isAction, datetime);
|
||||
MessageActionPtr ca = genMessageActionAction(author, message, isAction, datetime);
|
||||
ca->markAsSent();
|
||||
chatWidget->insertMessage(ca);
|
||||
}
|
||||
|
||||
void GenericChatForm::addMessage(const ToxID& author, const QString &message, bool isAction, const QDateTime &datetime)
|
||||
MessageActionPtr GenericChatForm::addMessage(const ToxID& author, const QString &message, bool isAction,
|
||||
const QDateTime &datetime, bool isSent)
|
||||
{
|
||||
ChatActionPtr ca = genMessageActionAction(author, message, isAction, datetime);
|
||||
MessageActionPtr ca = genMessageActionAction(author, message, isAction, datetime);
|
||||
if (isSent)
|
||||
ca->markAsSent();
|
||||
chatWidget->insertMessage(ca);
|
||||
return ca;
|
||||
}
|
||||
|
||||
void GenericChatForm::addSelfMessage(const QString &message, bool isAction, const QDateTime &datetime)
|
||||
MessageActionPtr GenericChatForm::addSelfMessage(const QString &message, bool isAction, const QDateTime &datetime, bool isSent)
|
||||
{
|
||||
ChatActionPtr ca = genSelfActionAction(message, isAction, datetime);
|
||||
MessageActionPtr ca = genSelfActionAction(message, isAction, datetime);
|
||||
if (isSent)
|
||||
ca->markAsSent();
|
||||
chatWidget->insertMessage(ca);
|
||||
return ca;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -221,7 +231,9 @@ void GenericChatForm::addSelfMessage(const QString &message, bool isAction, cons
|
|||
void GenericChatForm::addAlertMessage(const QString& author, QString message, QDateTime datetime)
|
||||
{
|
||||
QString date = datetime.toString(Settings::getInstance().getTimestampFormat());
|
||||
chatWidget->insertMessage(ChatActionPtr(new AlertAction(author, message, date)));
|
||||
AlertAction *alact = new AlertAction(author, message, date);
|
||||
alact->markAsSent();
|
||||
chatWidget->insertMessage(ChatActionPtr(alact));
|
||||
|
||||
previousId.publicKey = author;
|
||||
}
|
||||
|
@ -293,12 +305,15 @@ void GenericChatForm::clearChatArea(bool notinform)
|
|||
delete earliestMessage;
|
||||
earliestMessage = nullptr;
|
||||
}
|
||||
|
||||
emit chatAreaCleared();
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated The only reason it's still alive is because the groupchat API is a bit limited
|
||||
*/
|
||||
ChatActionPtr GenericChatForm::genMessageActionAction(const QString &author, QString message, bool isAction, const QDateTime &datetime)
|
||||
MessageActionPtr GenericChatForm::genMessageActionAction(const QString &author, QString message, bool isAction,
|
||||
const QDateTime &datetime)
|
||||
{
|
||||
if (earliestMessage == nullptr)
|
||||
{
|
||||
|
@ -317,20 +332,20 @@ ChatActionPtr GenericChatForm::genMessageActionAction(const QString &author, QSt
|
|||
if (isAction)
|
||||
{
|
||||
previousId = ToxID(); // next msg has a name regardless
|
||||
return ChatActionPtr(new ActionAction (getElidedName(author), message, date, isMe));
|
||||
return MessageActionPtr(new ActionAction (getElidedName(author), message, date, isMe));
|
||||
}
|
||||
|
||||
ChatActionPtr res;
|
||||
MessageActionPtr res;
|
||||
if (previousId.publicKey == author)
|
||||
res = ChatActionPtr(new MessageAction(QString(), message, date, isMe));
|
||||
res = MessageActionPtr(new MessageAction(QString(), message, date, isMe));
|
||||
else
|
||||
res = ChatActionPtr(new MessageAction(getElidedName(author), message, date, isMe));
|
||||
res = MessageActionPtr(new MessageAction(getElidedName(author), message, date, isMe));
|
||||
|
||||
previousId.publicKey = author;
|
||||
return res;
|
||||
}
|
||||
|
||||
ChatActionPtr GenericChatForm::genMessageActionAction(const ToxID& author, QString message, bool isAction, const QDateTime &datetime)
|
||||
MessageActionPtr GenericChatForm::genMessageActionAction(const ToxID& author, QString message, bool isAction, const QDateTime &datetime)
|
||||
{
|
||||
if (earliestMessage == nullptr)
|
||||
{
|
||||
|
@ -364,20 +379,20 @@ ChatActionPtr GenericChatForm::genMessageActionAction(const ToxID& author, QStri
|
|||
if (isAction)
|
||||
{
|
||||
previousId = ToxID(); // next msg has a name regardless
|
||||
return ChatActionPtr(new ActionAction (getElidedName(authorStr), message, date, isMe));
|
||||
return MessageActionPtr(new ActionAction (getElidedName(authorStr), message, date, isMe));
|
||||
}
|
||||
|
||||
ChatActionPtr res;
|
||||
MessageActionPtr res;
|
||||
if (previousId == author)
|
||||
res = ChatActionPtr(new MessageAction(QString(), message, date, isMe));
|
||||
res = MessageActionPtr(new MessageAction(QString(), message, date, isMe));
|
||||
else
|
||||
res = ChatActionPtr(new MessageAction(getElidedName(authorStr), message, date, isMe));
|
||||
res = MessageActionPtr(new MessageAction(getElidedName(authorStr), message, date, isMe));
|
||||
|
||||
previousId = author;
|
||||
return res;
|
||||
}
|
||||
|
||||
ChatActionPtr GenericChatForm::genSelfActionAction(QString message, bool isAction, const QDateTime &datetime)
|
||||
MessageActionPtr GenericChatForm::genSelfActionAction(QString message, bool isAction, const QDateTime &datetime)
|
||||
{
|
||||
if (earliestMessage == nullptr)
|
||||
{
|
||||
|
@ -398,14 +413,14 @@ ChatActionPtr GenericChatForm::genSelfActionAction(QString message, bool isActio
|
|||
if (isAction)
|
||||
{
|
||||
previousId = ToxID(); // next msg has a name regardless
|
||||
return ChatActionPtr(new ActionAction (getElidedName(author), message, date, true));
|
||||
return MessageActionPtr(new ActionAction (getElidedName(author), message, date, true));
|
||||
}
|
||||
|
||||
ChatActionPtr res;
|
||||
MessageActionPtr res;
|
||||
if (previousId.isMine())
|
||||
res = ChatActionPtr(new MessageAction(QString(), message, date, true));
|
||||
res = MessageActionPtr(new MessageAction(QString(), message, date, true));
|
||||
else
|
||||
res = ChatActionPtr(new MessageAction(getElidedName(author), message, date, true));
|
||||
res = MessageActionPtr(new MessageAction(getElidedName(author), message, date, true));
|
||||
|
||||
previousId = Core::getInstance()->getSelfId();
|
||||
return res;
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
#include <QPoint>
|
||||
#include <QDateTime>
|
||||
#include <QMenu>
|
||||
#include "src/widget/tool/chatactions/chataction.h"
|
||||
#include "src/widget/tool/chatactions/messageaction.h"
|
||||
#include "src/corestructs.h"
|
||||
|
||||
// Spacing in px inserted when the author of the last message changes
|
||||
|
@ -48,9 +48,10 @@ public:
|
|||
|
||||
virtual void setName(const QString &newName);
|
||||
virtual void show(Ui::MainWindow &ui);
|
||||
|
||||
void addMessage(const QString& author, const QString &message, bool isAction, const QDateTime &datetime); ///< Deprecated
|
||||
void addMessage(const ToxID& author, const QString &message, bool isAction, const QDateTime &datetime);
|
||||
void addSelfMessage(const QString &message, bool isAction, const QDateTime &datetime);
|
||||
MessageActionPtr addMessage(const ToxID& author, const QString &message, bool isAction, const QDateTime &datetime, bool isSent);
|
||||
MessageActionPtr addSelfMessage(const QString &message, bool isAction, const QDateTime &datetime, bool isSent);
|
||||
void addSystemInfoMessage(const QString &message, const QString &type, const QDateTime &datetime);
|
||||
void addAlertMessage(const QString& author, QString message, QDateTime datetime); ///< Deprecated
|
||||
void addAlertMessage(const ToxID& author, QString message, QDateTime datetime);
|
||||
|
@ -59,6 +60,7 @@ public:
|
|||
signals:
|
||||
void sendMessage(int, QString);
|
||||
void sendAction(int, QString);
|
||||
void chatAreaCleared();
|
||||
|
||||
public slots:
|
||||
void focusInput();
|
||||
|
@ -72,9 +74,9 @@ protected slots:
|
|||
|
||||
protected:
|
||||
QString getElidedName(const QString& name);
|
||||
ChatActionPtr genMessageActionAction(const QString& author, QString message, bool isAction, const QDateTime &datetime); ///< Deprecated
|
||||
ChatActionPtr genMessageActionAction(const ToxID& author, QString message, bool isAction, const QDateTime &datetime);
|
||||
ChatActionPtr genSelfActionAction(QString message, bool isAction, const QDateTime &datetime);
|
||||
MessageActionPtr genMessageActionAction(const QString& author, QString message, bool isAction, const QDateTime &datetime); ///< Deprecated
|
||||
MessageActionPtr genMessageActionAction(const ToxID& author, QString message, bool isAction, const QDateTime &datetime);
|
||||
MessageActionPtr genSelfActionAction(QString message, bool isAction, const QDateTime &datetime);
|
||||
ChatActionPtr genSystemInfoAction(const QString &message, const QString &type, const QDateTime &datetime);
|
||||
|
||||
ToxID previousId;
|
||||
|
|
|
@ -59,6 +59,7 @@ GeneralForm::GeneralForm(SettingsWidget *myParent) :
|
|||
bodyUI->autoacceptFiles->setChecked(Settings::getInstance().getAutoSaveEnabled());
|
||||
bodyUI->autoSaveFilesDir->setText(Settings::getInstance().getGlobalAutoAcceptDir());
|
||||
bodyUI->showInFront->setChecked(Settings::getInstance().getShowInFront());
|
||||
bodyUI->cbFauxOfflineMessaging->setChecked(Settings::getInstance().getFauxOfflineMessaging());
|
||||
|
||||
for (auto entry : SmileyPack::listSmileyPacks())
|
||||
{
|
||||
|
@ -125,6 +126,7 @@ GeneralForm::GeneralForm(SettingsWidget *myParent) :
|
|||
connect(bodyUI->proxyAddr, &QLineEdit::editingFinished, this, &GeneralForm::onProxyAddrEdited);
|
||||
connect(bodyUI->proxyPort, SIGNAL(valueChanged(int)), this, SLOT(onProxyPortEdited(int)));
|
||||
connect(bodyUI->reconnectButton, &QPushButton::clicked, this, &GeneralForm::onReconnectClicked);
|
||||
connect(bodyUI->cbFauxOfflineMessaging, &QCheckBox::stateChanged, this, &GeneralForm::onFauxOfflineMessaging);
|
||||
}
|
||||
|
||||
GeneralForm::~GeneralForm()
|
||||
|
@ -300,3 +302,7 @@ void GeneralForm::onSetShowInFront()
|
|||
Settings::getInstance().setShowInFront(bodyUI->showInFront->isChecked());
|
||||
}
|
||||
|
||||
void GeneralForm::onFauxOfflineMessaging()
|
||||
{
|
||||
Settings::getInstance().setFauxOfflineMessaging(bodyUI->cbFauxOfflineMessaging->isChecked());
|
||||
}
|
||||
|
|
|
@ -53,6 +53,7 @@ private slots:
|
|||
void onAutoSaveDirChange();
|
||||
void onCheckUpdateChanged();
|
||||
void onSetShowInFront();
|
||||
void onFauxOfflineMessaging();
|
||||
|
||||
private:
|
||||
Ui::GeneralSettings *bodyUI;
|
||||
|
|
|
@ -40,7 +40,7 @@
|
|||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>511</width>
|
||||
<height>796</height>
|
||||
<height>698</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_4" stretch="0,0,1">
|
||||
|
@ -97,41 +97,41 @@
|
|||
<layout class="QHBoxLayout" name="trayLayout">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="startInTray">
|
||||
<property name="text">
|
||||
<string>Start in tray</string>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Start in tray</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="closeToTray">
|
||||
<property name="text">
|
||||
<string>Close to tray</string>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Close to tray</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="minimizeToTray">
|
||||
<property name="text">
|
||||
<string>Minimize to tray</string>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Minimize to tray</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
|
@ -157,6 +157,13 @@
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="cbFauxOfflineMessaging">
|
||||
<property name="text">
|
||||
<string>Faux offline messaging</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<item alignment="Qt::AlignLeft">
|
||||
|
|
|
@ -52,6 +52,7 @@ void PrivacyForm::onEnableLoggingUpdated()
|
|||
Settings::getInstance().setEnableLogging(bodyUI->cbKeepHistory->isChecked());
|
||||
bodyUI->cbEncryptHistory->setEnabled(bodyUI->cbKeepHistory->isChecked());
|
||||
HistoryKeeper::getInstance()->resetInstance();
|
||||
Widget::getInstance()->clearAllReceipts();
|
||||
}
|
||||
|
||||
void PrivacyForm::onTypingNotificationEnabledUpdated()
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
ActionAction::ActionAction(const QString &author, QString message, const QString &date, const bool& me) :
|
||||
MessageAction(author, author+" "+message, date, me)
|
||||
{
|
||||
rawMessage = message;
|
||||
}
|
||||
|
||||
QString ActionAction::getName()
|
||||
|
@ -31,3 +32,8 @@ QString ActionAction::getMessage()
|
|||
{
|
||||
return MessageAction::getMessage("action");
|
||||
}
|
||||
|
||||
QString ActionAction::getRawMessage()
|
||||
{
|
||||
return rawMessage;
|
||||
}
|
||||
|
|
|
@ -24,12 +24,15 @@ class ActionAction : public MessageAction
|
|||
public:
|
||||
ActionAction(const QString &author, QString message, const QString& date, const bool&);
|
||||
virtual ~ActionAction(){;}
|
||||
virtual QString getRawMessage();
|
||||
virtual bool isAction() {return true;}
|
||||
|
||||
protected:
|
||||
virtual QString getMessage();
|
||||
virtual QString getName();
|
||||
virtual void setup(QTextCursor, QTextEdit*) override {;}
|
||||
|
||||
private:
|
||||
QString message;
|
||||
QString message, rawMessage;
|
||||
};
|
||||
|
||||
#endif // MESSAGEACTION_H
|
||||
|
|
|
@ -21,26 +21,6 @@ AlertAction::AlertAction(const QString &author, const QString &message, const QS
|
|||
{
|
||||
}
|
||||
|
||||
void AlertAction::setup(QTextCursor cursor, QTextEdit *)
|
||||
{
|
||||
// When this function is called, we're supposed to only update ourselve when needed
|
||||
// Nobody should ask us to do anything with our content, we're on our own
|
||||
// Except we never udpate on our own, so we can safely free our resources
|
||||
|
||||
(void) cursor;
|
||||
message.clear();
|
||||
message.squeeze();
|
||||
name.clear();
|
||||
name.squeeze();
|
||||
date.clear();
|
||||
date.squeeze();
|
||||
}
|
||||
/*
|
||||
QString AlertAction::getName()
|
||||
{
|
||||
return QString("<div class=%1>%2</div>").arg("alert_name").arg(toHtmlChars(name));
|
||||
}
|
||||
*/
|
||||
QString AlertAction::getMessage()
|
||||
{
|
||||
return MessageAction::getMessage("alert");
|
||||
|
|
|
@ -24,9 +24,9 @@ class AlertAction : public MessageAction
|
|||
public:
|
||||
AlertAction(const QString &author, const QString &message, const QString& date);
|
||||
virtual ~AlertAction(){;}
|
||||
|
||||
protected:
|
||||
virtual QString getMessage();
|
||||
//virtual QString getName(); only do the message for now; preferably would do the whole row
|
||||
virtual void setup(QTextCursor cursor, QTextEdit*) override;
|
||||
|
||||
private:
|
||||
QString message;
|
||||
|
|
|
@ -17,6 +17,11 @@
|
|||
#include "chataction.h"
|
||||
#include <QStringList>
|
||||
#include <QBuffer>
|
||||
#include <QTextTable>
|
||||
#include <QScrollBar>
|
||||
#include <QTextEdit>
|
||||
|
||||
QTextBlockFormat ChatAction::nameFormat, ChatAction::dateFormat;
|
||||
|
||||
QString ChatAction::toHtmlChars(const QString &str)
|
||||
{
|
||||
|
@ -53,3 +58,59 @@ QString ChatAction::getDate()
|
|||
else
|
||||
return QString("<div class=date>" + toHtmlChars(date) + "</div>");
|
||||
}
|
||||
|
||||
void ChatAction::assignPlace(QTextTable *position, QTextEdit *te)
|
||||
{
|
||||
textTable = position;
|
||||
cur = position->cellAt(0, 2).firstCursorPosition();
|
||||
cur.clearSelection();
|
||||
cur.setKeepPositionOnInsert(true);
|
||||
textEdit = te;
|
||||
}
|
||||
|
||||
void ChatAction::dispaly()
|
||||
{
|
||||
textTable->cellAt(0, 0).firstCursorPosition().setBlockFormat(nameFormat);
|
||||
textTable->cellAt(0, 0).firstCursorPosition().insertHtml(getName());
|
||||
textTable->cellAt(0, 2).firstCursorPosition().insertHtml(getMessage());
|
||||
textTable->cellAt(0, 4).firstCursorPosition().setBlockFormat(dateFormat);
|
||||
textTable->cellAt(0, 4).firstCursorPosition().insertHtml(getDate());
|
||||
|
||||
cur.setKeepPositionOnInsert(true);
|
||||
int end=cur.selectionEnd();
|
||||
cur.setPosition(cur.position());
|
||||
cur.setPosition(end, QTextCursor::KeepAnchor);
|
||||
|
||||
featureUpdate();
|
||||
}
|
||||
|
||||
void ChatAction::setupFormat()
|
||||
{
|
||||
nameFormat.setAlignment(Qt::AlignRight);
|
||||
nameFormat.setNonBreakableLines(true);
|
||||
dateFormat.setAlignment(Qt::AlignLeft);
|
||||
dateFormat.setNonBreakableLines(true);
|
||||
}
|
||||
|
||||
void ChatAction::updateContent()
|
||||
{
|
||||
if (cur.isNull() || !textEdit)
|
||||
return;
|
||||
|
||||
int vSliderVal = textEdit->verticalScrollBar()->value();
|
||||
|
||||
// update content
|
||||
int pos = cur.selectionStart();
|
||||
cur.removeSelectedText();
|
||||
cur.setKeepPositionOnInsert(false);
|
||||
cur.insertHtml(getMessage());
|
||||
cur.setKeepPositionOnInsert(true);
|
||||
int end = cur.position();
|
||||
cur.setPosition(pos);
|
||||
cur.setPosition(end, QTextCursor::KeepAnchor);
|
||||
|
||||
// restore old slider value
|
||||
textEdit->verticalScrollBar()->setValue(vSliderVal);
|
||||
|
||||
featureUpdate();
|
||||
}
|
||||
|
|
|
@ -23,26 +23,42 @@
|
|||
|
||||
class FileTransferInstance;
|
||||
class QTextEdit;
|
||||
class QTextTable;
|
||||
|
||||
class ChatAction : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
ChatAction(const bool &me, const QString &author, const QString &date) : isMe(me), name(author), date(date) {;}
|
||||
virtual ~ChatAction(){;}
|
||||
virtual void setup(QTextCursor cursor, QTextEdit* textEdit) = 0; ///< Call once, and then you MUST let the object update itself
|
||||
|
||||
void assignPlace(QTextTable *position, QTextEdit* te);
|
||||
virtual void dispaly();
|
||||
virtual bool isInteractive(){return false;}
|
||||
virtual void featureUpdate() {;}
|
||||
|
||||
static void setupFormat();
|
||||
|
||||
public slots:
|
||||
void updateContent();
|
||||
|
||||
protected:
|
||||
virtual QString getName();
|
||||
virtual QString getMessage() = 0;
|
||||
virtual QString getDate();
|
||||
virtual bool isInteractive(){return false;}
|
||||
|
||||
protected:
|
||||
QString toHtmlChars(const QString &str);
|
||||
QString QImage2base64(const QImage &img);
|
||||
|
||||
protected:
|
||||
bool isMe;
|
||||
QString name, date;
|
||||
|
||||
QTextTable *textTable;
|
||||
QTextEdit *textEdit;
|
||||
QTextCursor cur;
|
||||
|
||||
static QTextBlockFormat nameFormat, dateFormat;
|
||||
};
|
||||
|
||||
typedef QSharedPointer<ChatAction> ChatActionPtr;
|
||||
|
|
|
@ -22,11 +22,10 @@
|
|||
|
||||
FileTransferAction::FileTransferAction(FileTransferInstance *widget, const QString &author, const QString &date, const bool &me)
|
||||
: ChatAction(me, author, date)
|
||||
, edit(nullptr)
|
||||
{
|
||||
w = widget;
|
||||
|
||||
connect(w, &FileTransferInstance::stateUpdated, this, &FileTransferAction::updateHtml);
|
||||
connect(w, &FileTransferInstance::stateUpdated, this, &FileTransferAction::updateContent);
|
||||
}
|
||||
|
||||
FileTransferAction::~FileTransferAction()
|
||||
|
@ -43,6 +42,7 @@ QString FileTransferAction::getMessage()
|
|||
return widgetHtml;
|
||||
}
|
||||
|
||||
/*
|
||||
void FileTransferAction::setup(QTextCursor cursor, QTextEdit *textEdit)
|
||||
{
|
||||
cur = cursor;
|
||||
|
@ -53,7 +53,8 @@ void FileTransferAction::setup(QTextCursor cursor, QTextEdit *textEdit)
|
|||
|
||||
edit = textEdit;
|
||||
}
|
||||
|
||||
*/
|
||||
/*
|
||||
void FileTransferAction::updateHtml()
|
||||
{
|
||||
if (cur.isNull() || !edit)
|
||||
|
@ -75,7 +76,7 @@ void FileTransferAction::updateHtml()
|
|||
// restore old slider value
|
||||
edit->verticalScrollBar()->setValue(vSliderVal);
|
||||
}
|
||||
|
||||
*/
|
||||
bool FileTransferAction::isInteractive()
|
||||
{
|
||||
if (w->getState() == FileTransferInstance::TransfState::tsCanceled
|
||||
|
|
|
@ -25,17 +25,13 @@ class FileTransferAction : public ChatAction
|
|||
public:
|
||||
FileTransferAction(FileTransferInstance *widget, const QString &author, const QString &date, const bool &me);
|
||||
virtual ~FileTransferAction();
|
||||
virtual QString getMessage();
|
||||
virtual void setup(QTextCursor cursor, QTextEdit* textEdit) override;
|
||||
virtual bool isInteractive();
|
||||
|
||||
private slots:
|
||||
void updateHtml();
|
||||
protected:
|
||||
virtual QString getMessage();
|
||||
|
||||
private:
|
||||
FileTransferInstance *w;
|
||||
QTextCursor cur;
|
||||
QTextEdit* edit;
|
||||
};
|
||||
|
||||
#endif // FILETRANSFERACTION_H
|
||||
|
|
|
@ -17,11 +17,13 @@
|
|||
#include "messageaction.h"
|
||||
#include "src/misc/smileypack.h"
|
||||
#include "src/misc/settings.h"
|
||||
#include <QTextTable>
|
||||
|
||||
MessageAction::MessageAction(const QString &author, const QString &message, const QString &date, const bool &me) :
|
||||
ChatAction(me, author, date),
|
||||
message(message)
|
||||
{
|
||||
isProcessed = false;
|
||||
}
|
||||
|
||||
QString MessageAction::getMessage(QString div)
|
||||
|
@ -71,3 +73,24 @@ QString MessageAction::getMessage()
|
|||
else
|
||||
return getMessage("message");
|
||||
}
|
||||
|
||||
void MessageAction::featureUpdate()
|
||||
{
|
||||
QTextTableCell cell = textTable->cellAt(0,3);
|
||||
QTextTableCellFormat format;
|
||||
if (!isProcessed)
|
||||
format.setBackground(QColor(Qt::red));
|
||||
else
|
||||
format.setBackground(QColor(Qt::white));
|
||||
cell.setFormat(format);
|
||||
}
|
||||
|
||||
void MessageAction::markAsSent()
|
||||
{
|
||||
isProcessed = true;
|
||||
}
|
||||
|
||||
QString MessageAction::getRawMessage()
|
||||
{
|
||||
return message;
|
||||
}
|
||||
|
|
|
@ -24,12 +24,20 @@ class MessageAction : public ChatAction
|
|||
public:
|
||||
MessageAction(const QString &author, const QString &message, const QString &date, const bool &me);
|
||||
virtual ~MessageAction(){;}
|
||||
virtual void featureUpdate();
|
||||
void markAsSent();
|
||||
virtual QString getRawMessage();
|
||||
virtual bool isAction() {return false;}
|
||||
|
||||
protected:
|
||||
virtual QString getMessage();
|
||||
virtual QString getMessage(QString div);
|
||||
virtual void setup(QTextCursor, QTextEdit*) override {;}
|
||||
|
||||
protected:
|
||||
QString message;
|
||||
bool isProcessed;
|
||||
};
|
||||
|
||||
typedef QSharedPointer<MessageAction> MessageActionPtr;
|
||||
|
||||
#endif // MESSAGEACTION_H
|
||||
|
|
|
@ -24,8 +24,8 @@ class SystemMessageAction : public ChatAction
|
|||
public:
|
||||
SystemMessageAction(const QString &message, const QString& type, const QString &date);
|
||||
virtual ~SystemMessageAction(){;}
|
||||
virtual void setup(QTextCursor, QTextEdit*) override {;}
|
||||
|
||||
protected:
|
||||
virtual QString getName() {return QString();}
|
||||
virtual QString getMessage();
|
||||
|
||||
|
|
|
@ -213,6 +213,7 @@ void Widget::init()
|
|||
connect(core, &Core::friendStatusMessageChanged, this, &Widget::onFriendStatusMessageChanged);
|
||||
connect(core, &Core::friendRequestReceived, this, &Widget::onFriendRequestReceived);
|
||||
connect(core, &Core::friendMessageReceived, this, &Widget::onFriendMessageReceived);
|
||||
connect(core, &Core::receiptRecieved, this, &Widget::onReceiptRecieved);
|
||||
connect(core, &Core::groupInviteReceived, this, &Widget::onGroupInviteReceived);
|
||||
connect(core, &Core::groupMessageReceived, this, &Widget::onGroupMessageReceived);
|
||||
connect(core, &Core::groupNamelistChanged, this, &Widget::onGroupNamelistChanged);
|
||||
|
@ -691,6 +692,11 @@ void Widget::onFriendStatusChanged(int friendId, Status status)
|
|||
f->getChatForm()->addSystemInfoMessage(tr("%1 is now %2", "e.g. \"Dubslow is now online\"").arg(f->getDisplayedName()).arg(fStatus),
|
||||
"white", QDateTime::currentDateTime());
|
||||
}
|
||||
|
||||
if (isActualChange && status != Status::Offline)
|
||||
{ // wait a little
|
||||
QTimer::singleShot(250, f->getChatForm(), SLOT(deliverOfflineMsgs()));
|
||||
}
|
||||
}
|
||||
|
||||
void Widget::onFriendStatusMessageChanged(int friendId, const QString& message)
|
||||
|
@ -737,12 +743,12 @@ void Widget::onFriendMessageReceived(int friendId, const QString& message, bool
|
|||
return;
|
||||
|
||||
QDateTime timestamp = QDateTime::currentDateTime();
|
||||
f->getChatForm()->addMessage(f->getToxID(), message, isAction, timestamp);
|
||||
f->getChatForm()->addMessage(f->getToxID(), message, isAction, timestamp, true);
|
||||
|
||||
if (isAction)
|
||||
HistoryKeeper::getInstance()->addChatEntry(f->getToxID().publicKey, "/me " + message, f->getToxID().publicKey, timestamp);
|
||||
HistoryKeeper::getInstance()->addChatEntry(f->getToxID().publicKey, "/me " + message, f->getToxID().publicKey, timestamp, true);
|
||||
else
|
||||
HistoryKeeper::getInstance()->addChatEntry(f->getToxID().publicKey, message, f->getToxID().publicKey, timestamp);
|
||||
HistoryKeeper::getInstance()->addChatEntry(f->getToxID().publicKey, message, f->getToxID().publicKey, timestamp, true);
|
||||
|
||||
if (activeChatroomWidget != nullptr)
|
||||
{
|
||||
|
@ -761,6 +767,15 @@ void Widget::onFriendMessageReceived(int friendId, const QString& message, bool
|
|||
f->getFriendWidget()->updateStatusLight();
|
||||
}
|
||||
|
||||
void Widget::onReceiptRecieved(int friendId, int receipt)
|
||||
{
|
||||
Friend* f = FriendList::findFriend(friendId);
|
||||
if (!f)
|
||||
return;
|
||||
|
||||
f->getChatForm()->dischargeReceipt(receipt);
|
||||
}
|
||||
|
||||
void Widget::newMessageAlert(GenericChatroomWidget* chat)
|
||||
{
|
||||
QApplication::alert(this);
|
||||
|
@ -1047,12 +1062,10 @@ void Widget::setStatusBusy()
|
|||
void Widget::onMessageSendResult(int friendId, const QString& message, int messageId)
|
||||
{
|
||||
Q_UNUSED(message)
|
||||
Q_UNUSED(messageId)
|
||||
Friend* f = FriendList::findFriend(friendId);
|
||||
if (!f)
|
||||
return;
|
||||
|
||||
if (!messageId)
|
||||
f->getChatForm()->addSystemInfoMessage(tr("Message failed to send"), "red", QDateTime::currentDateTime());
|
||||
}
|
||||
|
||||
void Widget::onGroupSendResult(int groupId, const QString& message, int result)
|
||||
|
@ -1129,3 +1142,12 @@ bool Widget::askMsgboxQuestion(const QString& title, const QString& msg)
|
|||
return QMessageBox::question(this, title, msg) == QMessageBox::StandardButton::Yes;
|
||||
}
|
||||
}
|
||||
|
||||
void Widget::clearAllReceipts()
|
||||
{
|
||||
QList<Friend*> frnds = FriendList::getAllFriends();
|
||||
for (Friend *f : frnds)
|
||||
{
|
||||
f->getChatForm()->clearReciepts();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -73,6 +73,7 @@ public:
|
|||
virtual void closeEvent(QCloseEvent *event);
|
||||
virtual void changeEvent(QEvent *event);
|
||||
|
||||
void clearAllReceipts();
|
||||
|
||||
public slots:
|
||||
void onSettingsClicked();
|
||||
|
@ -109,6 +110,7 @@ private slots:
|
|||
void onChatroomWidgetClicked(GenericChatroomWidget *);
|
||||
void onFriendMessageReceived(int friendId, const QString& message, bool isAction);
|
||||
void onFriendRequestReceived(const QString& userId, const QString& message);
|
||||
void onReceiptRecieved(int friendId, int receipt);
|
||||
void onEmptyGroupCreated(int groupId);
|
||||
void onGroupInviteReceived(int32_t friendId, const uint8_t *publicKey,uint16_t length);
|
||||
void onGroupMessageReceived(int groupnumber, const QString& message, const QString& author, bool isAction);
|
||||
|
|
Loading…
Reference in New Issue
Block a user