1
0
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:
Tux3 / Mlkj / !Lev.uXFMLA 2014-11-10 16:36:51 +01:00
commit 9e7ee848e8
No known key found for this signature in database
GPG Key ID: 7E086DD661263264
28 changed files with 438 additions and 128 deletions

View File

@ -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)

View File

@ -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"

View File

@ -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));
}

View File

@ -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

View File

@ -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;
}

View File

@ -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();

View File

@ -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);

View File

@ -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());
}
}

View File

@ -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

View File

@ -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;

View File

@ -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;

View File

@ -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());
}

View File

@ -53,6 +53,7 @@ private slots:
void onAutoSaveDirChange();
void onCheckUpdateChanged();
void onSetShowInFront();
void onFauxOfflineMessaging();
private:
Ui::GeneralSettings *bodyUI;

View File

@ -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">

View File

@ -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()

View File

@ -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;
}

View File

@ -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

View File

@ -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");

View File

@ -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;

View File

@ -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();
}

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -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();

View File

@ -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();
}
}

View File

@ -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);