separating chat from conversation in ui
This commit is contained in:
parent
828d14c908
commit
e2cc1bae2e
10 changed files with 150 additions and 65 deletions
72
ui/widgets/chat.cpp
Normal file
72
ui/widgets/chat.cpp
Normal file
|
@ -0,0 +1,72 @@
|
|||
/*
|
||||
* 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 "chat.h"
|
||||
|
||||
Chat::Chat(Models::Contact* p_contact, QWidget* parent):
|
||||
Conversation(p_contact->getAccountJid(), p_contact->getAccountResource(), p_contact->getJid(), "", p_contact->getAccountName(), parent),
|
||||
contact(p_contact)
|
||||
{
|
||||
setName(p_contact->getContactName());
|
||||
updateState();
|
||||
setStatus(p_contact->getStatus());
|
||||
|
||||
connect(contact, SIGNAL(childChanged(Models::Item*, int, int)), this, SLOT(onContactChanged(Models::Item*, int, int)));
|
||||
|
||||
line->setMyName(p_contact->getAccountName());
|
||||
|
||||
Models::Contact::Messages deque;
|
||||
contact->getMessages(deque);
|
||||
|
||||
for (Models::Contact::Messages::const_iterator itr = deque.begin(), end = deque.end(); itr != end; ++itr) {
|
||||
addMessage(*itr);
|
||||
}
|
||||
}
|
||||
|
||||
Chat::~Chat()
|
||||
{
|
||||
}
|
||||
|
||||
void Chat::onContactChanged(Models::Item* item, int row, int col)
|
||||
{
|
||||
if (item == contact) {
|
||||
switch (col) {
|
||||
case 0:
|
||||
setName(contact->getContactName());
|
||||
break;
|
||||
case 3:
|
||||
updateState();
|
||||
break;
|
||||
case 5:
|
||||
setStatus(contact->getStatus());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Chat::updateState()
|
||||
{
|
||||
Shared::Availability av = contact->getAvailability();
|
||||
statusIcon->setPixmap(Shared::availabilityIcon(av, true).pixmap(40));
|
||||
statusIcon->setToolTip(Shared::availabilityNames[av]);
|
||||
}
|
||||
|
||||
void Chat::setStatus(const QString& status)
|
||||
{
|
||||
statusLabel->setText(status);
|
||||
}
|
47
ui/widgets/chat.h
Normal file
47
ui/widgets/chat.h
Normal file
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* 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 CHAT_H
|
||||
#define CHAT_H
|
||||
|
||||
#include "conversation.h"
|
||||
#include "../models/contact.h"
|
||||
|
||||
namespace Ui
|
||||
{
|
||||
class Chat;
|
||||
}
|
||||
class Chat : public Conversation
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
Chat(Models::Contact* p_contact, QWidget* parent = 0);
|
||||
~Chat();
|
||||
|
||||
protected slots:
|
||||
void onContactChanged(Models::Item* item, int row, int col);
|
||||
|
||||
private:
|
||||
void updateState();
|
||||
void setStatus(const QString& status);
|
||||
|
||||
private:
|
||||
Models::Contact* contact;
|
||||
};
|
||||
|
||||
#endif // CHAT_H
|
273
ui/widgets/conversation.cpp
Normal file
273
ui/widgets/conversation.cpp
Normal file
|
@ -0,0 +1,273 @@
|
|||
/*
|
||||
* 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 "conversation.h"
|
||||
#include "ui_conversation.h"
|
||||
#include <QDebug>
|
||||
#include <QScrollBar>
|
||||
#include <QTimer>
|
||||
#include <QGraphicsDropShadowEffect>
|
||||
#include <QFileDialog>
|
||||
|
||||
Conversation::Conversation(const QString& mJid, const QString mRes, const QString pJid, const QString pRes, const QString& acc, QWidget* parent):
|
||||
QWidget(parent),
|
||||
myJid(mJid),
|
||||
myResource(mRes),
|
||||
palJid(pJid),
|
||||
activePalResource(pRes),
|
||||
account(acc),
|
||||
line(new MessageLine()),
|
||||
m_ui(new Ui::Conversation()),
|
||||
ker(),
|
||||
thread(),
|
||||
statusIcon(0),
|
||||
statusLabel(0),
|
||||
scroll(down),
|
||||
manualSliderChange(false),
|
||||
requestingHistory(false),
|
||||
everShown(false)
|
||||
{
|
||||
m_ui->setupUi(this);
|
||||
m_ui->splitter->setSizes({300, 0});
|
||||
m_ui->splitter->setStretchFactor(1, 0);
|
||||
|
||||
statusIcon = m_ui->statusIcon;
|
||||
statusLabel = m_ui->statusLabel;
|
||||
|
||||
connect(&ker, SIGNAL(enterPressed()), this, SLOT(onEnterPressed()));
|
||||
connect(m_ui->sendButton, SIGNAL(clicked(bool)), this, SLOT(onEnterPressed()));
|
||||
connect(line, SIGNAL(resize(int)), this, SLOT(onMessagesResize(int)));
|
||||
//connect(m_ui->attachButton, SIGNAL(clicked(bool)), this, SLOT(onAttach()));
|
||||
|
||||
m_ui->messageEditor->installEventFilter(&ker);
|
||||
|
||||
QScrollBar* vs = m_ui->scrollArea->verticalScrollBar();
|
||||
m_ui->scrollArea->setWidget(line);
|
||||
vs->setBackgroundRole(QPalette::Base);
|
||||
vs->setAutoFillBackground(true);
|
||||
connect(vs, SIGNAL(valueChanged(int)), this, SLOT(onSliderValueChanged(int)));
|
||||
|
||||
applyVisualEffects();
|
||||
}
|
||||
|
||||
Conversation::~Conversation()
|
||||
{
|
||||
}
|
||||
|
||||
void Conversation::applyVisualEffects()
|
||||
{
|
||||
QGraphicsDropShadowEffect *e1 = new QGraphicsDropShadowEffect;
|
||||
e1->setBlurRadius(10);
|
||||
e1->setXOffset(0);
|
||||
e1->setYOffset(-2);
|
||||
e1->setColor(Qt::black);
|
||||
m_ui->bl->setGraphicsEffect(e1);
|
||||
|
||||
QGraphicsDropShadowEffect *e2 = new QGraphicsDropShadowEffect;
|
||||
e2->setBlurRadius(7);
|
||||
e2->setXOffset(0);
|
||||
e2->setYOffset(2);
|
||||
e2->setColor(Qt::black);
|
||||
m_ui->ul->setGraphicsEffect(e2);
|
||||
|
||||
QGraphicsDropShadowEffect *e3 = new QGraphicsDropShadowEffect;
|
||||
e3->setBlurRadius(10);
|
||||
e3->setXOffset(0);
|
||||
e3->setYOffset(2);
|
||||
e3->setColor(Qt::black);
|
||||
m_ui->ut->setGraphicsEffect(e3);
|
||||
}
|
||||
|
||||
void Conversation::setName(const QString& name)
|
||||
{
|
||||
m_ui->nameLabel->setText(name);
|
||||
setWindowTitle(name);
|
||||
line->setPalName(getJid(), name);
|
||||
}
|
||||
|
||||
QString Conversation::getAccount() const
|
||||
{
|
||||
return account;
|
||||
}
|
||||
|
||||
QString Conversation::getJid() const
|
||||
{
|
||||
return palJid;
|
||||
}
|
||||
|
||||
void Conversation::addMessage(const Shared::Message& data)
|
||||
{
|
||||
int pos = m_ui->scrollArea->verticalScrollBar()->sliderPosition();
|
||||
int max = m_ui->scrollArea->verticalScrollBar()->maximum();
|
||||
|
||||
MessageLine::Position place = line->message(data);
|
||||
if (place == MessageLine::invalid) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!data.getOutgoing()) {
|
||||
const QString& res = data.getPenPalResource();
|
||||
if (res.size() > 0) {
|
||||
setPalResource(res);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
KeyEnterReceiver::KeyEnterReceiver(QObject* parent): QObject(parent), ownEvent(false) {}
|
||||
|
||||
bool KeyEnterReceiver::eventFilter(QObject* obj, QEvent* event)
|
||||
{
|
||||
QEvent::Type type = event->type();
|
||||
if (type == QEvent::KeyPress) {
|
||||
QKeyEvent* key = static_cast<QKeyEvent*>(event);
|
||||
int k = key->key();
|
||||
if (k == Qt::Key_Enter || k == Qt::Key_Return) {
|
||||
Qt::KeyboardModifiers mod = key->modifiers();
|
||||
if (mod & Qt::ControlModifier) {
|
||||
mod = mod & ~Qt::ControlModifier;
|
||||
QKeyEvent* nEvent = new QKeyEvent(event->type(), k, mod, key->text(), key->isAutoRepeat(), key->count());
|
||||
QCoreApplication::postEvent(obj, nEvent);
|
||||
ownEvent = true;
|
||||
return true;
|
||||
} else {
|
||||
if (ownEvent) {
|
||||
ownEvent = false;
|
||||
} else {
|
||||
emit enterPressed();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return QObject::eventFilter(obj, event);
|
||||
}
|
||||
|
||||
QString Conversation::getPalResource() const
|
||||
{
|
||||
return activePalResource;
|
||||
}
|
||||
|
||||
void Conversation::setPalResource(const QString& res)
|
||||
{
|
||||
activePalResource = res;
|
||||
}
|
||||
|
||||
void Conversation::onEnterPressed()
|
||||
{
|
||||
QString body(m_ui->messageEditor->toPlainText());
|
||||
|
||||
if (body.size() > 0) {
|
||||
m_ui->messageEditor->clear();
|
||||
Shared::Message msg(Shared::Message::chat);
|
||||
msg.setFromJid(myJid);
|
||||
msg.setFromResource(myResource);
|
||||
msg.setToJid(palJid);
|
||||
msg.setToResource(activePalResource);
|
||||
msg.setBody(body);
|
||||
msg.setOutgoing(true);
|
||||
msg.generateRandomId();
|
||||
msg.setCurrentTime();
|
||||
addMessage(msg);
|
||||
emit sendMessage(msg);
|
||||
}
|
||||
}
|
||||
|
||||
void Conversation::onMessagesResize(int amount)
|
||||
{
|
||||
manualSliderChange = true;
|
||||
switch (scroll) {
|
||||
case down:
|
||||
m_ui->scrollArea->verticalScrollBar()->setValue(m_ui->scrollArea->verticalScrollBar()->maximum());
|
||||
break;
|
||||
case keep: {
|
||||
int max = m_ui->scrollArea->verticalScrollBar()->maximum();
|
||||
int value = m_ui->scrollArea->verticalScrollBar()->value() + amount;
|
||||
m_ui->scrollArea->verticalScrollBar()->setValue(value);
|
||||
|
||||
if (value == max) {
|
||||
scroll = down;
|
||||
} else {
|
||||
scroll = nothing;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
manualSliderChange = false;
|
||||
}
|
||||
|
||||
void Conversation::onSliderValueChanged(int value)
|
||||
{
|
||||
if (!manualSliderChange) {
|
||||
if (value == m_ui->scrollArea->verticalScrollBar()->maximum()) {
|
||||
scroll = down;
|
||||
} else {
|
||||
if (!requestingHistory && value == 0) {
|
||||
m_ui->historyStatus->setPixmap(Shared::icon("view-refresh", true).pixmap(25));
|
||||
requestingHistory = true;
|
||||
emit requestArchive(line->firstMessageId());
|
||||
}
|
||||
scroll = nothing;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Conversation::responseArchive(const std::list<Shared::Message> list)
|
||||
{
|
||||
requestingHistory = false;
|
||||
scroll = keep;
|
||||
|
||||
m_ui->historyStatus->clear();
|
||||
for (std::list<Shared::Message>::const_iterator itr = list.begin(), end = list.end(); itr != end; ++itr) {
|
||||
addMessage(*itr);
|
||||
}
|
||||
}
|
||||
|
||||
void Conversation::showEvent(QShowEvent* event)
|
||||
{
|
||||
if (!everShown) {
|
||||
everShown = true;
|
||||
m_ui->historyStatus->setPixmap(Shared::icon("view-refresh", true).pixmap(25));
|
||||
requestingHistory = true;
|
||||
emit requestArchive(line->firstMessageId());
|
||||
}
|
||||
emit shown();
|
||||
|
||||
QWidget::showEvent(event);
|
||||
}
|
||||
|
||||
void Conversation::onAttach()
|
||||
{
|
||||
QFileDialog* d = new QFileDialog(this, "Chose a file to send");
|
||||
d->setFileMode(QFileDialog::ExistingFile);
|
||||
|
||||
connect(d, SIGNAL(accepted()), this, SLOT(onFileSelected()));
|
||||
connect(d, SIGNAL(rejected()), d, SLOT(deleteLater()));
|
||||
|
||||
d->show();
|
||||
}
|
||||
|
||||
void Conversation::onFileSelected()
|
||||
{
|
||||
QFileDialog* d = static_cast<QFileDialog*>(sender());
|
||||
|
||||
qDebug() << d->selectedFiles();
|
||||
|
||||
d->deleteLater();
|
||||
}
|
100
ui/widgets/conversation.h
Normal file
100
ui/widgets/conversation.h
Normal file
|
@ -0,0 +1,100 @@
|
|||
/*
|
||||
* 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 CONVERSATION_H
|
||||
#define CONVERSATION_H
|
||||
|
||||
#include <QWidget>
|
||||
#include <QScopedPointer>
|
||||
#include "../../global.h"
|
||||
#include "messageline.h"
|
||||
|
||||
namespace Ui
|
||||
{
|
||||
class Conversation;
|
||||
}
|
||||
|
||||
class KeyEnterReceiver : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
KeyEnterReceiver(QObject* parent = 0);
|
||||
protected:
|
||||
bool ownEvent;
|
||||
bool eventFilter(QObject* obj, QEvent* event);
|
||||
|
||||
signals:
|
||||
void enterPressed();
|
||||
};
|
||||
|
||||
class Conversation : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
Conversation(const QString& mJid, const QString mRes, const QString pJid, const QString pRes, const QString& acc, QWidget* parent = 0);
|
||||
~Conversation();
|
||||
|
||||
QString getJid() const;
|
||||
QString getAccount() const;
|
||||
QString getPalResource() const;
|
||||
void addMessage(const Shared::Message& data);
|
||||
|
||||
void setPalResource(const QString& res);
|
||||
void responseArchive(const std::list<Shared::Message> list);
|
||||
void showEvent(QShowEvent * event) override;
|
||||
|
||||
signals:
|
||||
void sendMessage(const Shared::Message& message);
|
||||
void requestArchive(const QString& before);
|
||||
void shown();
|
||||
|
||||
protected:
|
||||
void setName(const QString& name);
|
||||
void applyVisualEffects();
|
||||
|
||||
protected slots:
|
||||
void onEnterPressed();
|
||||
void onMessagesResize(int amount);
|
||||
void onSliderValueChanged(int value);
|
||||
void onAttach();
|
||||
void onFileSelected();
|
||||
|
||||
protected:
|
||||
enum Scroll {
|
||||
nothing,
|
||||
keep,
|
||||
down
|
||||
};
|
||||
QString myJid;
|
||||
QString myResource;
|
||||
QString palJid;
|
||||
QString activePalResource;
|
||||
QString account;
|
||||
MessageLine* line;
|
||||
QScopedPointer<Ui::Conversation> m_ui;
|
||||
KeyEnterReceiver ker;
|
||||
QString thread;
|
||||
QLabel* statusIcon;
|
||||
QLabel* statusLabel;
|
||||
Scroll scroll;
|
||||
bool manualSliderChange;
|
||||
bool requestingHistory;
|
||||
bool everShown;
|
||||
};
|
||||
|
||||
#endif // CONVERSATION_H
|
453
ui/widgets/conversation.ui
Normal file
453
ui/widgets/conversation.ui
Normal file
|
@ -0,0 +1,453 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>Conversation</class>
|
||||
<widget class="QWidget" name="Conversation">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>572</width>
|
||||
<height>485</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QSplitter" name="splitter">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::NoFrame</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Plain</enum>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="childrenCollapsible">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<widget class="QWidget" name="widget" native="true">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QWidget" name="widget_3" native="true">
|
||||
<property name="autoFillBackground">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="statusIcon">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="nameLabel">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="statusLabel">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_2">
|
||||
<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="QLabel" name="historyStatus">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="avatar">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QWidget" name="ul" native="true">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>2</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="baseSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>2</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="autoFillBackground">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QScrollArea" name="scrollArea">
|
||||
<property name="autoFillBackground">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::NoFrame</enum>
|
||||
</property>
|
||||
<property name="lineWidth">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="midLineWidth">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="horizontalScrollBarPolicy">
|
||||
<enum>Qt::ScrollBarAlwaysOff</enum>
|
||||
</property>
|
||||
<property name="sizeAdjustPolicy">
|
||||
<enum>QAbstractScrollArea::AdjustToContents</enum>
|
||||
</property>
|
||||
<property name="widgetResizable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<widget class="QWidget" name="scrollAreaWidgetContents">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>572</width>
|
||||
<height>116</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QWidget" name="bl" native="true">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>2</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>16777215</width>
|
||||
<height>2</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="baseSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>2</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="autoFillBackground">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
<zorder>scrollArea</zorder>
|
||||
<zorder>bl</zorder>
|
||||
<zorder>ul</zorder>
|
||||
<zorder>widget_3</zorder>
|
||||
</widget>
|
||||
<widget class="QWidget" name="widget_2" native="true">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="autoFillBackground">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QWidget" name="panel" native="true">
|
||||
<property name="autoFillBackground">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_4">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QPushButton" name="smilesButton">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset theme="smiley-shape">
|
||||
<normaloff>.</normaloff>.</iconset>
|
||||
</property>
|
||||
<property name="flat">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<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="QPushButton" name="attachButton">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset theme="mail-attachment-symbolic"/>
|
||||
</property>
|
||||
<property name="flat">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="clearButton">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset theme="edit-clear-all">
|
||||
<normaloff>.</normaloff>.</iconset>
|
||||
</property>
|
||||
<property name="flat">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="sendButton">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset theme="document-send">
|
||||
<normaloff>.</normaloff>.</iconset>
|
||||
</property>
|
||||
<property name="flat">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QWidget" name="ut" native="true">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>2</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>16777215</width>
|
||||
<height>2</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="baseSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>2</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="autoFillBackground">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPlainTextEdit" name="messageEditor">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>30</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="baseSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>30</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::NoFrame</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
<zorder>messageEditor</zorder>
|
||||
<zorder>ut</zorder>
|
||||
<zorder>panel</zorder>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
170
ui/widgets/messageline.cpp
Normal file
170
ui/widgets/messageline.cpp
Normal file
|
@ -0,0 +1,170 @@
|
|||
/*
|
||||
* 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 <QGraphicsDropShadowEffect>
|
||||
|
||||
const QRegExp urlReg("^(?!<img\\ssrc=\")((?:https?|ftp)://\\S+)");
|
||||
const QRegExp imgReg("((?:https?|ftp)://\\S+\\.(?:jpg|jpeg|png|svg|gif))");
|
||||
|
||||
MessageLine::MessageLine(QWidget* parent):
|
||||
QWidget(parent),
|
||||
messageIndex(),
|
||||
messageOrder(),
|
||||
layout(new QVBoxLayout()),
|
||||
myName(),
|
||||
palNames(),
|
||||
views()
|
||||
{
|
||||
setLayout(layout);
|
||||
setBackgroundRole(QPalette::Base);
|
||||
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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
Shared::Message* copy = new Shared::Message(msg);
|
||||
std::pair<Order::const_iterator, bool> result = messageOrder.insert(std::make_pair(msg.getTime(), copy));
|
||||
if (!result.second) {
|
||||
qDebug() << "Error appending a message into a message list - seems like the time of that message exactly matches the time of some other message, can't put them in order, skipping yet";
|
||||
delete copy;
|
||||
return invalid;
|
||||
}
|
||||
messageIndex.insert(std::make_pair(id, copy));
|
||||
int 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;
|
||||
}
|
||||
|
||||
QVBoxLayout* vBox = new QVBoxLayout();
|
||||
QHBoxLayout* hBox = new QHBoxLayout();
|
||||
QWidget* message = new QWidget();
|
||||
message->setLayout(vBox);
|
||||
message->setBackgroundRole(QPalette::AlternateBase);
|
||||
message->setAutoFillBackground(true);
|
||||
|
||||
|
||||
QString bd = msg.getBody();
|
||||
//bd.replace(imgReg, "<img src=\"\\1\"/>");
|
||||
bd.replace(urlReg, "<a href=\"\\1\">\\1</a>");
|
||||
QLabel* body = new QLabel(bd);
|
||||
body->setTextInteractionFlags(body->textInteractionFlags() | Qt::TextSelectableByMouse);
|
||||
QLabel* sender = new QLabel();
|
||||
QLabel* time = new QLabel(msg.getTime().toLocalTime().toString());
|
||||
QFont dFont = time->font();
|
||||
dFont.setItalic(true);
|
||||
dFont.setPointSize(dFont.pointSize() - 2);
|
||||
time->setFont(dFont);
|
||||
time->setForegroundRole(QPalette::ToolTipText);
|
||||
QFont f;
|
||||
f.setBold(true);
|
||||
sender->setFont(f);
|
||||
|
||||
body->setWordWrap(true);
|
||||
body->setOpenExternalLinks(true);
|
||||
|
||||
vBox->addWidget(sender);
|
||||
vBox->addWidget(body);
|
||||
vBox->addWidget(time);
|
||||
|
||||
QGraphicsDropShadowEffect *effect = new QGraphicsDropShadowEffect;
|
||||
effect->setBlurRadius(10);
|
||||
effect->setXOffset(1);
|
||||
effect->setYOffset(1);
|
||||
effect->setColor(Qt::black);
|
||||
|
||||
message->setGraphicsEffect(effect);
|
||||
|
||||
if (msg.getOutgoing()) {
|
||||
//body->setAlignment(Qt::AlignRight);
|
||||
sender->setAlignment(Qt::AlignRight);
|
||||
time->setAlignment(Qt::AlignRight);
|
||||
sender->setText(myName);
|
||||
hBox->addStretch();
|
||||
hBox->addWidget(message);
|
||||
} else {
|
||||
QString jid = msg.getFromJid();
|
||||
std::map<QString, QString>::iterator itr = palNames.find(jid);
|
||||
if (itr != palNames.end()) {
|
||||
sender->setText(itr->second);
|
||||
} else {
|
||||
sender->setText(jid);
|
||||
}
|
||||
hBox->addWidget(message);
|
||||
hBox->addStretch();
|
||||
}
|
||||
|
||||
if (res == end) {
|
||||
layout->addLayout(hBox);
|
||||
} else {
|
||||
layout->insertLayout(index, hBox);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
void MessageLine::setMyName(const QString& name)
|
||||
{
|
||||
myName = 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;
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
75
ui/widgets/messageline.h
Normal file
75
ui/widgets/messageline.h
Normal file
|
@ -0,0 +1,75 @@
|
|||
/*
|
||||
* 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 "../global.h"
|
||||
|
||||
class MessageLine : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
enum Position {
|
||||
beggining,
|
||||
middle,
|
||||
end,
|
||||
invalid
|
||||
};
|
||||
MessageLine(QWidget* parent = 0);
|
||||
~MessageLine();
|
||||
|
||||
Position message(const Shared::Message& msg);
|
||||
void setMyName(const QString& name);
|
||||
void setPalName(const QString& jid, const QString& name);
|
||||
QString firstMessageId() const;
|
||||
void showBusyIndicator();
|
||||
void hideBusyIndicator();
|
||||
|
||||
signals:
|
||||
void resize(int amount);
|
||||
|
||||
protected:
|
||||
void resizeEvent(QResizeEvent * event) override;
|
||||
|
||||
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, Shared::Message*> Order;
|
||||
typedef std::map<QString, Shared::Message*> Index;
|
||||
Index messageIndex;
|
||||
Order messageOrder;
|
||||
QVBoxLayout* layout;
|
||||
|
||||
QString myName;
|
||||
std::map<QString, QString> palNames;
|
||||
std::deque<QHBoxLayout*> views;
|
||||
};
|
||||
|
||||
#endif // MESSAGELINE_H
|
Loading…
Add table
Add a link
Reference in a new issue