forked from blue/squawk
removed unused old message line files, first thoughts on message edition
This commit is contained in:
parent
73b1b58a96
commit
0823b35148
@ -6,11 +6,13 @@
|
|||||||
- build now correctly installs all build plugin libs
|
- build now correctly installs all build plugin libs
|
||||||
|
|
||||||
### Improvements
|
### Improvements
|
||||||
|
- reduced amount of places where platform specific path separator is used
|
||||||
|
|
||||||
### New features
|
### New features
|
||||||
- the settings are here! You con config different stuff from there
|
- the settings are here! You con config different stuff from there
|
||||||
- now it's possible to set up different qt styles from settings
|
- now it's possible to set up different qt styles from settings
|
||||||
- if you have KConfig nad KConfigWidgets packages installed - you can chose from global color schemes
|
- if you have KConfig nad KConfigWidgets packages installed - you can chose from global color schemes
|
||||||
|
- it's possible now to chose a folder where squawk is going to store downloaded files
|
||||||
|
|
||||||
## Squawk 0.2.0 (Jan 10, 2022)
|
## Squawk 0.2.0 (Jan 10, 2022)
|
||||||
### Bug fixes
|
### Bug fixes
|
||||||
|
@ -26,32 +26,62 @@ Badge::Badge(const QString& p_id, const QString& p_text, const QIcon& icon, QWid
|
|||||||
closeButton(new QPushButton()),
|
closeButton(new QPushButton()),
|
||||||
layout(new QHBoxLayout(this))
|
layout(new QHBoxLayout(this))
|
||||||
{
|
{
|
||||||
setBackgroundRole(QPalette::Base);
|
createMandatoryComponents();
|
||||||
//setAutoFillBackground(true);
|
|
||||||
setFrameStyle(QFrame::StyledPanel);
|
|
||||||
setFrameShadow(QFrame::Raised);
|
|
||||||
|
|
||||||
image->setPixmap(icon.pixmap(25, 25));
|
image->setPixmap(icon.pixmap(25, 25));
|
||||||
QIcon tabCloseIcon = QIcon::fromTheme("tab-close");
|
|
||||||
if (tabCloseIcon.isNull()) {
|
|
||||||
tabCloseIcon.addFile(QString::fromUtf8(":/images/fallback/dark/big/edit-none.svg"), QSize(), QIcon::Normal, QIcon::Off);
|
|
||||||
}
|
|
||||||
closeButton->setIcon(tabCloseIcon);
|
|
||||||
|
|
||||||
closeButton->setMaximumHeight(25);
|
|
||||||
closeButton->setMaximumWidth(25);
|
|
||||||
|
|
||||||
layout->addWidget(image);
|
layout->addWidget(image);
|
||||||
layout->addWidget(text);
|
layout->addWidget(text);
|
||||||
layout->addWidget(closeButton);
|
layout->addWidget(closeButton);
|
||||||
|
}
|
||||||
layout->setContentsMargins(2, 2, 2, 2);
|
|
||||||
|
Badge::Badge(QWidget* parent):
|
||||||
connect(closeButton, &QPushButton::clicked, this, &Badge::close);
|
QFrame(parent),
|
||||||
|
id(Shared::generateUUID()),
|
||||||
|
image(nullptr),
|
||||||
|
text(nullptr),
|
||||||
|
closeButton(new QPushButton()),
|
||||||
|
layout(new QHBoxLayout(this))
|
||||||
|
{
|
||||||
|
createMandatoryComponents();
|
||||||
|
|
||||||
|
layout->addWidget(closeButton);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Badge::setIcon(const QIcon& icon)
|
||||||
|
{
|
||||||
|
if (image == nullptr) {
|
||||||
|
image = new QLabel();
|
||||||
|
image->setPixmap(icon.pixmap(25, 25));
|
||||||
|
layout->insertWidget(0, image);
|
||||||
|
} else {
|
||||||
|
image->setPixmap(icon.pixmap(25, 25));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Badge::setText(const QString& p_text)
|
||||||
|
{
|
||||||
|
if (text == nullptr) {
|
||||||
|
text = new QLabel(p_text);
|
||||||
|
int index = 0;
|
||||||
|
if (image != nullptr) {
|
||||||
|
index = 1;
|
||||||
|
}
|
||||||
|
layout->insertWidget(index, text);
|
||||||
|
} else {
|
||||||
|
text->setText(p_text);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Badge::~Badge()
|
Badge::~Badge()
|
||||||
{
|
{
|
||||||
|
if (image != nullptr) {
|
||||||
|
delete image;
|
||||||
|
}
|
||||||
|
if (text != nullptr) {
|
||||||
|
delete text;
|
||||||
|
}
|
||||||
|
delete closeButton;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Badge::Comparator::operator()(const Badge* a, const Badge* b) const
|
bool Badge::Comparator::operator()(const Badge* a, const Badge* b) const
|
||||||
@ -63,3 +93,22 @@ bool Badge::Comparator::operator()(const Badge& a, const Badge& b) const
|
|||||||
{
|
{
|
||||||
return a.id < b.id;
|
return a.id < b.id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Badge::createMandatoryComponents()
|
||||||
|
{
|
||||||
|
setBackgroundRole(QPalette::Base);
|
||||||
|
//setAutoFillBackground(true);
|
||||||
|
setFrameStyle(QFrame::StyledPanel);
|
||||||
|
setFrameShadow(QFrame::Raised);
|
||||||
|
|
||||||
|
QIcon tabCloseIcon = QIcon::fromTheme("tab-close");
|
||||||
|
if (tabCloseIcon.isNull()) {
|
||||||
|
tabCloseIcon.addFile(QString::fromUtf8(":/images/fallback/dark/big/edit-none.svg"), QSize(), QIcon::Normal, QIcon::Off);
|
||||||
|
}
|
||||||
|
closeButton->setIcon(tabCloseIcon);
|
||||||
|
|
||||||
|
closeButton->setMaximumHeight(25);
|
||||||
|
closeButton->setMaximumWidth(25);
|
||||||
|
layout->setContentsMargins(2, 2, 2, 2);
|
||||||
|
connect(closeButton, &QPushButton::clicked, this, &Badge::close);
|
||||||
|
}
|
||||||
|
@ -25,6 +25,8 @@
|
|||||||
#include <QIcon>
|
#include <QIcon>
|
||||||
#include <QPushButton>
|
#include <QPushButton>
|
||||||
|
|
||||||
|
#include "shared/utils.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @todo write docs
|
* @todo write docs
|
||||||
*/
|
*/
|
||||||
@ -33,9 +35,14 @@ class Badge : public QFrame
|
|||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
Badge(const QString& id, const QString& text, const QIcon& icon, QWidget* parent = nullptr);
|
Badge(const QString& id, const QString& text, const QIcon& icon, QWidget* parent = nullptr);
|
||||||
|
Badge(QWidget* parent = nullptr);
|
||||||
~Badge();
|
~Badge();
|
||||||
|
|
||||||
const QString id;
|
const QString id;
|
||||||
|
|
||||||
|
public:
|
||||||
|
void setText(const QString& text);
|
||||||
|
void setIcon(const QIcon& icon);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void close();
|
void close();
|
||||||
@ -45,6 +52,9 @@ private:
|
|||||||
QLabel* text;
|
QLabel* text;
|
||||||
QPushButton* closeButton;
|
QPushButton* closeButton;
|
||||||
QHBoxLayout* layout;
|
QHBoxLayout* layout;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void createMandatoryComponents();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
struct Comparator {
|
struct Comparator {
|
||||||
|
@ -57,7 +57,8 @@ Conversation::Conversation(bool muc, Models::Account* acc, Models::Element* el,
|
|||||||
tsb(QApplication::style()->styleHint(QStyle::SH_ScrollBar_Transient) == 1),
|
tsb(QApplication::style()->styleHint(QStyle::SH_ScrollBar_Transient) == 1),
|
||||||
pasteImageAction(new QAction(tr("Paste Image"), this)),
|
pasteImageAction(new QAction(tr("Paste Image"), this)),
|
||||||
shadow(10, 1, Qt::black, this),
|
shadow(10, 1, Qt::black, this),
|
||||||
contextMenu(new QMenu())
|
contextMenu(new QMenu()),
|
||||||
|
currentAction(CurrentAction::none)
|
||||||
{
|
{
|
||||||
m_ui->setupUi(this);
|
m_ui->setupUi(this);
|
||||||
|
|
||||||
@ -108,6 +109,9 @@ Conversation::Conversation(bool muc, Models::Account* acc, Models::Element* el,
|
|||||||
//line->setMyName(acc->getName());
|
//line->setMyName(acc->getName());
|
||||||
|
|
||||||
initializeOverlay();
|
initializeOverlay();
|
||||||
|
|
||||||
|
m_ui->currentActionBadge->setVisible(false);;
|
||||||
|
// m_ui->currentActionBadge->setText(tr("Editing message..."));
|
||||||
}
|
}
|
||||||
|
|
||||||
Conversation::~Conversation()
|
Conversation::~Conversation()
|
||||||
@ -237,7 +241,7 @@ void Conversation::onEnterPressed()
|
|||||||
element->feed->registerUpload(msg.getId());
|
element->feed->registerUpload(msg.getId());
|
||||||
emit sendMessage(msg);
|
emit sendMessage(msg);
|
||||||
}
|
}
|
||||||
clearAttachedFiles();
|
clearAttachedFiles();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -121,6 +121,11 @@ public:
|
|||||||
const bool isMuc;
|
const bool isMuc;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
enum class CurrentAction {
|
||||||
|
none,
|
||||||
|
edit
|
||||||
|
};
|
||||||
|
|
||||||
Models::Account* account;
|
Models::Account* account;
|
||||||
Models::Element* element;
|
Models::Element* element;
|
||||||
QString palJid;
|
QString palJid;
|
||||||
@ -142,6 +147,7 @@ protected:
|
|||||||
|
|
||||||
ShadowOverlay shadow;
|
ShadowOverlay shadow;
|
||||||
QMenu* contextMenu;
|
QMenu* contextMenu;
|
||||||
|
CurrentAction currentAction;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static bool painterInitialized;
|
static bool painterInitialized;
|
||||||
|
@ -279,6 +279,29 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item>
|
||||||
|
<spacer name="horizontalSpacer_3">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>40</width>
|
||||||
|
<height>20</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="Badge" name="currentActionBadge">
|
||||||
|
<property name="frameShape">
|
||||||
|
<enum>QFrame::StyledPanel</enum>
|
||||||
|
</property>
|
||||||
|
<property name="frameShadow">
|
||||||
|
<enum>QFrame::Raised</enum>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<spacer name="horizontalSpacer">
|
<spacer name="horizontalSpacer">
|
||||||
<property name="orientation">
|
<property name="orientation">
|
||||||
@ -400,8 +423,8 @@ background-color: transparent
|
|||||||
<string><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
|
<string><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
|
||||||
<html><head><meta name="qrichtext" content="1" /><style type="text/css">
|
<html><head><meta name="qrichtext" content="1" /><style type="text/css">
|
||||||
p, li { white-space: pre-wrap; }
|
p, li { white-space: pre-wrap; }
|
||||||
</style></head><body style=" font-family:'Liberation Sans'; font-size:10pt; font-weight:400; font-style:normal;">
|
</style></head><body style=" font-family:'Noto Sans'; font-size:8pt; font-weight:400; font-style:normal;">
|
||||||
<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html></string>
|
<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Liberation Sans'; font-size:10pt;"><br /></p></body></html></string>
|
||||||
</property>
|
</property>
|
||||||
<property name="acceptRichText">
|
<property name="acceptRichText">
|
||||||
<bool>false</bool>
|
<bool>false</bool>
|
||||||
@ -419,6 +442,13 @@ p, li { white-space: pre-wrap; }
|
|||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
|
<customwidgets>
|
||||||
|
<customwidget>
|
||||||
|
<class>Badge</class>
|
||||||
|
<extends>QFrame</extends>
|
||||||
|
<header location="global">ui/utils/badge.h</header>
|
||||||
|
</customwidget>
|
||||||
|
</customwidgets>
|
||||||
<resources>
|
<resources>
|
||||||
<include location="../../resources/resources.qrc"/>
|
<include location="../../resources/resources.qrc"/>
|
||||||
</resources>
|
</resources>
|
||||||
|
@ -1,14 +1,10 @@
|
|||||||
target_sources(squawk PRIVATE
|
target_sources(squawk PRIVATE
|
||||||
messagedelegate.cpp
|
messagedelegate.cpp
|
||||||
messagedelegate.h
|
messagedelegate.h
|
||||||
#messageline.cpp
|
|
||||||
#messageline.h
|
|
||||||
preview.cpp
|
preview.cpp
|
||||||
preview.h
|
preview.h
|
||||||
messagefeed.cpp
|
messagefeed.cpp
|
||||||
messagefeed.h
|
messagefeed.h
|
||||||
feedview.cpp
|
feedview.cpp
|
||||||
feedview.h
|
feedview.h
|
||||||
#message.cpp
|
|
||||||
#message.h
|
|
||||||
)
|
)
|
||||||
|
@ -1,344 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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 "message.h"
|
|
||||||
#include <QDebug>
|
|
||||||
#include <QMimeDatabase>
|
|
||||||
#include <QPixmap>
|
|
||||||
#include <QFileInfo>
|
|
||||||
#include <QRegularExpression>
|
|
||||||
|
|
||||||
Message::Message(const Shared::Message& source, bool p_outgoing, const QString& p_sender, const QString& avatarPath, QWidget* parent):
|
|
||||||
QWidget(parent),
|
|
||||||
outgoing(p_outgoing),
|
|
||||||
msg(source),
|
|
||||||
body(new QWidget()),
|
|
||||||
statusBar(new QWidget()),
|
|
||||||
bodyLayout(new QVBoxLayout(body)),
|
|
||||||
layout(new QHBoxLayout(this)),
|
|
||||||
date(new QLabel(msg.getTime().toLocalTime().toString())),
|
|
||||||
sender(new QLabel(p_sender)),
|
|
||||||
text(new QLabel()),
|
|
||||||
shadow(new QGraphicsDropShadowEffect()),
|
|
||||||
button(0),
|
|
||||||
file(0),
|
|
||||||
progress(0),
|
|
||||||
fileComment(new QLabel()),
|
|
||||||
statusIcon(0),
|
|
||||||
editedLabel(0),
|
|
||||||
avatar(new Image(avatarPath.size() == 0 ? Shared::iconPath("user", true) : avatarPath, 60)),
|
|
||||||
hasButton(false),
|
|
||||||
hasProgress(false),
|
|
||||||
hasFile(false),
|
|
||||||
commentAdded(false),
|
|
||||||
hasStatusIcon(false),
|
|
||||||
hasEditedLabel(false)
|
|
||||||
{
|
|
||||||
setContentsMargins(0, 0, 0, 0);
|
|
||||||
layout->setContentsMargins(10, 5, 10, 5);
|
|
||||||
body->setBackgroundRole(QPalette::AlternateBase);
|
|
||||||
body->setAutoFillBackground(true);
|
|
||||||
|
|
||||||
QString bd = Shared::processMessageBody(msg.getBody());
|
|
||||||
text->setTextFormat(Qt::RichText);
|
|
||||||
text->setText(bd);;
|
|
||||||
text->setTextInteractionFlags(text->textInteractionFlags() | Qt::TextSelectableByMouse | Qt::LinksAccessibleByMouse);
|
|
||||||
text->setWordWrap(true);
|
|
||||||
text->setOpenExternalLinks(true);
|
|
||||||
if (bd.size() == 0) {
|
|
||||||
text->hide();
|
|
||||||
}
|
|
||||||
|
|
||||||
QFont dFont = date->font();
|
|
||||||
dFont.setItalic(true);
|
|
||||||
dFont.setPointSize(dFont.pointSize() - 2);
|
|
||||||
date->setFont(dFont);
|
|
||||||
|
|
||||||
QFont f;
|
|
||||||
f.setBold(true);
|
|
||||||
sender->setFont(f);
|
|
||||||
|
|
||||||
bodyLayout->addWidget(sender);
|
|
||||||
bodyLayout->addWidget(text);
|
|
||||||
|
|
||||||
shadow->setBlurRadius(10);
|
|
||||||
shadow->setXOffset(1);
|
|
||||||
shadow->setYOffset(1);
|
|
||||||
shadow->setColor(Qt::black);
|
|
||||||
body->setGraphicsEffect(shadow);
|
|
||||||
avatar->setMaximumHeight(60);
|
|
||||||
avatar->setMaximumWidth(60);
|
|
||||||
|
|
||||||
statusBar->setContentsMargins(0, 0, 0, 0);
|
|
||||||
QHBoxLayout* statusLay = new QHBoxLayout();
|
|
||||||
statusLay->setContentsMargins(0, 0, 0, 0);
|
|
||||||
statusBar->setLayout(statusLay);
|
|
||||||
|
|
||||||
if (outgoing) {
|
|
||||||
sender->setAlignment(Qt::AlignRight);
|
|
||||||
date->setAlignment(Qt::AlignRight);
|
|
||||||
statusIcon = new QLabel();
|
|
||||||
setState();
|
|
||||||
statusLay->addWidget(statusIcon);
|
|
||||||
statusLay->addWidget(date);
|
|
||||||
layout->addStretch();
|
|
||||||
layout->addWidget(body);
|
|
||||||
layout->addWidget(avatar);
|
|
||||||
hasStatusIcon = true;
|
|
||||||
} else {
|
|
||||||
layout->addWidget(avatar);
|
|
||||||
layout->addWidget(body);
|
|
||||||
layout->addStretch();
|
|
||||||
statusLay->addWidget(date);
|
|
||||||
}
|
|
||||||
if (msg.getEdited()) {
|
|
||||||
setEdited();
|
|
||||||
}
|
|
||||||
|
|
||||||
bodyLayout->addWidget(statusBar);
|
|
||||||
layout->setAlignment(avatar, Qt::AlignTop);
|
|
||||||
}
|
|
||||||
|
|
||||||
Message::~Message()
|
|
||||||
{
|
|
||||||
if (!commentAdded) {
|
|
||||||
delete fileComment;
|
|
||||||
}
|
|
||||||
//delete body; //not sure if I should delete it here, it's probably already owned by the infrastructure and gonna die with the rest of the widget
|
|
||||||
//delete avatar;
|
|
||||||
}
|
|
||||||
|
|
||||||
QString Message::getId() const
|
|
||||||
{
|
|
||||||
return msg.getId();
|
|
||||||
}
|
|
||||||
|
|
||||||
QString Message::getSenderJid() const
|
|
||||||
{
|
|
||||||
return msg.getFromJid();
|
|
||||||
}
|
|
||||||
|
|
||||||
QString Message::getSenderResource() const
|
|
||||||
{
|
|
||||||
return msg.getFromResource();
|
|
||||||
}
|
|
||||||
|
|
||||||
QString Message::getFileUrl() const
|
|
||||||
{
|
|
||||||
return msg.getOutOfBandUrl();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Message::setSender(const QString& p_sender)
|
|
||||||
{
|
|
||||||
sender->setText(p_sender);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Message::addButton(const QIcon& icon, const QString& buttonText, const QString& tooltip)
|
|
||||||
{
|
|
||||||
hideFile();
|
|
||||||
hideProgress();
|
|
||||||
if (!hasButton) {
|
|
||||||
hideComment();
|
|
||||||
if (msg.getBody() == msg.getOutOfBandUrl()) {
|
|
||||||
text->setText("");
|
|
||||||
text->hide();
|
|
||||||
}
|
|
||||||
button = new QPushButton(icon, buttonText);
|
|
||||||
button->setToolTip(tooltip);
|
|
||||||
connect(button, &QPushButton::clicked, this, &Message::buttonClicked);
|
|
||||||
bodyLayout->insertWidget(2, button);
|
|
||||||
hasButton = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Message::setProgress(qreal value)
|
|
||||||
{
|
|
||||||
hideFile();
|
|
||||||
hideButton();
|
|
||||||
if (!hasProgress) {
|
|
||||||
hideComment();
|
|
||||||
if (msg.getBody() == msg.getOutOfBandUrl()) {
|
|
||||||
text->setText("");
|
|
||||||
text->hide();
|
|
||||||
}
|
|
||||||
progress = new QProgressBar();
|
|
||||||
progress->setRange(0, 100);
|
|
||||||
bodyLayout->insertWidget(2, progress);
|
|
||||||
hasProgress = true;
|
|
||||||
}
|
|
||||||
progress->setValue(value * 100);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Message::showFile(const QString& path)
|
|
||||||
{
|
|
||||||
hideButton();
|
|
||||||
hideProgress();
|
|
||||||
if (!hasFile) {
|
|
||||||
hideComment();
|
|
||||||
if (msg.getBody() == msg.getOutOfBandUrl()) {
|
|
||||||
text->setText("");
|
|
||||||
text->hide();
|
|
||||||
}
|
|
||||||
QMimeDatabase db;
|
|
||||||
QMimeType type = db.mimeTypeForFile(path);
|
|
||||||
QStringList parts = type.name().split("/");
|
|
||||||
QString big = parts.front();
|
|
||||||
QFileInfo info(path);
|
|
||||||
if (big == "image") {
|
|
||||||
file = new Image(path);
|
|
||||||
} else {
|
|
||||||
file = new QLabel();
|
|
||||||
file->setPixmap(QIcon::fromTheme(type.iconName()).pixmap(50));
|
|
||||||
file->setAlignment(Qt::AlignCenter);
|
|
||||||
showComment(info.fileName(), true);
|
|
||||||
}
|
|
||||||
file->setContextMenuPolicy(Qt::ActionsContextMenu);
|
|
||||||
QAction* openAction = new QAction(QIcon::fromTheme("document-new-from-template"), tr("Open"), file);
|
|
||||||
connect(openAction, &QAction::triggered, [path]() { //TODO need to get rid of this shame
|
|
||||||
QDesktopServices::openUrl(QUrl::fromLocalFile(path));
|
|
||||||
});
|
|
||||||
file->addAction(openAction);
|
|
||||||
bodyLayout->insertWidget(2, file);
|
|
||||||
hasFile = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Message::hideComment()
|
|
||||||
{
|
|
||||||
if (commentAdded) {
|
|
||||||
bodyLayout->removeWidget(fileComment);
|
|
||||||
fileComment->hide();
|
|
||||||
fileComment->setWordWrap(false);
|
|
||||||
commentAdded = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Message::hideButton()
|
|
||||||
{
|
|
||||||
if (hasButton) {
|
|
||||||
button->deleteLater();
|
|
||||||
button = 0;
|
|
||||||
hasButton = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Message::hideFile()
|
|
||||||
{
|
|
||||||
if (hasFile) {
|
|
||||||
file->deleteLater();
|
|
||||||
file = 0;
|
|
||||||
hasFile = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Message::hideProgress()
|
|
||||||
{
|
|
||||||
if (hasProgress) {
|
|
||||||
progress->deleteLater();
|
|
||||||
progress = 0;
|
|
||||||
hasProgress = false;;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
void Message::showComment(const QString& comment, bool wordWrap)
|
|
||||||
{
|
|
||||||
if (!commentAdded) {
|
|
||||||
int index = 2;
|
|
||||||
if (hasFile) {
|
|
||||||
index++;
|
|
||||||
}
|
|
||||||
if (hasButton) {
|
|
||||||
index++;
|
|
||||||
}
|
|
||||||
if (hasProgress) {
|
|
||||||
index++;
|
|
||||||
}
|
|
||||||
bodyLayout->insertWidget(index, fileComment);
|
|
||||||
fileComment->show();
|
|
||||||
commentAdded = true;
|
|
||||||
}
|
|
||||||
fileComment->setWordWrap(wordWrap);
|
|
||||||
fileComment->setText(comment);
|
|
||||||
}
|
|
||||||
|
|
||||||
const Shared::Message & Message::getMessage() const
|
|
||||||
{
|
|
||||||
return msg;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Message::setAvatarPath(const QString& p_path)
|
|
||||||
{
|
|
||||||
if (p_path.size() == 0) {
|
|
||||||
avatar->setPath(Shared::iconPath("user", true));
|
|
||||||
} else {
|
|
||||||
avatar->setPath(p_path);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Message::change(const QMap<QString, QVariant>& data)
|
|
||||||
{
|
|
||||||
bool idChanged = msg.change(data);
|
|
||||||
|
|
||||||
QString body = msg.getBody();
|
|
||||||
QString bd = Shared::processMessageBody(body);
|
|
||||||
if (body.size() > 0) {
|
|
||||||
text->setText(bd);
|
|
||||||
text->show();
|
|
||||||
} else {
|
|
||||||
text->setText(body);
|
|
||||||
text->hide();
|
|
||||||
}
|
|
||||||
if (msg.getEdited()) {
|
|
||||||
setEdited();
|
|
||||||
}
|
|
||||||
if (hasStatusIcon) {
|
|
||||||
setState();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
return idChanged;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Message::setEdited()
|
|
||||||
{
|
|
||||||
if (!hasEditedLabel) {
|
|
||||||
editedLabel = new QLabel();
|
|
||||||
hasEditedLabel = true;
|
|
||||||
QIcon q(Shared::icon("edit-rename"));
|
|
||||||
editedLabel->setPixmap(q.pixmap(12, 12));
|
|
||||||
QHBoxLayout* statusLay = static_cast<QHBoxLayout*>(statusBar->layout());
|
|
||||||
statusLay->insertWidget(1, editedLabel);
|
|
||||||
}
|
|
||||||
editedLabel->setToolTip("Last time edited: " + msg.getLastModified().toLocalTime().toString()
|
|
||||||
+ "\nOriginal message: " + msg.getOriginalBody());
|
|
||||||
}
|
|
||||||
|
|
||||||
void Message::setState()
|
|
||||||
{
|
|
||||||
Shared::Message::State state = msg.getState();
|
|
||||||
QIcon q(Shared::icon(Shared::messageStateThemeIcons[static_cast<uint8_t>(state)]));
|
|
||||||
QString tt = Shared::Global::getName(state);
|
|
||||||
if (state == Shared::Message::State::error) {
|
|
||||||
QString errText = msg.getErrorText();
|
|
||||||
if (errText.size() > 0) {
|
|
||||||
tt += ": " + errText;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
statusIcon->setToolTip(tt);
|
|
||||||
statusIcon->setPixmap(q.pixmap(12, 12));
|
|
||||||
}
|
|
||||||
|
|
@ -1,103 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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 <QPushButton>
|
|
||||||
#include <QProgressBar>
|
|
||||||
#include <QAction>
|
|
||||||
#include <QDesktopServices>
|
|
||||||
#include <QUrl>
|
|
||||||
#include <QMap>
|
|
||||||
|
|
||||||
#include "shared/message.h"
|
|
||||||
#include "shared/icons.h"
|
|
||||||
#include "shared/global.h"
|
|
||||||
#include "shared/utils.h"
|
|
||||||
#include "resizer.h"
|
|
||||||
#include "image.h"
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @todo write docs
|
|
||||||
*/
|
|
||||||
class Message : public QWidget
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
public:
|
|
||||||
Message(const Shared::Message& source, bool outgoing, const QString& sender, const QString& avatarPath = "", QWidget* parent = nullptr);
|
|
||||||
~Message();
|
|
||||||
|
|
||||||
void setSender(const QString& sender);
|
|
||||||
QString getId() const;
|
|
||||||
QString getSenderJid() const;
|
|
||||||
QString getSenderResource() const;
|
|
||||||
QString getFileUrl() const;
|
|
||||||
const Shared::Message& getMessage() const;
|
|
||||||
|
|
||||||
void addButton(const QIcon& icon, const QString& buttonText, const QString& tooltip = "");
|
|
||||||
void showComment(const QString& comment, bool wordWrap = false);
|
|
||||||
void hideComment();
|
|
||||||
void showFile(const QString& path);
|
|
||||||
void setProgress(qreal value);
|
|
||||||
void setAvatarPath(const QString& p_path);
|
|
||||||
bool change(const QMap<QString, QVariant>& data);
|
|
||||||
|
|
||||||
bool const outgoing;
|
|
||||||
|
|
||||||
signals:
|
|
||||||
void buttonClicked();
|
|
||||||
|
|
||||||
private:
|
|
||||||
Shared::Message msg;
|
|
||||||
QWidget* body;
|
|
||||||
QWidget* statusBar;
|
|
||||||
QVBoxLayout* bodyLayout;
|
|
||||||
QHBoxLayout* layout;
|
|
||||||
QLabel* date;
|
|
||||||
QLabel* sender;
|
|
||||||
QLabel* text;
|
|
||||||
QGraphicsDropShadowEffect* shadow;
|
|
||||||
QPushButton* button;
|
|
||||||
QLabel* file;
|
|
||||||
QProgressBar* progress;
|
|
||||||
QLabel* fileComment;
|
|
||||||
QLabel* statusIcon;
|
|
||||||
QLabel* editedLabel;
|
|
||||||
Image* avatar;
|
|
||||||
bool hasButton;
|
|
||||||
bool hasProgress;
|
|
||||||
bool hasFile;
|
|
||||||
bool commentAdded;
|
|
||||||
bool hasStatusIcon;
|
|
||||||
bool hasEditedLabel;
|
|
||||||
|
|
||||||
private:
|
|
||||||
void hideButton();
|
|
||||||
void hideProgress();
|
|
||||||
void hideFile();
|
|
||||||
void setState();
|
|
||||||
void setEdited();
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // MESSAGE_H
|
|
@ -1,504 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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 "messageline.h"
|
|
||||||
#include <QDebug>
|
|
||||||
#include <QCoreApplication>
|
|
||||||
#include <cmath>
|
|
||||||
|
|
||||||
MessageLine::MessageLine(bool p_room, QWidget* parent):
|
|
||||||
QWidget(parent),
|
|
||||||
messageIndex(),
|
|
||||||
messageOrder(),
|
|
||||||
myMessages(),
|
|
||||||
palMessages(),
|
|
||||||
uploadPaths(),
|
|
||||||
palAvatars(),
|
|
||||||
exPalAvatars(),
|
|
||||||
layout(new QVBoxLayout(this)),
|
|
||||||
myName(),
|
|
||||||
myAvatarPath(),
|
|
||||||
palNames(),
|
|
||||||
uploading(),
|
|
||||||
downloading(),
|
|
||||||
room(p_room),
|
|
||||||
busyShown(false),
|
|
||||||
progress()
|
|
||||||
{
|
|
||||||
setContentsMargins(0, 0, 0, 0);
|
|
||||||
layout->setContentsMargins(0, 0, 0, 0);
|
|
||||||
layout->setSpacing(0);
|
|
||||||
layout->addStretch();
|
|
||||||
}
|
|
||||||
|
|
||||||
MessageLine::~MessageLine()
|
|
||||||
{
|
|
||||||
for (Index::const_iterator itr = messageIndex.begin(), end = messageIndex.end(); itr != end; ++itr) {
|
|
||||||
delete itr->second;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
MessageLine::Position MessageLine::message(const Shared::Message& msg, bool forceOutgoing)
|
|
||||||
{
|
|
||||||
QString id = msg.getId();
|
|
||||||
Index::iterator itr = messageIndex.find(id);
|
|
||||||
if (itr != messageIndex.end()) {
|
|
||||||
qDebug() << "received more then one message with the same id, skipping yet the new one";
|
|
||||||
return invalid;
|
|
||||||
}
|
|
||||||
|
|
||||||
QString sender;
|
|
||||||
QString aPath;
|
|
||||||
bool outgoing;
|
|
||||||
|
|
||||||
if (forceOutgoing) {
|
|
||||||
sender = myName;
|
|
||||||
aPath = myAvatarPath;
|
|
||||||
outgoing = true;
|
|
||||||
} else {
|
|
||||||
if (room) {
|
|
||||||
if (msg.getFromResource() == myName) {
|
|
||||||
sender = myName;
|
|
||||||
aPath = myAvatarPath;
|
|
||||||
outgoing = true;
|
|
||||||
} else {
|
|
||||||
sender = msg.getFromResource();
|
|
||||||
std::map<QString, QString>::iterator aItr = palAvatars.find(sender);
|
|
||||||
if (aItr != palAvatars.end()) {
|
|
||||||
aPath = aItr->second;
|
|
||||||
} else {
|
|
||||||
aItr = exPalAvatars.find(sender);
|
|
||||||
if (aItr != exPalAvatars.end()) {
|
|
||||||
aPath = aItr->second;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
outgoing = false;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (msg.getOutgoing()) {
|
|
||||||
sender = myName;
|
|
||||||
aPath = myAvatarPath;
|
|
||||||
outgoing = true;
|
|
||||||
} else {
|
|
||||||
QString jid = msg.getFromJid();
|
|
||||||
std::map<QString, QString>::iterator itr = palNames.find(jid);
|
|
||||||
if (itr != palNames.end()) {
|
|
||||||
sender = itr->second;
|
|
||||||
} else {
|
|
||||||
sender = jid;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::map<QString, QString>::iterator aItr = palAvatars.find(jid);
|
|
||||||
if (aItr != palAvatars.end()) {
|
|
||||||
aPath = aItr->second;
|
|
||||||
}
|
|
||||||
|
|
||||||
outgoing = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Message* message = new Message(msg, outgoing, sender, aPath);
|
|
||||||
|
|
||||||
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 message;
|
|
||||||
return invalid;
|
|
||||||
}
|
|
||||||
if (outgoing) {
|
|
||||||
myMessages.insert(std::make_pair(id, message));
|
|
||||||
} else {
|
|
||||||
QString senderId;
|
|
||||||
if (room) {
|
|
||||||
senderId = sender;
|
|
||||||
} else {
|
|
||||||
senderId = msg.getFromJid();
|
|
||||||
}
|
|
||||||
|
|
||||||
std::map<QString, Index>::iterator pItr = palMessages.find(senderId);
|
|
||||||
if (pItr == palMessages.end()) {
|
|
||||||
pItr = palMessages.insert(std::make_pair(senderId, Index())).first;
|
|
||||||
}
|
|
||||||
pItr->second.insert(std::make_pair(id, message));
|
|
||||||
}
|
|
||||||
messageIndex.insert(std::make_pair(id, message));
|
|
||||||
unsigned long index = std::distance<Order::const_iterator>(messageOrder.begin(), result.first); //need to make with binary indexed tree
|
|
||||||
Position res = invalid;
|
|
||||||
if (index == 0) {
|
|
||||||
res = beggining;
|
|
||||||
} else if (index == messageIndex.size() - 1) {
|
|
||||||
res = end;
|
|
||||||
} else {
|
|
||||||
res = middle;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (busyShown) {
|
|
||||||
index += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (res == end) {
|
|
||||||
layout->addWidget(message);
|
|
||||||
} else {
|
|
||||||
layout->insertWidget(index + 1, message);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (msg.hasOutOfBandUrl()) {
|
|
||||||
emit requestLocalFile(msg.getId(), msg.getOutOfBandUrl());
|
|
||||||
connect(message, &Message::buttonClicked, this, &MessageLine::onDownload);
|
|
||||||
}
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
void MessageLine::changeMessage(const QString& id, const QMap<QString, QVariant>& data)
|
|
||||||
{
|
|
||||||
Index::const_iterator itr = messageIndex.find(id);
|
|
||||||
if (itr != messageIndex.end()) {
|
|
||||||
Message* msg = itr->second;
|
|
||||||
if (msg->change(data)) { //if ID changed (stanza in replace of another)
|
|
||||||
QString newId = msg->getId(); //need to updated IDs of that message in all maps
|
|
||||||
messageIndex.erase(itr);
|
|
||||||
messageIndex.insert(std::make_pair(newId, msg));
|
|
||||||
if (msg->outgoing) {
|
|
||||||
QString senderId;
|
|
||||||
if (room) {
|
|
||||||
senderId = msg->getSenderResource();
|
|
||||||
} else {
|
|
||||||
senderId = msg->getSenderJid();
|
|
||||||
}
|
|
||||||
|
|
||||||
std::map<QString, Index>::iterator pItr = palMessages.find(senderId);
|
|
||||||
if (pItr != palMessages.end()) {
|
|
||||||
Index::const_iterator sItr = pItr->second.find(id);
|
|
||||||
if (sItr != pItr->second.end()) {
|
|
||||||
pItr->second.erase(sItr);
|
|
||||||
pItr->second.insert(std::make_pair(newId, msg));
|
|
||||||
} else {
|
|
||||||
qDebug() << "Was trying to replace message in open conversations, couldn't find it among pal's messages, probably an error";
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
qDebug() << "Was trying to replace message in open conversations, couldn't find pal messages, probably an error";
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Index::const_iterator mItr = myMessages.find(id);
|
|
||||||
if (mItr != myMessages.end()) {
|
|
||||||
myMessages.erase(mItr);
|
|
||||||
myMessages.insert(std::make_pair(newId, msg));
|
|
||||||
} else {
|
|
||||||
qDebug() << "Was trying to replace message in open conversations, couldn't find it among my messages, probably an error";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void MessageLine::onDownload()
|
|
||||||
{
|
|
||||||
Message* msg = static_cast<Message*>(sender());
|
|
||||||
QString messageId = msg->getId();
|
|
||||||
Index::const_iterator itr = downloading.find(messageId);
|
|
||||||
if (itr == downloading.end()) {
|
|
||||||
downloading.insert(std::make_pair(messageId, msg));
|
|
||||||
msg->setProgress(0);
|
|
||||||
msg->showComment(tr("Downloading..."));
|
|
||||||
emit downloadFile(messageId, msg->getFileUrl());
|
|
||||||
} else {
|
|
||||||
qDebug() << "An attempt to initiate download for already downloading file" << msg->getFileUrl() << ", skipping";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
std::map<QString, QString>::iterator itr = palNames.find(jid);
|
|
||||||
if (itr == palNames.end()) {
|
|
||||||
palNames.insert(std::make_pair(jid, 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::setPalAvatar(const QString& jid, const QString& path)
|
|
||||||
{
|
|
||||||
std::map<QString, QString>::iterator itr = palAvatars.find(jid);
|
|
||||||
if (itr == palAvatars.end()) {
|
|
||||||
palAvatars.insert(std::make_pair(jid, path));
|
|
||||||
|
|
||||||
std::map<QString, QString>::const_iterator eitr = exPalAvatars.find(jid);
|
|
||||||
if (eitr != exPalAvatars.end()) {
|
|
||||||
exPalAvatars.erase(eitr);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
itr->second = path;
|
|
||||||
}
|
|
||||||
|
|
||||||
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->setAvatarPath(path);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void MessageLine::dropPalAvatar(const QString& jid)
|
|
||||||
{
|
|
||||||
std::map<QString, QString>::iterator itr = palAvatars.find(jid);
|
|
||||||
if (itr != palAvatars.end()) {
|
|
||||||
palAvatars.erase(itr);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::map<QString, QString>::const_iterator eitr = exPalAvatars.find(jid);
|
|
||||||
if (eitr != exPalAvatars.end()) {
|
|
||||||
exPalAvatars.erase(eitr);
|
|
||||||
}
|
|
||||||
|
|
||||||
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->setAvatarPath("");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void MessageLine::movePalAvatarToEx(const QString& name)
|
|
||||||
{
|
|
||||||
std::map<QString, QString>::iterator itr = palAvatars.find(name);
|
|
||||||
if (itr != palAvatars.end()) {
|
|
||||||
std::map<QString, QString>::iterator eitr = exPalAvatars.find(name);
|
|
||||||
if (eitr != exPalAvatars.end()) {
|
|
||||||
eitr->second = itr->second;
|
|
||||||
} else {
|
|
||||||
exPalAvatars.insert(std::make_pair(name, itr->second));
|
|
||||||
}
|
|
||||||
|
|
||||||
palAvatars.erase(itr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void MessageLine::resizeEvent(QResizeEvent* event)
|
|
||||||
{
|
|
||||||
QWidget::resizeEvent(event);
|
|
||||||
emit resize(event->size().height() - event->oldSize().height());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
QString MessageLine::firstMessageId() const
|
|
||||||
{
|
|
||||||
if (messageOrder.size() == 0) {
|
|
||||||
return "";
|
|
||||||
} else {
|
|
||||||
return messageOrder.begin()->second->getId();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void MessageLine::showBusyIndicator()
|
|
||||||
{
|
|
||||||
if (!busyShown) {
|
|
||||||
layout->insertWidget(0, &progress);
|
|
||||||
progress.start();
|
|
||||||
busyShown = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void MessageLine::hideBusyIndicator()
|
|
||||||
{
|
|
||||||
if (busyShown) {
|
|
||||||
progress.stop();
|
|
||||||
layout->removeWidget(&progress);
|
|
||||||
busyShown = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void MessageLine::fileProgress(const QString& messageId, qreal progress)
|
|
||||||
{
|
|
||||||
Index::const_iterator itr = messageIndex.find(messageId);
|
|
||||||
if (itr == messageIndex.end()) {
|
|
||||||
//TODO may be some logging, that's not normal
|
|
||||||
} else {
|
|
||||||
itr->second->setProgress(progress);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void MessageLine::responseLocalFile(const QString& messageId, const QString& path)
|
|
||||||
{
|
|
||||||
Index::const_iterator itr = messageIndex.find(messageId);
|
|
||||||
if (itr == messageIndex.end()) {
|
|
||||||
|
|
||||||
} else {
|
|
||||||
Index::const_iterator uItr = uploading.find(messageId);
|
|
||||||
if (path.size() > 0) {
|
|
||||||
Index::const_iterator dItr = downloading.find(messageId);
|
|
||||||
if (dItr != downloading.end()) {
|
|
||||||
downloading.erase(dItr);
|
|
||||||
itr->second->showFile(path);
|
|
||||||
} else {
|
|
||||||
if (uItr != uploading.end()) {
|
|
||||||
uploading.erase(uItr);
|
|
||||||
std::map<QString, QString>::const_iterator muItr = uploadPaths.find(messageId);
|
|
||||||
if (muItr != uploadPaths.end()) {
|
|
||||||
uploadPaths.erase(muItr);
|
|
||||||
}
|
|
||||||
Shared::Message msg = itr->second->getMessage();
|
|
||||||
removeMessage(messageId);
|
|
||||||
msg.setCurrentTime();
|
|
||||||
message(msg);
|
|
||||||
itr = messageIndex.find(messageId);
|
|
||||||
itr->second->showFile(path);
|
|
||||||
} else {
|
|
||||||
itr->second->showFile(path); //then it is already cached file
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (uItr == uploading.end()) {
|
|
||||||
const Shared::Message& msg = itr->second->getMessage();
|
|
||||||
itr->second->addButton(QIcon::fromTheme("download"), tr("Download"), "<a href=\"" + msg.getOutOfBandUrl() + "\">" + msg.getOutOfBandUrl() + "</a>");
|
|
||||||
itr->second->showComment(tr("Push the button to download the file"));
|
|
||||||
} else {
|
|
||||||
qDebug() << "An unhandled state for file uploading - empty path";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void MessageLine::removeMessage(const QString& messageId)
|
|
||||||
{
|
|
||||||
Index::const_iterator itr = messageIndex.find(messageId);
|
|
||||||
if (itr != messageIndex.end()) {
|
|
||||||
Message* ui = itr->second;
|
|
||||||
const Shared::Message& msg = ui->getMessage();
|
|
||||||
messageIndex.erase(itr);
|
|
||||||
Order::const_iterator oItr = messageOrder.find(msg.getTime());
|
|
||||||
if (oItr != messageOrder.end()) {
|
|
||||||
messageOrder.erase(oItr);
|
|
||||||
} else {
|
|
||||||
qDebug() << "An attempt to remove message from messageLine, but it wasn't found in order";
|
|
||||||
}
|
|
||||||
if (msg.getOutgoing()) {
|
|
||||||
Index::const_iterator mItr = myMessages.find(messageId);
|
|
||||||
if (mItr != myMessages.end()) {
|
|
||||||
myMessages.erase(mItr);
|
|
||||||
} else {
|
|
||||||
qDebug() << "Error removing message: it seems to be outgoing yet it wasn't found in outgoing messages";
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (room) {
|
|
||||||
|
|
||||||
} else {
|
|
||||||
QString jid = msg.getFromJid();
|
|
||||||
std::map<QString, Index>::iterator pItr = palMessages.find(jid);
|
|
||||||
if (pItr != palMessages.end()) {
|
|
||||||
Index& pMsgs = pItr->second;
|
|
||||||
Index::const_iterator pmitr = pMsgs.find(messageId);
|
|
||||||
if (pmitr != pMsgs.end()) {
|
|
||||||
pMsgs.erase(pmitr);
|
|
||||||
} else {
|
|
||||||
qDebug() << "Error removing message: it seems to be incoming yet it wasn't found among messages from that penpal";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ui->deleteLater();
|
|
||||||
qDebug() << "message" << messageId << "has been removed";
|
|
||||||
} else {
|
|
||||||
qDebug() << "An attempt to remove non existing message from messageLine";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void MessageLine::fileError(const QString& messageId, const QString& error)
|
|
||||||
{
|
|
||||||
Index::const_iterator itr = downloading.find(messageId);
|
|
||||||
if (itr == downloading.end()) {
|
|
||||||
Index::const_iterator itr = uploading.find(messageId);
|
|
||||||
if (itr == uploading.end()) {
|
|
||||||
//TODO may be some logging, that's not normal
|
|
||||||
} else {
|
|
||||||
itr->second->showComment(tr("Error uploading file: %1\nYou can try again").arg(QCoreApplication::translate("NetworkErrors", error.toLatin1())), true);
|
|
||||||
itr->second->addButton(QIcon::fromTheme("upload"), tr("Upload"));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
const Shared::Message& msg = itr->second->getMessage();
|
|
||||||
itr->second->addButton(QIcon::fromTheme("download"), tr("Download"), "<a href=\"" + msg.getOutOfBandUrl() + "\">" + msg.getOutOfBandUrl() + "</a>");
|
|
||||||
itr->second->showComment(tr("Error downloading file: %1\nYou can try again").arg(QCoreApplication::translate("NetworkErrors", error.toLatin1())), true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void MessageLine::appendMessageWithUpload(const Shared::Message& msg, const QString& path)
|
|
||||||
{
|
|
||||||
appendMessageWithUploadNoSiganl(msg, path);
|
|
||||||
emit uploadFile(msg, path);
|
|
||||||
}
|
|
||||||
|
|
||||||
void MessageLine::appendMessageWithUploadNoSiganl(const Shared::Message& msg, const QString& path)
|
|
||||||
{
|
|
||||||
message(msg, true);
|
|
||||||
QString id = msg.getId();
|
|
||||||
Message* ui = messageIndex.find(id)->second;
|
|
||||||
connect(ui, &Message::buttonClicked, this, &MessageLine::onUpload); //this is in case of retry;
|
|
||||||
ui->setProgress(0);
|
|
||||||
ui->showComment(tr("Uploading..."));
|
|
||||||
uploading.insert(std::make_pair(id, ui));
|
|
||||||
uploadPaths.insert(std::make_pair(id, path));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void MessageLine::onUpload()
|
|
||||||
{
|
|
||||||
//TODO retry
|
|
||||||
}
|
|
||||||
|
|
||||||
void MessageLine::setMyAvatarPath(const QString& p_path)
|
|
||||||
{
|
|
||||||
if (myAvatarPath != p_path) {
|
|
||||||
myAvatarPath = p_path;
|
|
||||||
for (std::pair<QString, Message*> pair : myMessages) {
|
|
||||||
pair.second->setAvatarPath(myAvatarPath);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void MessageLine::setExPalAvatars(const std::map<QString, QString>& data)
|
|
||||||
{
|
|
||||||
exPalAvatars = data;
|
|
||||||
|
|
||||||
for (const std::pair<QString, Index>& pair : palMessages) {
|
|
||||||
if (palAvatars.find(pair.first) == palAvatars.end()) {
|
|
||||||
std::map<QString, QString>::const_iterator eitr = exPalAvatars.find(pair.first);
|
|
||||||
if (eitr != exPalAvatars.end()) {
|
|
||||||
for (const std::pair<QString, Message*>& mp : pair.second) {
|
|
||||||
mp.second->setAvatarPath(eitr->second);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,108 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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 MESSAGELINE_H
|
|
||||||
#define MESSAGELINE_H
|
|
||||||
|
|
||||||
#include <QWidget>
|
|
||||||
#include <QVBoxLayout>
|
|
||||||
#include <QHBoxLayout>
|
|
||||||
#include <QLabel>
|
|
||||||
#include <QResizeEvent>
|
|
||||||
#include <QIcon>
|
|
||||||
|
|
||||||
#include "shared/message.h"
|
|
||||||
#include "message.h"
|
|
||||||
#include "progress.h"
|
|
||||||
|
|
||||||
class MessageLine : public QWidget
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
public:
|
|
||||||
enum Position {
|
|
||||||
beggining,
|
|
||||||
middle,
|
|
||||||
end,
|
|
||||||
invalid
|
|
||||||
};
|
|
||||||
MessageLine(bool p_room, QWidget* parent = 0);
|
|
||||||
~MessageLine();
|
|
||||||
|
|
||||||
Position message(const Shared::Message& msg, bool forceOutgoing = false);
|
|
||||||
void setMyName(const QString& name);
|
|
||||||
void setPalName(const QString& jid, const QString& name);
|
|
||||||
QString firstMessageId() const;
|
|
||||||
void showBusyIndicator();
|
|
||||||
void hideBusyIndicator();
|
|
||||||
void responseLocalFile(const QString& messageId, const QString& path);
|
|
||||||
void fileError(const QString& messageId, const QString& error);
|
|
||||||
void fileProgress(const QString& messageId, qreal progress);
|
|
||||||
void appendMessageWithUpload(const Shared::Message& msg, const QString& path);
|
|
||||||
void appendMessageWithUploadNoSiganl(const Shared::Message& msg, const QString& path);
|
|
||||||
void removeMessage(const QString& messageId);
|
|
||||||
void setMyAvatarPath(const QString& p_path);
|
|
||||||
void setPalAvatar(const QString& jid, const QString& path);
|
|
||||||
void dropPalAvatar(const QString& jid);
|
|
||||||
void changeMessage(const QString& id, const QMap<QString, QVariant>& data);
|
|
||||||
void setExPalAvatars(const std::map<QString, QString>& data);
|
|
||||||
void movePalAvatarToEx(const QString& name);
|
|
||||||
|
|
||||||
signals:
|
|
||||||
void resize(int amount);
|
|
||||||
void downloadFile(const QString& messageId, const QString& url);
|
|
||||||
void uploadFile(const Shared::Message& msg, const QString& path);
|
|
||||||
void requestLocalFile(const QString& messageId, const QString& url);
|
|
||||||
|
|
||||||
protected:
|
|
||||||
void resizeEvent(QResizeEvent * event) override;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
void onDownload();
|
|
||||||
void onUpload();
|
|
||||||
|
|
||||||
private:
|
|
||||||
struct Comparator {
|
|
||||||
bool operator()(const Shared::Message& a, const Shared::Message& b) const {
|
|
||||||
return a.getTime() < b.getTime();
|
|
||||||
}
|
|
||||||
bool operator()(const Shared::Message* a, const Shared::Message* b) const {
|
|
||||||
return a->getTime() < b->getTime();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
typedef std::map<QDateTime, Message*> Order;
|
|
||||||
typedef std::map<QString, Message*> Index;
|
|
||||||
Index messageIndex;
|
|
||||||
Order messageOrder;
|
|
||||||
Index myMessages;
|
|
||||||
std::map<QString, Index> palMessages;
|
|
||||||
std::map<QString, QString> uploadPaths;
|
|
||||||
std::map<QString, QString> palAvatars;
|
|
||||||
std::map<QString, QString> exPalAvatars;
|
|
||||||
QVBoxLayout* layout;
|
|
||||||
|
|
||||||
QString myName;
|
|
||||||
QString myAvatarPath;
|
|
||||||
std::map<QString, QString> palNames;
|
|
||||||
Index uploading;
|
|
||||||
Index downloading;
|
|
||||||
bool room;
|
|
||||||
bool busyShown;
|
|
||||||
Progress progress;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // MESSAGELINE_H
|
|
Loading…
Reference in New Issue
Block a user