forked from blue/squawk
encrypted messages now are displayed in the feed
This commit is contained in:
parent
637eb702a8
commit
0a530bfa93
34 changed files with 439 additions and 245 deletions
|
@ -24,12 +24,11 @@
|
|||
#include "shared/icons.h"
|
||||
#include "shared/global.h"
|
||||
|
||||
namespace Ui
|
||||
{
|
||||
namespace Ui {
|
||||
class Chat;
|
||||
}
|
||||
class Chat : public Conversation
|
||||
{
|
||||
|
||||
class Chat : public Conversation {
|
||||
Q_OBJECT
|
||||
public:
|
||||
Chat(Models::Account* acc, Models::Contact* p_contact, QWidget* parent = 0);
|
||||
|
|
|
@ -120,6 +120,7 @@ Conversation::~Conversation() {
|
|||
delete contextMenu;
|
||||
|
||||
element->feed->decrementObservers();
|
||||
delete m_ui;
|
||||
}
|
||||
|
||||
void Conversation::onAccountChanged(Models::Item* item, int row, int col) {
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#define CONVERSATION_H
|
||||
|
||||
#include <QWidget>
|
||||
#include <QObject>
|
||||
#include <QScopedPointer>
|
||||
#include <QMap>
|
||||
#include <QMimeData>
|
||||
|
@ -134,7 +135,7 @@ protected:
|
|||
Models::Element* element;
|
||||
QString palJid;
|
||||
QString activePalResource;
|
||||
QScopedPointer<Ui::Conversation> m_ui;
|
||||
Ui::Conversation* m_ui;
|
||||
KeyEnterReceiver ker;
|
||||
QString thread;
|
||||
QLabel* statusIcon;
|
||||
|
|
|
@ -14,5 +14,4 @@ set(HEADER_FILES
|
|||
|
||||
target_sources(squawk PRIVATE
|
||||
${SOURCE_FILES}
|
||||
${HEADER_FILES}
|
||||
)
|
||||
|
|
|
@ -47,22 +47,23 @@ MessageDelegate::MessageDelegate(QObject* parent):
|
|||
dateFont(Shared::Global::getInstance()->smallFont),
|
||||
nickMetrics(Shared::Global::getInstance()->headerFontMetrics),
|
||||
dateMetrics(Shared::Global::getInstance()->smallFontMetrics),
|
||||
bodyRenderer(new QTextDocument()),
|
||||
bodyRenderer(),
|
||||
buttonHeight(0),
|
||||
buttonWidth(0),
|
||||
barHeight(0),
|
||||
buttons(new std::map<QString, FeedButton*>()),
|
||||
bars(new std::map<QString, QProgressBar*>()),
|
||||
statusIcons(new std::map<QString, QLabel*>()),
|
||||
pencilIcons(new std::map<QString, QLabel*>()),
|
||||
previews(new std::map<QString, Preview*>()),
|
||||
idsToKeep(new std::set<QString>()),
|
||||
buttons(),
|
||||
bars(),
|
||||
statusIcons(),
|
||||
pencilIcons(),
|
||||
encryptionIcons(),
|
||||
previews(),
|
||||
idsToKeep(),
|
||||
clearingWidgets(false),
|
||||
currentId(""),
|
||||
selection(0, 0)
|
||||
{
|
||||
bodyRenderer->setDocumentMargin(0);
|
||||
bodyRenderer->setDefaultFont(bodyFont);
|
||||
bodyRenderer.setDocumentMargin(0);
|
||||
bodyRenderer.setDefaultFont(bodyFont);
|
||||
|
||||
QPushButton btn(QCoreApplication::translate("MessageLine", "Download"));
|
||||
buttonHeight = btn.sizeHint().height();
|
||||
|
@ -73,28 +74,23 @@ MessageDelegate::MessageDelegate(QObject* parent):
|
|||
}
|
||||
|
||||
MessageDelegate::~MessageDelegate() {
|
||||
for (const std::pair<const QString, FeedButton*>& pair: *buttons)
|
||||
for (const std::pair<const QString, FeedButton*>& pair: buttons)
|
||||
delete pair.second;
|
||||
|
||||
for (const std::pair<const QString, QProgressBar*>& pair: *bars)
|
||||
for (const std::pair<const QString, QProgressBar*>& pair: bars)
|
||||
delete pair.second;
|
||||
|
||||
for (const std::pair<const QString, QLabel*>& pair: *statusIcons)
|
||||
for (const std::pair<const QString, QLabel*>& pair: statusIcons)
|
||||
delete pair.second;
|
||||
|
||||
for (const std::pair<const QString, QLabel*>& pair: *pencilIcons)
|
||||
for (const std::pair<const QString, QLabel*>& pair: pencilIcons)
|
||||
delete pair.second;
|
||||
|
||||
for (const std::pair<const QString, QLabel*>& pair: encryptionIcons)
|
||||
delete pair.second;
|
||||
|
||||
for (const std::pair<const QString, Preview*>& pair: *previews)
|
||||
for (const std::pair<const QString, Preview*>& pair: previews)
|
||||
delete pair.second;
|
||||
|
||||
delete statusIcons;
|
||||
delete pencilIcons;
|
||||
delete idsToKeep;
|
||||
delete buttons;
|
||||
delete bars;
|
||||
delete previews;
|
||||
delete bodyRenderer;
|
||||
}
|
||||
|
||||
void MessageDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const {
|
||||
|
@ -168,6 +164,7 @@ void MessageDelegate::paint(QPainter* painter, const QStyleOptionViewItem& optio
|
|||
painter->setPen(q);
|
||||
painter->drawText(opt.rect, opt.displayAlignment, dateString, &rect);
|
||||
int currentY = opt.rect.y();
|
||||
int statusOffset = statusIconSize;
|
||||
if (data.sentByMe) {
|
||||
QLabel* statusIcon = getStatusIcon(data);
|
||||
|
||||
|
@ -176,30 +173,43 @@ void MessageDelegate::paint(QPainter* painter, const QStyleOptionViewItem& optio
|
|||
statusIcon->show();
|
||||
|
||||
opt.rect.adjust(0, statusIconSize + textMargin, 0, 0);
|
||||
statusOffset = statusIconSize + margin;
|
||||
}
|
||||
|
||||
if (data.correction.corrected) {
|
||||
QLabel* pencilIcon = getPencilIcon(data);
|
||||
|
||||
pencilIcon->setParent(vp);
|
||||
if (data.sentByMe)
|
||||
pencilIcon->move(opt.rect.left() + statusIconSize + margin, currentY);
|
||||
pencilIcon->move(opt.rect.left() + statusOffset, currentY);
|
||||
else
|
||||
pencilIcon->move(opt.rect.right() - statusIconSize - margin, currentY);
|
||||
pencilIcon->move(opt.rect.right() - statusOffset, currentY);
|
||||
|
||||
pencilIcon->show();
|
||||
statusOffset += statusIconSize + margin;
|
||||
} else {
|
||||
std::map<QString, QLabel*>::const_iterator itr = pencilIcons->find(data.id);
|
||||
if (itr != pencilIcons->end()) {
|
||||
std::map<QString, QLabel*>::const_iterator itr = pencilIcons.find(data.id);
|
||||
if (itr != pencilIcons.end()) {
|
||||
delete itr->second;
|
||||
pencilIcons->erase(itr);
|
||||
pencilIcons.erase(itr);
|
||||
}
|
||||
}
|
||||
|
||||
if (data.encryption != Shared::EncryptionProtocol::none) {
|
||||
QLabel* shieldIcon = getEncryptionIcon(data);
|
||||
shieldIcon->setParent(vp);
|
||||
if (data.sentByMe)
|
||||
shieldIcon->move(opt.rect.left() + statusOffset, currentY);
|
||||
else
|
||||
shieldIcon->move(opt.rect.right() - statusOffset, currentY);
|
||||
|
||||
shieldIcon->show();
|
||||
statusOffset += statusIconSize + margin;
|
||||
}
|
||||
|
||||
painter->restore();
|
||||
|
||||
if (clearingWidgets)
|
||||
idsToKeep->insert(data.id);
|
||||
idsToKeep.insert(data.id);
|
||||
}
|
||||
|
||||
void MessageDelegate::paintBubble(const Models::FeedItem& data, QPainter* painter, const QStyleOptionViewItem& option) const {
|
||||
|
@ -281,11 +291,11 @@ QSize MessageDelegate::sizeHint(const QStyleOptionViewItem& option, const QModel
|
|||
Models::FeedItem data = qvariant_cast<Models::FeedItem>(vi);
|
||||
QSize messageSize(0, 0);
|
||||
if (data.text.size() > 0) {
|
||||
bodyRenderer->setPlainText(data.text);
|
||||
bodyRenderer->setTextWidth(messageRect.size().width());
|
||||
bodyRenderer.setPlainText(data.text);
|
||||
bodyRenderer.setTextWidth(messageRect.size().width());
|
||||
|
||||
QSizeF size = bodyRenderer->size();
|
||||
size.setWidth(bodyRenderer->idealWidth());
|
||||
QSizeF size = bodyRenderer.size();
|
||||
size.setWidth(bodyRenderer.idealWidth());
|
||||
messageSize = QSize(std::ceil(size.width()), std::ceil(size.height()));
|
||||
messageSize.rheight() += textMargin;
|
||||
}
|
||||
|
@ -338,9 +348,12 @@ QSize MessageDelegate::sizeHint(const QStyleOptionViewItem& option, const QModel
|
|||
messageSize.rheight() += dateSize.height() > statusIconSize ? dateSize.height() : statusIconSize;
|
||||
|
||||
int statusWidth = dateSize.width() + statusIconSize + margin;
|
||||
if (data.correction.corrected) {
|
||||
if (data.correction.corrected)
|
||||
statusWidth += statusIconSize + margin;
|
||||
}
|
||||
|
||||
if (data.encryption != Shared::EncryptionProtocol::none)
|
||||
statusWidth += statusIconSize + margin;
|
||||
|
||||
messageSize.setWidth(std::max(statusWidth, messageSize.width()));
|
||||
messageSize.rwidth() += 2 * bubbleMargin;
|
||||
|
||||
|
@ -399,10 +412,10 @@ QString MessageDelegate::getAnchor(const QPoint& point, const QModelIndex& index
|
|||
if (localHint.contains(point)) {
|
||||
QPoint translated = point - localHint.topLeft();
|
||||
|
||||
bodyRenderer->setHtml(Shared::processMessageBody(data.text));
|
||||
bodyRenderer->setTextWidth(localHint.size().width());
|
||||
bodyRenderer.setHtml(Shared::processMessageBody(data.text));
|
||||
bodyRenderer.setTextWidth(localHint.size().width());
|
||||
|
||||
return bodyRenderer->documentLayout()->anchorAt(translated);
|
||||
return bodyRenderer.documentLayout()->anchorAt(translated);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -424,13 +437,13 @@ QString MessageDelegate::leftDoubleClick(const QPoint& point, const QModelIndex&
|
|||
if (localHint.contains(point)) {
|
||||
QPoint translated = point - localHint.topLeft();
|
||||
|
||||
bodyRenderer->setHtml(Shared::processMessageBody(data.text));
|
||||
bodyRenderer->setTextWidth(localHint.size().width());
|
||||
bodyRenderer.setHtml(Shared::processMessageBody(data.text));
|
||||
bodyRenderer.setTextWidth(localHint.size().width());
|
||||
|
||||
QAbstractTextDocumentLayout* lay = bodyRenderer->documentLayout();
|
||||
QAbstractTextDocumentLayout* lay = bodyRenderer.documentLayout();
|
||||
|
||||
int position = lay->hitTest(translated, Qt::HitTestAccuracy::FuzzyHit);
|
||||
QTextCursor cursor(bodyRenderer);
|
||||
QTextCursor cursor(&bodyRenderer);
|
||||
cursor.setPosition(position, QTextCursor::MoveAnchor);
|
||||
cursor.movePosition(QTextCursor::StartOfWord, QTextCursor::MoveAnchor);
|
||||
cursor.movePosition(QTextCursor::EndOfWord, QTextCursor::KeepAnchor);
|
||||
|
@ -456,10 +469,10 @@ Shared::Hover MessageDelegate::hoverType(const QPoint& point, const QModelIndex&
|
|||
if (localHint.contains(point)) {
|
||||
QPoint translated = point - localHint.topLeft();
|
||||
|
||||
bodyRenderer->setHtml(Shared::processMessageBody(data.text));
|
||||
bodyRenderer->setTextWidth(localHint.size().width());
|
||||
bodyRenderer.setHtml(Shared::processMessageBody(data.text));
|
||||
bodyRenderer.setTextWidth(localHint.size().width());
|
||||
|
||||
QAbstractTextDocumentLayout* lay = bodyRenderer->documentLayout();
|
||||
QAbstractTextDocumentLayout* lay = bodyRenderer.documentLayout();
|
||||
QString anchor = lay->anchorAt(translated);
|
||||
|
||||
if (anchor.size() > 0) {
|
||||
|
@ -489,15 +502,15 @@ QString MessageDelegate::mouseDrag(const QPoint& start, const QPoint& end, const
|
|||
last.setY(std::max(last.y(), 0));
|
||||
last.setY(std::min(last.y(), localHint.height()));
|
||||
|
||||
bodyRenderer->setHtml(Shared::processMessageBody(data.text));
|
||||
bodyRenderer->setTextWidth(localHint.size().width());
|
||||
selection.first = bodyRenderer->documentLayout()->hitTest(first, Qt::HitTestAccuracy::FuzzyHit);
|
||||
selection.second = bodyRenderer->documentLayout()->hitTest(last, Qt::HitTestAccuracy::FuzzyHit);
|
||||
bodyRenderer.setHtml(Shared::processMessageBody(data.text));
|
||||
bodyRenderer.setTextWidth(localHint.size().width());
|
||||
selection.first = bodyRenderer.documentLayout()->hitTest(first, Qt::HitTestAccuracy::FuzzyHit);
|
||||
selection.second = bodyRenderer.documentLayout()->hitTest(last, Qt::HitTestAccuracy::FuzzyHit);
|
||||
|
||||
currentId = data.id;
|
||||
|
||||
if (selection.first != selection.second) {
|
||||
QTextCursor cursor(bodyRenderer);
|
||||
QTextCursor cursor(&bodyRenderer);
|
||||
cursor.setPosition(selection.first, QTextCursor::MoveAnchor);
|
||||
cursor.setPosition(selection.second, QTextCursor::KeepAnchor);
|
||||
return cursor.selectedText();
|
||||
|
@ -562,17 +575,17 @@ int MessageDelegate::paintBar(QProgressBar* bar, QPainter* painter, bool sentByM
|
|||
|
||||
int MessageDelegate::paintPreview(const Models::FeedItem& data, QPainter* painter, QStyleOptionViewItem& option) const {
|
||||
Preview* preview = 0;
|
||||
std::map<QString, Preview*>::iterator itr = previews->find(data.id);
|
||||
std::map<QString, Preview*>::iterator itr = previews.find(data.id);
|
||||
|
||||
QSize size = option.rect.size();
|
||||
QString path = Shared::resolvePath(data.attach.localPath);
|
||||
if (itr != previews->end()) {
|
||||
if (itr != previews.end()) {
|
||||
preview = itr->second;
|
||||
preview->actualize(path, size, option.rect.topLeft());
|
||||
} else {
|
||||
QWidget* vp = static_cast<QWidget*>(painter->device());
|
||||
preview = new Preview(path, size, option.rect.topLeft(), vp);
|
||||
previews->insert(std::make_pair(data.id, preview));
|
||||
previews.insert(std::make_pair(data.id, preview));
|
||||
}
|
||||
|
||||
if (!preview->isFileReachable()) //this is the situation when the file preview couldn't be painted because the file was moved
|
||||
|
@ -585,15 +598,15 @@ int MessageDelegate::paintPreview(const Models::FeedItem& data, QPainter* painte
|
|||
}
|
||||
|
||||
QPushButton * MessageDelegate::getButton(const Models::FeedItem& data) const {
|
||||
std::map<QString, FeedButton*>::const_iterator itr = buttons->find(data.id);
|
||||
std::map<QString, FeedButton*>::const_iterator itr = buttons.find(data.id);
|
||||
FeedButton* result = 0;
|
||||
if (itr != buttons->end()) {
|
||||
if (itr != buttons.end()) {
|
||||
result = itr->second;
|
||||
} else {
|
||||
std::map<QString, QProgressBar*>::const_iterator barItr = bars->find(data.id);
|
||||
if (barItr != bars->end()) {
|
||||
std::map<QString, QProgressBar*>::const_iterator barItr = bars.find(data.id);
|
||||
if (barItr != bars.end()) {
|
||||
delete barItr->second;
|
||||
bars->erase(barItr);
|
||||
bars.erase(barItr);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -601,7 +614,7 @@ QPushButton * MessageDelegate::getButton(const Models::FeedItem& data) const {
|
|||
result = new FeedButton();
|
||||
result->messageId = data.id;
|
||||
result->setText(QCoreApplication::translate("MessageLine", "Download"));
|
||||
buttons->insert(std::make_pair(data.id, result));
|
||||
buttons.insert(std::make_pair(data.id, result));
|
||||
connect(result, &QPushButton::clicked, this, &MessageDelegate::onButtonPushed);
|
||||
}
|
||||
|
||||
|
@ -609,22 +622,22 @@ QPushButton * MessageDelegate::getButton(const Models::FeedItem& data) const {
|
|||
}
|
||||
|
||||
QProgressBar * MessageDelegate::getBar(const Models::FeedItem& data) const {
|
||||
std::map<QString, QProgressBar*>::const_iterator barItr = bars->find(data.id);
|
||||
std::map<QString, QProgressBar*>::const_iterator barItr = bars.find(data.id);
|
||||
QProgressBar* result = 0;
|
||||
if (barItr != bars->end()) {
|
||||
if (barItr != bars.end()) {
|
||||
result = barItr->second;
|
||||
} else {
|
||||
std::map<QString, FeedButton*>::const_iterator itr = buttons->find(data.id);
|
||||
if (itr != buttons->end()) {
|
||||
std::map<QString, FeedButton*>::const_iterator itr = buttons.find(data.id);
|
||||
if (itr != buttons.end()) {
|
||||
delete itr->second;
|
||||
buttons->erase(itr);
|
||||
buttons.erase(itr);
|
||||
}
|
||||
}
|
||||
|
||||
if (result == 0) {
|
||||
result = new QProgressBar();
|
||||
result->setRange(0, 100);
|
||||
bars->insert(std::make_pair(data.id, result));
|
||||
bars.insert(std::make_pair(data.id, result));
|
||||
}
|
||||
|
||||
result->setValue(data.attach.progress * 100);
|
||||
|
@ -633,14 +646,14 @@ QProgressBar * MessageDelegate::getBar(const Models::FeedItem& data) const {
|
|||
}
|
||||
|
||||
QLabel * MessageDelegate::getStatusIcon(const Models::FeedItem& data) const {
|
||||
std::map<QString, QLabel*>::const_iterator itr = statusIcons->find(data.id);
|
||||
std::map<QString, QLabel*>::const_iterator itr = statusIcons.find(data.id);
|
||||
QLabel* result = 0;
|
||||
|
||||
if (itr != statusIcons->end()) {
|
||||
if (itr != statusIcons.end()) {
|
||||
result = itr->second;
|
||||
} else {
|
||||
result = new QLabel();
|
||||
statusIcons->insert(std::make_pair(data.id, result));
|
||||
statusIcons.insert(std::make_pair(data.id, result));
|
||||
}
|
||||
|
||||
QIcon q(Shared::icon(Shared::messageStateThemeIcons[static_cast<uint8_t>(data.state)]));
|
||||
|
@ -657,17 +670,17 @@ QLabel * MessageDelegate::getStatusIcon(const Models::FeedItem& data) const {
|
|||
return result;
|
||||
}
|
||||
|
||||
QLabel * MessageDelegate::getPencilIcon(const Models::FeedItem& data) const {
|
||||
std::map<QString, QLabel*>::const_iterator itr = pencilIcons->find(data.id);
|
||||
QLabel* MessageDelegate::getPencilIcon(const Models::FeedItem& data) const {
|
||||
std::map<QString, QLabel*>::const_iterator itr = pencilIcons.find(data.id);
|
||||
QLabel* result = 0;
|
||||
|
||||
if (itr != pencilIcons->end()) {
|
||||
if (itr != pencilIcons.end()) {
|
||||
result = itr->second;
|
||||
} else {
|
||||
result = new QLabel();
|
||||
QIcon icon = Shared::icon("edit-rename");
|
||||
result->setPixmap(icon.pixmap(statusIconSize));
|
||||
pencilIcons->insert(std::make_pair(data.id, result));
|
||||
pencilIcons.insert(std::make_pair(data.id, result));
|
||||
}
|
||||
|
||||
result->setToolTip("Last time edited: " + data.correction.lastCorrection.toLocalTime().toString()
|
||||
|
@ -676,30 +689,46 @@ QLabel * MessageDelegate::getPencilIcon(const Models::FeedItem& data) const {
|
|||
return result;
|
||||
}
|
||||
|
||||
QLabel* MessageDelegate::getEncryptionIcon(const Models::FeedItem& data) const {
|
||||
std::map<QString, QLabel*>::const_iterator itr = encryptionIcons.find(data.id);
|
||||
QLabel* result = 0;
|
||||
|
||||
if (itr != encryptionIcons.end()) {
|
||||
result = itr->second;
|
||||
} else {
|
||||
result = new QLabel();
|
||||
QIcon icon = Shared::icon("secure");
|
||||
result->setPixmap(icon.pixmap(statusIconSize));
|
||||
encryptionIcons.insert(std::make_pair(data.id, result));
|
||||
result->setToolTip("Encrypted: " + Shared::Global::getName(data.encryption));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void removeElements(std::map<QString, T*>* elements, std::set<QString>* idsToKeep) {
|
||||
void removeElements(std::map<QString, T*>& elements, std::set<QString>& idsToKeep) {
|
||||
std::set<QString> toRemove;
|
||||
for (const std::pair<const QString, T*>& pair: *elements) {
|
||||
if (idsToKeep->find(pair.first) == idsToKeep->end()) {
|
||||
for (const std::pair<const QString, T*>& pair: elements) {
|
||||
if (idsToKeep.find(pair.first) == idsToKeep.end()) {
|
||||
delete pair.second;
|
||||
toRemove.insert(pair.first);
|
||||
}
|
||||
}
|
||||
for (const QString& key : toRemove) {
|
||||
elements->erase(key);
|
||||
}
|
||||
for (const QString& key : toRemove)
|
||||
elements.erase(key);
|
||||
}
|
||||
|
||||
int MessageDelegate::paintBody(const Models::FeedItem& data, QPainter* painter, QStyleOptionViewItem& option) const
|
||||
{
|
||||
if (data.text.size() > 0) {
|
||||
bodyRenderer->setHtml(Shared::processMessageBody(data.text));
|
||||
bodyRenderer->setTextWidth(option.rect.size().width());
|
||||
bodyRenderer.setHtml(Shared::processMessageBody(data.text));
|
||||
bodyRenderer.setTextWidth(option.rect.size().width());
|
||||
painter->save();
|
||||
painter->translate(option.rect.topLeft());
|
||||
|
||||
if (data.id == currentId) {
|
||||
QTextCursor cursor(bodyRenderer);
|
||||
QTextCursor cursor(&bodyRenderer);
|
||||
cursor.setPosition(selection.first, QTextCursor::MoveAnchor);
|
||||
cursor.setPosition(selection.second, QTextCursor::KeepAnchor);
|
||||
QTextCharFormat format = cursor.charFormat();
|
||||
|
@ -708,10 +737,10 @@ int MessageDelegate::paintBody(const Models::FeedItem& data, QPainter* painter,
|
|||
cursor.setCharFormat(format);
|
||||
}
|
||||
|
||||
bodyRenderer->drawContents(painter);
|
||||
bodyRenderer.drawContents(painter);
|
||||
|
||||
painter->restore();
|
||||
QSize bodySize(std::ceil(bodyRenderer->idealWidth()), std::ceil(bodyRenderer->size().height()));
|
||||
QSize bodySize(std::ceil(bodyRenderer.idealWidth()), std::ceil(bodyRenderer.size().height()));
|
||||
|
||||
option.rect.adjust(0, bodySize.height() + textMargin, 0, 0);
|
||||
return bodySize.width();
|
||||
|
@ -720,7 +749,7 @@ int MessageDelegate::paintBody(const Models::FeedItem& data, QPainter* painter,
|
|||
}
|
||||
|
||||
void MessageDelegate::beginClearWidgets() {
|
||||
idsToKeep->clear();
|
||||
idsToKeep.clear();
|
||||
clearingWidgets = true;
|
||||
}
|
||||
|
||||
|
@ -730,9 +759,10 @@ void MessageDelegate::endClearWidgets() {
|
|||
removeElements(bars, idsToKeep);
|
||||
removeElements(statusIcons, idsToKeep);
|
||||
removeElements(pencilIcons, idsToKeep);
|
||||
removeElements(encryptionIcons, idsToKeep);
|
||||
removeElements(previews, idsToKeep);
|
||||
|
||||
idsToKeep->clear();
|
||||
idsToKeep.clear();
|
||||
clearingWidgets = false;
|
||||
}
|
||||
}
|
||||
|
@ -743,15 +773,15 @@ void MessageDelegate::onButtonPushed() const {
|
|||
}
|
||||
|
||||
void MessageDelegate::clearHelperWidget(const Models::FeedItem& data) const {
|
||||
std::map<QString, FeedButton*>::const_iterator itr = buttons->find(data.id);
|
||||
if (itr != buttons->end()) {
|
||||
std::map<QString, FeedButton*>::const_iterator itr = buttons.find(data.id);
|
||||
if (itr != buttons.end()) {
|
||||
delete itr->second;
|
||||
buttons->erase(itr);
|
||||
buttons.erase(itr);
|
||||
} else {
|
||||
std::map<QString, QProgressBar*>::const_iterator barItr = bars->find(data.id);
|
||||
if (barItr != bars->end()) {
|
||||
std::map<QString, QProgressBar*>::const_iterator barItr = bars.find(data.id);
|
||||
if (barItr != bars.end()) {
|
||||
delete barItr->second;
|
||||
bars->erase(barItr);
|
||||
bars.erase(barItr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,23 +1,22 @@
|
|||
/*
|
||||
* Squawk messenger.
|
||||
* 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 MESSAGEDELEGATE_H
|
||||
#define MESSAGEDELEGATE_H
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
#include <set>
|
||||
|
@ -44,17 +43,16 @@ namespace Models {
|
|||
struct FeedItem;
|
||||
};
|
||||
|
||||
class MessageDelegate : public QStyledItemDelegate
|
||||
{
|
||||
class MessageDelegate : public QStyledItemDelegate {
|
||||
Q_OBJECT
|
||||
public:
|
||||
MessageDelegate(QObject *parent = nullptr);
|
||||
~MessageDelegate();
|
||||
|
||||
|
||||
void paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const override;
|
||||
QSize sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const override;
|
||||
//void setModelData(QWidget * editor, QAbstractItemModel * model, const QModelIndex & index) const override;
|
||||
|
||||
|
||||
bool editorEvent(QEvent * event, QAbstractItemModel * model, const QStyleOptionViewItem & option, const QModelIndex & index) override;
|
||||
void endClearWidgets();
|
||||
void beginClearWidgets();
|
||||
|
@ -66,12 +64,12 @@ public:
|
|||
|
||||
static int avatarHeight;
|
||||
static int margin;
|
||||
|
||||
|
||||
signals:
|
||||
void buttonPushed(const QString& messageId) const;
|
||||
void invalidPath(const QString& messageId) const;
|
||||
void openLink(const QString& href) const;
|
||||
|
||||
|
||||
protected:
|
||||
int paintButton(QPushButton* btn, QPainter* painter, bool sentByMe, QStyleOptionViewItem& option) const;
|
||||
int paintBar(QProgressBar* bar, QPainter* painter, bool sentByMe, QStyleOptionViewItem& option) const;
|
||||
|
@ -85,6 +83,7 @@ protected:
|
|||
QProgressBar* getBar(const Models::FeedItem& data) const;
|
||||
QLabel* getStatusIcon(const Models::FeedItem& data) const;
|
||||
QLabel* getPencilIcon(const Models::FeedItem& data) const;
|
||||
QLabel* getEncryptionIcon(const Models::FeedItem& data) const;
|
||||
void clearHelperWidget(const Models::FeedItem& data) const;
|
||||
|
||||
bool needToDrawAvatar(const QModelIndex& index, const Models::FeedItem& data, const QStyleOptionViewItem& option) const;
|
||||
|
@ -92,36 +91,35 @@ protected:
|
|||
|
||||
QRect getHoveredMessageBodyRect(const QModelIndex& index, const Models::FeedItem& data, const QRect& sizeHint) const;
|
||||
QString getAnchor(const QPoint& point, const QModelIndex& index, const QRect& sizeHint) const;
|
||||
|
||||
|
||||
protected slots:
|
||||
void onButtonPushed() const;
|
||||
|
||||
|
||||
private:
|
||||
class FeedButton : public QPushButton {
|
||||
public:
|
||||
QString messageId;
|
||||
};
|
||||
|
||||
|
||||
const QFont& bodyFont;
|
||||
const QFont& nickFont;
|
||||
const QFont& dateFont;
|
||||
const QFontMetrics& nickMetrics;
|
||||
const QFontMetrics& dateMetrics;
|
||||
QTextDocument* bodyRenderer;
|
||||
|
||||
mutable QTextDocument bodyRenderer;
|
||||
|
||||
int buttonHeight;
|
||||
int buttonWidth;
|
||||
int barHeight;
|
||||
|
||||
std::map<QString, FeedButton*>* buttons;
|
||||
std::map<QString, QProgressBar*>* bars;
|
||||
std::map<QString, QLabel*>* statusIcons;
|
||||
std::map<QString, QLabel*>* pencilIcons;
|
||||
std::map<QString, Preview*>* previews;
|
||||
std::set<QString>* idsToKeep;
|
||||
|
||||
mutable std::map<QString, FeedButton*> buttons;
|
||||
mutable std::map<QString, QProgressBar*> bars;
|
||||
mutable std::map<QString, QLabel*> statusIcons;
|
||||
mutable std::map<QString, QLabel*> pencilIcons;
|
||||
mutable std::map<QString, QLabel*> encryptionIcons;
|
||||
mutable std::map<QString, Preview*> previews;
|
||||
mutable std::set<QString> idsToKeep;
|
||||
bool clearingWidgets;
|
||||
QString currentId;
|
||||
std::pair<int, int> selection;
|
||||
};
|
||||
|
||||
#endif // MESSAGEDELEGATE_H
|
||||
|
|
|
@ -29,6 +29,7 @@ const QHash<int, QByteArray> Models::MessageFeed::roles = {
|
|||
{Sender, "sender"},
|
||||
{Date, "date"},
|
||||
{DeliveryState, "deliveryState"},
|
||||
{Encryption, "encryption"},
|
||||
{Correction, "correction"},
|
||||
{SentByMe,"sentByMe"},
|
||||
{Avatar, "avatar"},
|
||||
|
@ -51,20 +52,16 @@ Models::MessageFeed::MessageFeed(const Element* ri, QObject* parent):
|
|||
failedUploads(),
|
||||
unreadMessages(new std::set<QString>()),
|
||||
observersAmount(0)
|
||||
{
|
||||
}
|
||||
{}
|
||||
|
||||
Models::MessageFeed::~MessageFeed()
|
||||
{
|
||||
Models::MessageFeed::~MessageFeed() {
|
||||
delete unreadMessages;
|
||||
|
||||
for (Shared::Message* message : storage) {
|
||||
for (Shared::Message* message : storage)
|
||||
delete message;
|
||||
}
|
||||
}
|
||||
|
||||
void Models::MessageFeed::addMessage(const Shared::Message& msg)
|
||||
{
|
||||
void Models::MessageFeed::addMessage(const Shared::Message& msg) {
|
||||
QString id = msg.getId();
|
||||
StorageById::const_iterator itr = indexById.find(id);
|
||||
if (itr != indexById.end()) {
|
||||
|
@ -75,11 +72,11 @@ void Models::MessageFeed::addMessage(const Shared::Message& msg)
|
|||
Shared::Message* copy = new Shared::Message(msg);
|
||||
StorageByTime::const_iterator tItr = indexByTime.upper_bound(msg.getTime());
|
||||
int position;
|
||||
if (tItr == indexByTime.end()) {
|
||||
if (tItr == indexByTime.end())
|
||||
position = storage.size();
|
||||
} else {
|
||||
else
|
||||
position = indexByTime.rank(tItr);
|
||||
}
|
||||
|
||||
beginInsertRows(QModelIndex(), position, position);
|
||||
storage.insert(copy);
|
||||
endInsertRows();
|
||||
|
@ -93,8 +90,7 @@ void Models::MessageFeed::addMessage(const Shared::Message& msg)
|
|||
}
|
||||
}
|
||||
|
||||
void Models::MessageFeed::changeMessage(const QString& id, const QMap<QString, QVariant>& data)
|
||||
{
|
||||
void Models::MessageFeed::changeMessage(const QString& id, const QMap<QString, QVariant>& data) {
|
||||
StorageById::iterator itr = indexById.find(id);
|
||||
if (itr == indexById.end()) {
|
||||
qDebug() << "received a command to change a message, but the message couldn't be found, skipping";
|
||||
|
@ -159,9 +155,8 @@ void Models::MessageFeed::changeMessage(const QString& id, const QMap<QString, Q
|
|||
}
|
||||
|
||||
QVector<int> cr;
|
||||
for (MessageRoles role : changeRoles) {
|
||||
for (MessageRoles role : changeRoles)
|
||||
cr.push_back(role);
|
||||
}
|
||||
|
||||
emit dataChanged(index, index, cr);
|
||||
|
||||
|
@ -173,14 +168,15 @@ void Models::MessageFeed::changeMessage(const QString& id, const QMap<QString, Q
|
|||
}
|
||||
}
|
||||
|
||||
std::set<Models::MessageFeed::MessageRoles> Models::MessageFeed::detectChanges(const Shared::Message& msg, const QMap<QString, QVariant>& data) const
|
||||
{
|
||||
std::set<Models::MessageFeed::MessageRoles> Models::MessageFeed::detectChanges(
|
||||
const Shared::Message& msg,
|
||||
const QMap<QString, QVariant>& data
|
||||
) const {
|
||||
std::set<MessageRoles> roles;
|
||||
Shared::Message::State state = msg.getState();
|
||||
QMap<QString, QVariant>::const_iterator itr = data.find("state");
|
||||
if (itr != data.end() && static_cast<Shared::Message::State>(itr.value().toUInt()) != state) {
|
||||
if (itr != data.end() && static_cast<Shared::Message::State>(itr.value().toUInt()) != state)
|
||||
roles.insert(MessageRoles::DeliveryState);
|
||||
}
|
||||
|
||||
itr = data.find("outOfBandUrl");
|
||||
bool att = false;
|
||||
|
@ -255,9 +251,8 @@ QVariant Models::MessageFeed::data(const QModelIndex& index, int role) const {
|
|||
case Qt::DisplayRole:
|
||||
case Text: {
|
||||
QString body = msg->getBody();
|
||||
if (body != msg->getOutOfBandUrl()) {
|
||||
if (body != msg->getOutOfBandUrl())
|
||||
answer = body;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case Sender:
|
||||
|
@ -276,6 +271,9 @@ QVariant Models::MessageFeed::data(const QModelIndex& index, int role) const {
|
|||
case DeliveryState:
|
||||
answer = static_cast<unsigned int>(msg->getState());
|
||||
break;
|
||||
case Encryption:
|
||||
answer = QVariant::fromValue(msg->getEncryption());
|
||||
break;
|
||||
case Correction:
|
||||
answer.setValue(fillCorrection(*msg));;
|
||||
break;
|
||||
|
@ -318,13 +316,13 @@ QVariant Models::MessageFeed::data(const QModelIndex& index, int role) const {
|
|||
item.sentByMe = sentByMe(*msg);
|
||||
item.date = msg->getTime();
|
||||
item.state = msg->getState();
|
||||
item.encryption = msg->getEncryption();
|
||||
item.error = msg->getErrorText();
|
||||
item.correction = fillCorrection(*msg);
|
||||
|
||||
QString body = msg->getBody();
|
||||
if (body != msg->getOutOfBandUrl()) {
|
||||
if (body != msg->getOutOfBandUrl())
|
||||
item.text = body;
|
||||
}
|
||||
|
||||
item.avatar.clear();
|
||||
if (item.sentByMe) {
|
||||
|
@ -419,13 +417,11 @@ QModelIndex Models::MessageFeed::index(int row, int column, const QModelIndex& p
|
|||
return QModelIndex();
|
||||
|
||||
StorageByTime::iterator itr = indexByTime.nth(row);
|
||||
if (itr != indexByTime.end()) {
|
||||
Shared::Message* msg = *itr;
|
||||
|
||||
return createIndex(row, column, msg);
|
||||
} else {
|
||||
if (itr == indexByTime.end())
|
||||
return QModelIndex();
|
||||
}
|
||||
|
||||
Shared::Message* msg = *itr;
|
||||
return createIndex(row, column, msg);
|
||||
}
|
||||
|
||||
QHash<int, QByteArray> Models::MessageFeed::roleNames() const {return roles;}
|
||||
|
|
|
@ -16,12 +16,12 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef MESSAGEFEED_H
|
||||
#define MESSAGEFEED_H
|
||||
#pragma once
|
||||
|
||||
#include <QAbstractListModel>
|
||||
#include <QDateTime>
|
||||
#include <QString>
|
||||
#include <QHash>
|
||||
|
||||
#include <set>
|
||||
|
||||
|
@ -100,6 +100,7 @@ public:
|
|||
Sender,
|
||||
Date,
|
||||
DeliveryState,
|
||||
Encryption,
|
||||
Correction,
|
||||
SentByMe,
|
||||
Avatar,
|
||||
|
@ -216,6 +217,7 @@ struct FeedItem {
|
|||
Edition correction;
|
||||
QDateTime date;
|
||||
Shared::Message::State state;
|
||||
Shared::EncryptionProtocol encryption;
|
||||
Attachment attach;
|
||||
};
|
||||
};
|
||||
|
@ -224,4 +226,4 @@ Q_DECLARE_METATYPE(Models::Attachment);
|
|||
Q_DECLARE_METATYPE(Models::Edition);
|
||||
Q_DECLARE_METATYPE(Models::FeedItem);
|
||||
|
||||
#endif // MESSAGEFEED_H
|
||||
#pragma once
|
||||
|
|
|
@ -16,8 +16,7 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef PREVIEW_H
|
||||
#define PREVIEW_H
|
||||
#pragma once
|
||||
|
||||
#include <QWidget>
|
||||
#include <QString>
|
||||
|
@ -75,5 +74,3 @@ private:
|
|||
bool fileReachable;
|
||||
bool actualPreview;
|
||||
};
|
||||
|
||||
#endif // PREVIEW_H
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue