fix for presences in MUCs, fix for memory limit in message history, fix for message line resizing, started working on messages

This commit is contained in:
Blue 2019-09-10 17:33:39 +03:00
parent 139c0de0e3
commit 0574d6f72b
15 changed files with 332 additions and 95 deletions

View File

@ -468,6 +468,7 @@ void Core::Account::logMessage(const QXmppMessage& msg, const QString& reason)
qDebug() << "- state: " << msg.state();
qDebug() << "- stamp: " << msg.stamp();
qDebug() << "- id: " << msg.id();
qDebug() << "- outOfBandUrl: " << msg.outOfBandUrl();
qDebug() << "- isAttentionRequested: " << msg.isAttentionRequested();
qDebug() << "- isReceiptRequested: " << msg.isReceiptRequested();
qDebug() << "- receiptId: " << msg.receiptId();
@ -607,6 +608,7 @@ void Core::Account::initializeMessage(Shared::Message& target, const QXmppMessag
target.setTo(source.to());
target.setBody(source.body());
target.setForwarded(forwarded);
target.setOutOfBandUrl(source.outOfBandUrl());
if (guessing) {
if (target.getFromJid() == getLogin() + "@" + getServer()) {
outgoing = true;
@ -624,7 +626,7 @@ void Core::Account::initializeMessage(Shared::Message& target, const QXmppMessag
void Core::Account::onMamMessageReceived(const QString& queryId, const QXmppMessage& msg)
{
if (msg.id().size() > 0 && msg.body().size() > 0) {
if (msg.id().size() > 0 && (msg.body().size() > 0 || msg.outOfBandUrl().size() > 0)) {
std::map<QString, QString>::const_iterator itr = achiveQueries.find(queryId);
QString jid = itr->second;
RosterItem* item = 0;

View File

@ -57,6 +57,7 @@ void Core::Archive::open(const QString& account)
}
mdb_env_set_maxdbs(environment, 4);
mdb_env_set_mapsize(environment, 1UL * 1024UL * 1024UL * 1024UL);
mdb_env_open(environment, path.toStdString().c_str(), 0, 0664);
MDB_txn *txn;

View File

@ -137,7 +137,7 @@ void Core::Conference::onRoomParticipantAdded(const QString& p_name)
if (resource == jid) {
qDebug() << "Room" << jid << "is reporting of adding itself to the list participants. Not sure what to do with that yet, skipping";
} else {
QXmppPresence pres = room->participantPresence(jid);
QXmppPresence pres = room->participantPresence(p_name);
QDateTime lastInteraction = pres.lastUserInteraction();
if (!lastInteraction.isValid()) {
lastInteraction = QDateTime::currentDateTime();
@ -161,7 +161,7 @@ void Core::Conference::onRoomParticipantChanged(const QString& p_name)
if (resource == jid) {
qDebug() << "Room" << jid << "is reporting of changing his own presence. Not sure what to do with that yet, skipping";
} else {
QXmppPresence pres = room->participantPresence(jid);
QXmppPresence pres = room->participantPresence(p_name);
QDateTime lastInteraction = pres.lastUserInteraction();
if (!lastInteraction.isValid()) {
lastInteraction = QDateTime::currentDateTime();

View File

@ -71,7 +71,7 @@ void Core::RosterItem::setName(const QString& n)
void Core::RosterItem::addMessageToArchive(const Shared::Message& msg)
{
if (msg.getId().size() > 0 && msg.getBody().size() > 0) {
if (msg.storable()) {
hisoryCache.push_back(msg);
}
}
@ -184,7 +184,7 @@ void Core::RosterItem::appendMessageToArchive(const Shared::Message& msg)
{
const QString& id = msg.getId();
if (id.size() > 0) {
if (msg.getBody().size() > 0) {
if (msg.storable()) {
switch (archiveState) {
case empty:
if (archive->addElement(msg)) {

View File

@ -240,6 +240,7 @@ void Shared::Message::serialize(QDataStream& data) const
data << t;
data << outgoing;
data << forwarded;
data << oob;
}
void Shared::Message::deserialize(QDataStream& data)
@ -257,6 +258,7 @@ void Shared::Message::deserialize(QDataStream& data)
type = static_cast<Type>(t);
data >> outgoing;
data >> forwarded;
data >> oob;
}
QString Shared::generateUUID()
@ -274,6 +276,26 @@ void Shared::Message::setCurrentTime()
time = QDateTime::currentDateTime();
}
QString Shared::Message::getOutOfBandUrl() const
{
return oob;
}
bool Shared::Message::hasOutOfBandUrl() const
{
return oob.size() > 0;
}
void Shared::Message::setOutOfBandUrl(const QString& url)
{
oob = url;
}
bool Shared::Message::storable() const
{
return id.size() > 0 && (body.size() > 0 || oob.size()) > 0;
}
QIcon Shared::availabilityIcon(Shared::Availability av, bool big)
{
const std::deque<QString>& fallback = QApplication::palette().window().color().lightnessF() > 0.5 ?

View File

@ -128,6 +128,7 @@ public:
void setForwarded(bool fwd);
void setType(Type t);
void setCurrentTime();
void setOutOfBandUrl(const QString& url);
QString getFrom() const;
QString getFromJid() const;
@ -142,6 +143,9 @@ public:
bool getOutgoing() const;
bool getForwarded() const;
Type getType() const;
bool hasOutOfBandUrl() const;
bool storable() const;
QString getOutOfBandUrl() const;
QString getPenPalJid() const;
QString getPenPalResource() const;
@ -162,6 +166,7 @@ private:
Type type;
bool outgoing;
bool forwarded;
QString oob;
};
static const std::deque<QString> fallbackAvailabilityThemeIconsLightBig = {

View File

@ -36,7 +36,7 @@ int main(int argc, char *argv[])
QCoreApplication::setOrganizationName("Macaw");
QCoreApplication::setOrganizationDomain("macaw.me");
QCoreApplication::setApplicationName("Squawk");
QCoreApplication::setApplicationVersion("0.0.1");
QCoreApplication::setApplicationVersion("0.0.3");
QIcon icon;
icon.addFile(":images/logo.svg", QSize(16, 16));

View File

@ -30,6 +30,7 @@ set(squawkUI_SRC
widgets/accounts.cpp
widgets/account.cpp
widgets/joinconference.cpp
widgets/message.cpp
)
# Tell CMake to create the helloworld executable

View File

@ -35,6 +35,8 @@ Conversation::Conversation(bool muc, const QString& mJid, const QString mRes, co
line(new MessageLine(muc)),
m_ui(new Ui::Conversation()),
ker(),
res(),
vis(),
thread(),
statusIcon(0),
statusLabel(0),
@ -51,6 +53,9 @@ Conversation::Conversation(bool muc, const QString& mJid, const QString mRes, co
statusLabel = m_ui->statusLabel;
connect(&ker, SIGNAL(enterPressed()), this, SLOT(onEnterPressed()));
connect(&res, SIGNAL(resized()), this, SLOT(onScrollResize()));
connect(&vis, SIGNAL(shown()), this, SLOT(onScrollResize()));
connect(&vis, SIGNAL(hidden()), this, SLOT(onScrollResize()));
connect(m_ui->sendButton, SIGNAL(clicked(bool)), this, SLOT(onEnterPressed()));
connect(line, SIGNAL(resize(int)), this, SLOT(onMessagesResize(int)));
//connect(m_ui->attachButton, SIGNAL(clicked(bool)), this, SLOT(onAttach()));
@ -59,9 +64,11 @@ Conversation::Conversation(bool muc, const QString& mJid, const QString mRes, co
QScrollBar* vs = m_ui->scrollArea->verticalScrollBar();
m_ui->scrollArea->setWidget(line);
vs->installEventFilter(&vis);
vs->setBackgroundRole(QPalette::Base);
vs->setAutoFillBackground(true);
connect(vs, SIGNAL(valueChanged(int)), this, SLOT(onSliderValueChanged(int)));
m_ui->scrollArea->installEventFilter(&res);
applyVisualEffects();
}
@ -236,6 +243,7 @@ void Conversation::showEvent(QShowEvent* event)
emit shown();
QWidget::showEvent(event);
}
void Conversation::onAttach()
@ -262,3 +270,49 @@ void Conversation::setStatus(const QString& status)
{
statusLabel->setText(status);
}
void Conversation::onScrollResize()
{
if (everShown) {
int size = m_ui->scrollArea->width();
QScrollBar* bar = m_ui->scrollArea->verticalScrollBar();
if (bar->isVisible()) {
size -= bar->width();
}
line->setMaximumWidth(size);
}
}
Resizer::Resizer(QWidget* parent):
QObject(parent)
{
}
bool Resizer::eventFilter(QObject* obj, QEvent* event)
{
if (event->type() == QEvent::Resize) {
emit resized();
}
return false;
}
bool VisibilityCatcher::eventFilter(QObject* obj, QEvent* event)
{
if (event->type() == QEvent::Show) {
emit shown();
}
if (event->type() == QEvent::Hide) {
emit hidden();
}
return false;
}
VisibilityCatcher::VisibilityCatcher(QWidget* parent):
QObject(parent)
{
}

View File

@ -42,6 +42,31 @@ signals:
void enterPressed();
};
class Resizer : public QObject {
Q_OBJECT
public:
Resizer(QWidget* parent = nullptr);
protected:
bool eventFilter(QObject* obj, QEvent* event) override;
signals:
void resized();
};
class VisibilityCatcher : public QObject {
Q_OBJECT
public:
VisibilityCatcher(QWidget* parent = nullptr);
protected:
bool eventFilter(QObject* obj, QEvent* event) override;
signals:
void hidden();
void shown();
};
class Conversation : public QWidget
{
Q_OBJECT
@ -75,6 +100,7 @@ protected slots:
void onSliderValueChanged(int value);
void onAttach();
void onFileSelected();
void onScrollResize();
public:
const bool isMuc;
@ -93,6 +119,8 @@ protected:
MessageLine* line;
QScopedPointer<Ui::Conversation> m_ui;
KeyEnterReceiver ker;
Resizer res;
VisibilityCatcher vis;
QString thread;
QLabel* statusIcon;
QLabel* statusLabel;

View File

@ -191,7 +191,7 @@
<enum>Qt::ScrollBarAlwaysOff</enum>
</property>
<property name="sizeAdjustPolicy">
<enum>QAbstractScrollArea::AdjustToContents</enum>
<enum>QAbstractScrollArea::AdjustIgnored</enum>
</property>
<property name="widgetResizable">
<bool>true</bool>
@ -202,7 +202,7 @@
<x>0</x>
<y>0</y>
<width>572</width>
<height>116</height>
<height>123</height>
</rect>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_2">
@ -339,7 +339,8 @@
<string/>
</property>
<property name="icon">
<iconset theme="mail-attachment-symbolic"/>
<iconset theme="mail-attachment-symbolic">
<normaloff>.</normaloff>.</iconset>
</property>
<property name="flat">
<bool>true</bool>

89
ui/widgets/message.cpp Normal file
View File

@ -0,0 +1,89 @@
/*
* Squawk messenger.
* Copyright (C) 2019 Yury Gubich <blue@macaw.me>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <QDebug>
#include "message.h"
const QRegExp urlReg("^(?!<img\\ssrc=\")((?:https?|ftp)://\\S+)");
const QRegExp imgReg("((?:https?|ftp)://\\S+\\.(?:jpg|jpeg|png|svg|gif))");
Message::Message(const Shared::Message& source, bool outgoing, const QString& p_sender, QWidget* parent):
QHBoxLayout(parent),
msg(source),
body(new QWidget()),
bodyLayout(new QVBoxLayout(body)),
date(new QLabel(msg.getTime().toLocalTime().toString())),
sender(new QLabel(p_sender)),
text(new QLabel()),
shadow(new QGraphicsDropShadowEffect())
{
body->setBackgroundRole(QPalette::AlternateBase);
body->setAutoFillBackground(true);
QString bd = msg.getBody();
//bd.replace(imgReg, "<img src=\"\\1\"/>");
bd.replace(urlReg, "<a href=\"\\1\">\\1</a>");
text->setText(bd);;
text->setTextInteractionFlags(text->textInteractionFlags() | Qt::TextSelectableByMouse | Qt::LinksAccessibleByMouse);
text->setWordWrap(true);
text->setOpenExternalLinks(true);
QFont dFont = date->font();
dFont.setItalic(true);
dFont.setPointSize(dFont.pointSize() - 2);
date->setFont(dFont);
date->setForegroundRole(QPalette::ToolTipText);
QFont f;
f.setBold(true);
sender->setFont(f);
bodyLayout->addWidget(sender);
bodyLayout->addWidget(text);
bodyLayout->addWidget(date);
shadow->setBlurRadius(10);
shadow->setXOffset(1);
shadow->setYOffset(1);
shadow->setColor(Qt::black);
body->setGraphicsEffect(shadow);
if (outgoing) {
addWidget(body);
addStretch();
} else {
sender->setAlignment(Qt::AlignRight);
date->setAlignment(Qt::AlignRight);
addStretch();
addWidget(body);
}
}
Message::~Message()
{
}
QString Message::getId() const
{
return msg.getId();
}
void Message::setSender(const QString& p_sender)
{
sender->setText(p_sender);
}

53
ui/widgets/message.h Normal file
View File

@ -0,0 +1,53 @@
/*
* Squawk messenger.
* Copyright (C) 2019 Yury Gubich <blue@macaw.me>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef MESSAGE_H
#define MESSAGE_H
#include <QWidget>
#include <QHBoxLayout>
#include <QVBoxLayout>
#include <QLabel>
#include <QGraphicsDropShadowEffect>
#include "../../global.h"
/**
* @todo write docs
*/
class Message : public QHBoxLayout
{
Q_OBJECT
public:
Message(const Shared::Message& source, bool outgoing, const QString& sender, QWidget* parent = nullptr);
~Message();
void setSender(const QString& sender);
QString getId() const;
private:
Shared::Message msg;
QWidget* body;
QVBoxLayout* bodyLayout;
QLabel* date;
QLabel* sender;
QLabel* text;
QGraphicsDropShadowEffect* shadow;
};
#endif // MESSAGE_H

View File

@ -18,17 +18,15 @@
#include "messageline.h"
#include <QDebug>
#include <QGraphicsDropShadowEffect>
#include <cmath>
const QRegExp urlReg("^(?!<img\\ssrc=\")((?:https?|ftp)://\\S+)");
const QRegExp imgReg("((?:https?|ftp)://\\S+\\.(?:jpg|jpeg|png|svg|gif))");
MessageLine::MessageLine(bool p_room, QWidget* parent):
QWidget(parent),
messageIndex(),
messageOrder(),
layout(new QVBoxLayout()),
myMessages(),
palMessages(),
layout(new QVBoxLayout(this)),
myName(),
palNames(),
views(),
@ -40,7 +38,6 @@ MessageLine::MessageLine(bool p_room, QWidget* parent):
busyShown(false),
rotation()
{
setLayout(layout);
setBackgroundRole(QPalette::Base);
layout->addStretch();
@ -81,14 +78,56 @@ MessageLine::Position MessageLine::message(const Shared::Message& msg)
return invalid;
}
Shared::Message* copy = new Shared::Message(msg);
std::pair<Order::const_iterator, bool> result = messageOrder.insert(std::make_pair(msg.getTime(), copy));
QString sender;
bool outgoing;
if (room) {
if (msg.getFromResource() == myName) {
sender = myName;
outgoing = false;
} else {
sender = msg.getFromResource();
outgoing = true;
}
} else {
if (msg.getOutgoing()) {
sender = myName;
outgoing = false;
} else {
QString jid = msg.getFromJid();
std::map<QString, QString>::iterator itr = palNames.find(jid);
if (itr != palNames.end()) {
sender = itr->second;
} else {
sender = jid;
}
outgoing = true;
}
}
Message* message = new Message(msg, outgoing, sender);
std::pair<Order::const_iterator, bool> result = messageOrder.insert(std::make_pair(msg.getTime(), message));
if (!result.second) {
qDebug() << "Error appending a message into a message list - seems like the time of that message exactly matches the time of some other message, can't put them in order, skipping yet";
delete copy;
delete message;
return invalid;
}
messageIndex.insert(std::make_pair(id, copy));
if (outgoing) {
if (room) {
} else {
QString jid = msg.getFromJid();
std::map<QString, Index>::iterator pItr = palMessages.find(jid);
if (pItr == palMessages.end()) {
pItr = palMessages.insert(std::make_pair(jid, Index())).first;
}
pItr->second.insert(std::make_pair(id, message));
}
} else {
myMessages.insert(std::make_pair(id, message));
}
messageIndex.insert(std::make_pair(id, message));
int index = std::distance<Order::const_iterator>(messageOrder.begin(), result.first); //need to make with binary indexed tree
Position res = invalid;
if (index == 0) {
@ -103,83 +142,11 @@ MessageLine::Position MessageLine::message(const Shared::Message& msg)
index += 1;
}
QVBoxLayout* vBox = new QVBoxLayout();
QHBoxLayout* hBox = new QHBoxLayout();
QWidget* message = new QWidget();
message->setLayout(vBox);
message->setBackgroundRole(QPalette::AlternateBase);
message->setAutoFillBackground(true);
QString bd = msg.getBody();
//bd.replace(imgReg, "<img src=\"\\1\"/>");
bd.replace(urlReg, "<a href=\"\\1\">\\1</a>");
QLabel* body = new QLabel(bd);
body->setTextInteractionFlags(body->textInteractionFlags() | Qt::TextSelectableByMouse);
QLabel* sender = new QLabel();
QLabel* time = new QLabel(msg.getTime().toLocalTime().toString());
QFont dFont = time->font();
dFont.setItalic(true);
dFont.setPointSize(dFont.pointSize() - 2);
time->setFont(dFont);
time->setForegroundRole(QPalette::ToolTipText);
QFont f;
f.setBold(true);
sender->setFont(f);
body->setWordWrap(true);
body->setOpenExternalLinks(true);
vBox->addWidget(sender);
vBox->addWidget(body);
vBox->addWidget(time);
QGraphicsDropShadowEffect *effect = new QGraphicsDropShadowEffect;
effect->setBlurRadius(10);
effect->setXOffset(1);
effect->setYOffset(1);
effect->setColor(Qt::black);
message->setGraphicsEffect(effect);
if (room) {
if (msg.getFromResource() == myName) {
//body->setAlignment(Qt::AlignRight);
sender->setAlignment(Qt::AlignRight);
time->setAlignment(Qt::AlignRight);
sender->setText(myName);
hBox->addStretch();
hBox->addWidget(message);
} else {
sender->setText(msg.getFromResource());
hBox->addWidget(message);
hBox->addStretch();
}
} else {
if (msg.getOutgoing()) {
//body->setAlignment(Qt::AlignRight);
sender->setAlignment(Qt::AlignRight);
time->setAlignment(Qt::AlignRight);
sender->setText(myName);
hBox->addStretch();
hBox->addWidget(message);
} else {
QString jid = msg.getFromJid();
std::map<QString, QString>::iterator itr = palNames.find(jid);
if (itr != palNames.end()) {
sender->setText(itr->second);
} else {
sender->setText(jid);
}
hBox->addWidget(message);
hBox->addStretch();
}
}
if (res == end) {
layout->addLayout(hBox);
layout->addLayout(message);
} else {
layout->insertLayout(index, hBox);
layout->insertLayout(index, message);
}
return res;
@ -188,6 +155,9 @@ MessageLine::Position MessageLine::message(const Shared::Message& msg)
void MessageLine::setMyName(const QString& name)
{
myName = name;
for (Index::const_iterator itr = myMessages.begin(), end = myMessages.end(); itr != end; ++itr) {
itr->second->setSender(name);
}
}
void MessageLine::setPalName(const QString& jid, const QString& name)
@ -198,6 +168,13 @@ void MessageLine::setPalName(const QString& jid, const QString& name)
} else {
itr->second = name;
}
std::map<QString, Index>::iterator pItr = palMessages.find(jid);
if (pItr != palMessages.end()) {
for (Index::const_iterator itr = pItr->second.begin(), end = pItr->second.end(); itr != end; ++itr) {
itr->second->setSender(name);
}
}
}
void MessageLine::resizeEvent(QResizeEvent* event)

View File

@ -29,7 +29,9 @@
#include <QGraphicsView>
#include <QGraphicsPixmapItem>
#include <QVariantAnimation>
#include "../global.h"
#include "message.h"
class MessageLine : public QWidget
{
@ -66,10 +68,12 @@ private:
return a->getTime() < b->getTime();
}
};
typedef std::map<QDateTime, Shared::Message*> Order;
typedef std::map<QString, Shared::Message*> Index;
typedef std::map<QDateTime, Message*> Order;
typedef std::map<QString, Message*> Index;
Index messageIndex;
Order messageOrder;
Index myMessages;
std::map<QString, Index> palMessages;
QVBoxLayout* layout;
QString myName;