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
|
||||
|
||||
### Improvements
|
||||
- reduced amount of places where platform specific path separator is used
|
||||
|
||||
### New features
|
||||
- the settings are here! You con config different stuff from there
|
||||
- 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
|
||||
- it's possible now to chose a folder where squawk is going to store downloaded files
|
||||
|
||||
## Squawk 0.2.0 (Jan 10, 2022)
|
||||
### Bug fixes
|
||||
|
@ -26,32 +26,62 @@ Badge::Badge(const QString& p_id, const QString& p_text, const QIcon& icon, QWid
|
||||
closeButton(new QPushButton()),
|
||||
layout(new QHBoxLayout(this))
|
||||
{
|
||||
setBackgroundRole(QPalette::Base);
|
||||
//setAutoFillBackground(true);
|
||||
setFrameStyle(QFrame::StyledPanel);
|
||||
setFrameShadow(QFrame::Raised);
|
||||
createMandatoryComponents();
|
||||
|
||||
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(text);
|
||||
layout->addWidget(closeButton);
|
||||
}
|
||||
|
||||
layout->setContentsMargins(2, 2, 2, 2);
|
||||
Badge::Badge(QWidget* parent):
|
||||
QFrame(parent),
|
||||
id(Shared::generateUUID()),
|
||||
image(nullptr),
|
||||
text(nullptr),
|
||||
closeButton(new QPushButton()),
|
||||
layout(new QHBoxLayout(this))
|
||||
{
|
||||
createMandatoryComponents();
|
||||
|
||||
connect(closeButton, &QPushButton::clicked, this, &Badge::close);
|
||||
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()
|
||||
{
|
||||
if (image != nullptr) {
|
||||
delete image;
|
||||
}
|
||||
if (text != nullptr) {
|
||||
delete text;
|
||||
}
|
||||
delete closeButton;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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 <QPushButton>
|
||||
|
||||
#include "shared/utils.h"
|
||||
|
||||
/**
|
||||
* @todo write docs
|
||||
*/
|
||||
@ -33,10 +35,15 @@ class Badge : public QFrame
|
||||
Q_OBJECT
|
||||
public:
|
||||
Badge(const QString& id, const QString& text, const QIcon& icon, QWidget* parent = nullptr);
|
||||
Badge(QWidget* parent = nullptr);
|
||||
~Badge();
|
||||
|
||||
const QString id;
|
||||
|
||||
public:
|
||||
void setText(const QString& text);
|
||||
void setIcon(const QIcon& icon);
|
||||
|
||||
signals:
|
||||
void close();
|
||||
|
||||
@ -46,6 +53,9 @@ private:
|
||||
QPushButton* closeButton;
|
||||
QHBoxLayout* layout;
|
||||
|
||||
private:
|
||||
void createMandatoryComponents();
|
||||
|
||||
public:
|
||||
struct Comparator {
|
||||
bool operator()(const Badge& a, const Badge& b) const;
|
||||
|
@ -57,7 +57,8 @@ Conversation::Conversation(bool muc, Models::Account* acc, Models::Element* el,
|
||||
tsb(QApplication::style()->styleHint(QStyle::SH_ScrollBar_Transient) == 1),
|
||||
pasteImageAction(new QAction(tr("Paste Image"), this)),
|
||||
shadow(10, 1, Qt::black, this),
|
||||
contextMenu(new QMenu())
|
||||
contextMenu(new QMenu()),
|
||||
currentAction(CurrentAction::none)
|
||||
{
|
||||
m_ui->setupUi(this);
|
||||
|
||||
@ -108,6 +109,9 @@ Conversation::Conversation(bool muc, Models::Account* acc, Models::Element* el,
|
||||
//line->setMyName(acc->getName());
|
||||
|
||||
initializeOverlay();
|
||||
|
||||
m_ui->currentActionBadge->setVisible(false);;
|
||||
// m_ui->currentActionBadge->setText(tr("Editing message..."));
|
||||
}
|
||||
|
||||
Conversation::~Conversation()
|
||||
@ -237,7 +241,7 @@ void Conversation::onEnterPressed()
|
||||
element->feed->registerUpload(msg.getId());
|
||||
emit sendMessage(msg);
|
||||
}
|
||||
clearAttachedFiles();
|
||||
clearAttachedFiles();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -121,6 +121,11 @@ public:
|
||||
const bool isMuc;
|
||||
|
||||
protected:
|
||||
enum class CurrentAction {
|
||||
none,
|
||||
edit
|
||||
};
|
||||
|
||||
Models::Account* account;
|
||||
Models::Element* element;
|
||||
QString palJid;
|
||||
@ -142,6 +147,7 @@ protected:
|
||||
|
||||
ShadowOverlay shadow;
|
||||
QMenu* contextMenu;
|
||||
CurrentAction currentAction;
|
||||
|
||||
private:
|
||||
static bool painterInitialized;
|
||||
|
@ -279,6 +279,29 @@
|
||||
</property>
|
||||
</widget>
|
||||
</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>
|
||||
<spacer name="horizontalSpacer">
|
||||
<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">
|
||||
<html><head><meta name="qrichtext" content="1" /><style type="text/css">
|
||||
p, li { white-space: pre-wrap; }
|
||||
</style></head><body style=" font-family:'Liberation Sans'; font-size:10pt; 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>
|
||||
</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; font-family:'Liberation Sans'; font-size:10pt;"><br /></p></body></html></string>
|
||||
</property>
|
||||
<property name="acceptRichText">
|
||||
<bool>false</bool>
|
||||
@ -419,6 +442,13 @@ p, li { white-space: pre-wrap; }
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>Badge</class>
|
||||
<extends>QFrame</extends>
|
||||
<header location="global">ui/utils/badge.h</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources>
|
||||
<include location="../../resources/resources.qrc"/>
|
||||
</resources>
|
||||
|
@ -1,14 +1,10 @@
|
||||
target_sources(squawk PRIVATE
|
||||
messagedelegate.cpp
|
||||
messagedelegate.h
|
||||
#messageline.cpp
|
||||
#messageline.h
|
||||
preview.cpp
|
||||
preview.h
|
||||
messagefeed.cpp
|
||||
messagefeed.h
|
||||
feedview.cpp
|
||||
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