forked from blue/squawk
merge conflicts, text copying from context menu in message line
This commit is contained in:
commit
c3a45ec58c
38 changed files with 1221 additions and 798 deletions
|
@ -2,8 +2,6 @@ target_sources(squawk PRIVATE
|
|||
squawk.cpp
|
||||
squawk.h
|
||||
squawk.ui
|
||||
dialogqueue.cpp
|
||||
dialogqueue.h
|
||||
)
|
||||
|
||||
add_subdirectory(models)
|
||||
|
|
|
@ -1,174 +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 "dialogqueue.h"
|
||||
#include "squawk.h"
|
||||
#include <QDebug>
|
||||
|
||||
DialogQueue::DialogQueue(Squawk* p_squawk):
|
||||
QObject(),
|
||||
currentSource(),
|
||||
currentAction(none),
|
||||
queue(),
|
||||
collection(queue.get<0>()),
|
||||
sequence(queue.get<1>()),
|
||||
prompt(nullptr),
|
||||
squawk(p_squawk)
|
||||
{
|
||||
}
|
||||
|
||||
DialogQueue::~DialogQueue()
|
||||
{
|
||||
}
|
||||
|
||||
bool DialogQueue::addAction(const QString& source, DialogQueue::Action action)
|
||||
{
|
||||
if (action == none) {
|
||||
return false;
|
||||
}
|
||||
if (currentAction == none) {
|
||||
currentAction = action;
|
||||
currentSource = source;
|
||||
performNextAction();
|
||||
return true;
|
||||
} else {
|
||||
if (currentAction != action || currentSource != source) {
|
||||
std::pair<Queue::iterator, bool> result = queue.emplace(source, action);
|
||||
return result.second;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool DialogQueue::cancelAction(const QString& source, DialogQueue::Action action)
|
||||
{
|
||||
if (source == currentSource && action == currentAction) {
|
||||
actionDone();
|
||||
return true;
|
||||
} else {
|
||||
Collection::iterator itr = collection.find(ActionId{source, action});
|
||||
if (itr != collection.end()) {
|
||||
collection.erase(itr);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DialogQueue::performNextAction()
|
||||
{
|
||||
switch (currentAction) {
|
||||
case none:
|
||||
actionDone();
|
||||
break;
|
||||
case askPassword: {
|
||||
QInputDialog* dialog = new QInputDialog(squawk);
|
||||
prompt = dialog;
|
||||
connect(dialog, &QDialog::accepted, this, &DialogQueue::onPropmtAccepted);
|
||||
connect(dialog, &QDialog::rejected, this, &DialogQueue::onPropmtRejected);
|
||||
dialog->setInputMode(QInputDialog::TextInput);
|
||||
dialog->setTextEchoMode(QLineEdit::Password);
|
||||
dialog->setLabelText(tr("Input the password for account %1").arg(currentSource));
|
||||
dialog->setWindowTitle(tr("Password for account %1").arg(currentSource));
|
||||
dialog->setTextValue("");
|
||||
dialog->exec();
|
||||
}
|
||||
break;
|
||||
case askCredentials: {
|
||||
CredentialsPrompt* dialog = new CredentialsPrompt(squawk);
|
||||
prompt = dialog;
|
||||
connect(dialog, &QDialog::accepted, this, &DialogQueue::onPropmtAccepted);
|
||||
connect(dialog, &QDialog::rejected, this, &DialogQueue::onPropmtRejected);
|
||||
Models::Account* acc = squawk->rosterModel.getAccount(currentSource);
|
||||
dialog->setAccount(currentSource);
|
||||
dialog->setLogin(acc->getLogin());
|
||||
dialog->setPassword(acc->getPassword());
|
||||
dialog->exec();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void DialogQueue::onPropmtAccepted()
|
||||
{
|
||||
switch (currentAction) {
|
||||
case none:
|
||||
break;
|
||||
case askPassword: {
|
||||
QInputDialog* dialog = static_cast<QInputDialog*>(prompt);
|
||||
emit squawk->responsePassword(currentSource, dialog->textValue());
|
||||
}
|
||||
break;
|
||||
case askCredentials: {
|
||||
CredentialsPrompt* dialog = static_cast<CredentialsPrompt*>(prompt);
|
||||
emit squawk->modifyAccountRequest(currentSource, {
|
||||
{"login", dialog->getLogin()},
|
||||
{"password", dialog->getPassword()}
|
||||
});
|
||||
}
|
||||
break;
|
||||
}
|
||||
actionDone();
|
||||
}
|
||||
|
||||
void DialogQueue::onPropmtRejected()
|
||||
{
|
||||
switch (currentAction) {
|
||||
case none:
|
||||
break;
|
||||
case askPassword:
|
||||
case askCredentials:
|
||||
emit squawk->disconnectAccount(currentSource);
|
||||
break;
|
||||
}
|
||||
actionDone();
|
||||
}
|
||||
|
||||
void DialogQueue::actionDone()
|
||||
{
|
||||
prompt->deleteLater();
|
||||
prompt = nullptr;
|
||||
|
||||
if (queue.empty()) {
|
||||
currentAction = none;
|
||||
currentSource = "";
|
||||
} else {
|
||||
Sequence::iterator itr = sequence.begin();
|
||||
currentAction = itr->action;
|
||||
currentSource = itr->source;
|
||||
sequence.erase(itr);
|
||||
performNextAction();
|
||||
}
|
||||
}
|
||||
|
||||
DialogQueue::ActionId::ActionId(const QString& p_source, DialogQueue::Action p_action):
|
||||
source(p_source),
|
||||
action(p_action) {}
|
||||
|
||||
bool DialogQueue::ActionId::operator < (const DialogQueue::ActionId& other) const
|
||||
{
|
||||
if (action == other.action) {
|
||||
return source < other.source;
|
||||
} else {
|
||||
return action < other.action;
|
||||
}
|
||||
}
|
||||
|
||||
DialogQueue::ActionId::ActionId(const DialogQueue::ActionId& other):
|
||||
source(other.source),
|
||||
action(other.action) {}
|
|
@ -1,91 +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 DIALOGQUEUE_H
|
||||
#define DIALOGQUEUE_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QInputDialog>
|
||||
|
||||
#include <boost/multi_index_container.hpp>
|
||||
#include <boost/multi_index/ordered_index.hpp>
|
||||
#include <boost/multi_index/sequenced_index.hpp>
|
||||
|
||||
#include <ui/widgets/accounts/credentialsprompt.h>
|
||||
|
||||
class Squawk;
|
||||
|
||||
class DialogQueue : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
enum Action {
|
||||
none,
|
||||
askPassword,
|
||||
askCredentials
|
||||
};
|
||||
|
||||
DialogQueue(Squawk* squawk);
|
||||
~DialogQueue();
|
||||
|
||||
bool addAction(const QString& source, Action action);
|
||||
bool cancelAction(const QString& source, Action action);
|
||||
|
||||
private:
|
||||
void performNextAction();
|
||||
void actionDone();
|
||||
|
||||
private slots:
|
||||
void onPropmtAccepted();
|
||||
void onPropmtRejected();
|
||||
|
||||
private:
|
||||
QString currentSource;
|
||||
Action currentAction;
|
||||
|
||||
struct ActionId {
|
||||
public:
|
||||
ActionId(const QString& p_source, Action p_action);
|
||||
ActionId(const ActionId& other);
|
||||
|
||||
const QString source;
|
||||
const Action action;
|
||||
|
||||
bool operator < (const ActionId& other) const;
|
||||
};
|
||||
|
||||
typedef boost::multi_index_container <
|
||||
ActionId,
|
||||
boost::multi_index::indexed_by <
|
||||
boost::multi_index::ordered_unique <
|
||||
boost::multi_index::identity <ActionId>
|
||||
>,
|
||||
boost::multi_index::sequenced<>
|
||||
>
|
||||
> Queue;
|
||||
|
||||
typedef Queue::nth_index<0>::type Collection;
|
||||
typedef Queue::nth_index<1>::type Sequence;
|
||||
|
||||
Queue queue;
|
||||
Collection& collection;
|
||||
Sequence& sequence;
|
||||
|
||||
QDialog* prompt;
|
||||
Squawk* squawk;
|
||||
};
|
||||
|
||||
#endif // DIALOGQUEUE_H
|
|
@ -155,6 +155,16 @@ void Models::Contact::removePresence(const QString& name)
|
|||
}
|
||||
}
|
||||
|
||||
Models::Presence * Models::Contact::getPresence(const QString& name)
|
||||
{
|
||||
QMap<QString, Presence*>::iterator itr = presences.find(name);
|
||||
if (itr == presences.end()) {
|
||||
return nullptr;
|
||||
} else {
|
||||
return itr.value();
|
||||
}
|
||||
}
|
||||
|
||||
void Models::Contact::refresh()
|
||||
{
|
||||
QDateTime lastActivity;
|
||||
|
|
|
@ -51,6 +51,7 @@ public:
|
|||
|
||||
void addPresence(const QString& name, const QMap<QString, QVariant>& data);
|
||||
void removePresence(const QString& name);
|
||||
Presence* getPresence(const QString& name);
|
||||
|
||||
QString getContactName() const;
|
||||
QString getStatus() const;
|
||||
|
|
|
@ -134,6 +134,11 @@ unsigned int Models::Element::getMessagesCount() const
|
|||
return feed->unreadMessagesCount();
|
||||
}
|
||||
|
||||
bool Models::Element::markMessageAsRead(const QString& id) const
|
||||
{
|
||||
return feed->markMessageAsRead(id);
|
||||
}
|
||||
|
||||
void Models::Element::addMessage(const Shared::Message& data)
|
||||
{
|
||||
feed->addMessage(data);
|
||||
|
@ -171,6 +176,7 @@ void Models::Element::fileError(const QString& messageId, const QString& error,
|
|||
|
||||
void Models::Element::onFeedUnreadMessagesCountChanged()
|
||||
{
|
||||
emit unreadMessagesCountChanged();
|
||||
if (type == contact) {
|
||||
changed(4);
|
||||
} else if (type == room) {
|
||||
|
|
|
@ -42,6 +42,7 @@ public:
|
|||
void addMessage(const Shared::Message& data);
|
||||
void changeMessage(const QString& id, const QMap<QString, QVariant>& data);
|
||||
unsigned int getMessagesCount() const;
|
||||
bool markMessageAsRead(const QString& id) const;
|
||||
void responseArchive(const std::list<Shared::Message> list, bool last);
|
||||
bool isRoom() const;
|
||||
void fileProgress(const QString& messageId, qreal value, bool up);
|
||||
|
@ -52,6 +53,7 @@ signals:
|
|||
void requestArchive(const QString& before);
|
||||
void fileDownloadRequest(const QString& url);
|
||||
void unnoticedMessage(const QString& account, const Shared::Message& msg);
|
||||
void unreadMessagesCountChanged();
|
||||
void localPathInvalid(const QString& path);
|
||||
|
||||
protected:
|
||||
|
|
|
@ -264,6 +264,16 @@ void Models::Room::removeParticipant(const QString& p_name)
|
|||
}
|
||||
}
|
||||
|
||||
Models::Participant * Models::Room::getParticipant(const QString& p_name)
|
||||
{
|
||||
std::map<QString, Participant*>::const_iterator itr = participants.find(p_name);
|
||||
if (itr == participants.end()) {
|
||||
return nullptr;
|
||||
} else {
|
||||
return itr->second;
|
||||
}
|
||||
}
|
||||
|
||||
void Models::Room::handleParticipantUpdate(std::map<QString, Participant*>::const_iterator itr, const QMap<QString, QVariant>& data)
|
||||
{
|
||||
Participant* part = itr->second;
|
||||
|
|
|
@ -58,6 +58,7 @@ public:
|
|||
void addParticipant(const QString& name, const QMap<QString, QVariant>& data);
|
||||
void changeParticipant(const QString& name, const QMap<QString, QVariant>& data);
|
||||
void removeParticipant(const QString& name);
|
||||
Participant* getParticipant(const QString& name);
|
||||
|
||||
void toOfflineState() override;
|
||||
QString getDisplayedName() const override;
|
||||
|
|
|
@ -463,6 +463,7 @@ void Models::Roster::addContact(const QString& account, const QString& jid, cons
|
|||
connect(contact, &Contact::fileDownloadRequest, this, &Roster::fileDownloadRequest);
|
||||
connect(contact, &Contact::unnoticedMessage, this, &Roster::unnoticedMessage);
|
||||
connect(contact, &Contact::localPathInvalid, this, &Roster::localPathInvalid);
|
||||
connect(contact, &Contact::unreadMessagesCountChanged, this, &Roster::recalculateUnreadMessages);
|
||||
contacts.insert(std::make_pair(id, contact));
|
||||
} else {
|
||||
contact = itr->second;
|
||||
|
@ -548,8 +549,8 @@ void Models::Roster::removeGroup(const QString& account, const QString& name)
|
|||
|
||||
void Models::Roster::changeContact(const QString& account, const QString& jid, const QMap<QString, QVariant>& data)
|
||||
{
|
||||
Element* el = getElement({account, jid});
|
||||
if (el != NULL) {
|
||||
Element* el = getElement(ElId(account, jid));
|
||||
if (el != nullptr) {
|
||||
for (QMap<QString, QVariant>::const_iterator itr = data.begin(), end = data.end(); itr != end; ++itr) {
|
||||
el->update(itr.key(), itr.value());
|
||||
}
|
||||
|
@ -558,8 +559,8 @@ void Models::Roster::changeContact(const QString& account, const QString& jid, c
|
|||
|
||||
void Models::Roster::changeMessage(const QString& account, const QString& jid, const QString& id, const QMap<QString, QVariant>& data)
|
||||
{
|
||||
Element* el = getElement({account, jid});
|
||||
if (el != NULL) {
|
||||
Element* el = getElement(ElId(account, jid));
|
||||
if (el != nullptr) {
|
||||
el->changeMessage(id, data);
|
||||
} else {
|
||||
qDebug() << "A request to change a message of the contact " << jid << " in the account " << account << " but it wasn't found";
|
||||
|
@ -706,8 +707,8 @@ void Models::Roster::removePresence(const QString& account, const QString& jid,
|
|||
|
||||
void Models::Roster::addMessage(const QString& account, const Shared::Message& data)
|
||||
{
|
||||
Element* el = getElement({account, data.getPenPalJid()});
|
||||
if (el != NULL) {
|
||||
Element* el = getElement(ElId(account, data.getPenPalJid()));
|
||||
if (el != nullptr) {
|
||||
el->addMessage(data);
|
||||
}
|
||||
}
|
||||
|
@ -763,7 +764,7 @@ void Models::Roster::removeAccount(const QString& account)
|
|||
acc->deleteLater();
|
||||
}
|
||||
|
||||
QString Models::Roster::getContactName(const QString& account, const QString& jid)
|
||||
QString Models::Roster::getContactName(const QString& account, const QString& jid) const
|
||||
{
|
||||
ElId id(account, jid);
|
||||
std::map<ElId, Contact*>::const_iterator cItr = contacts.find(id);
|
||||
|
@ -801,10 +802,11 @@ void Models::Roster::addRoom(const QString& account, const QString jid, const QM
|
|||
}
|
||||
|
||||
Room* room = new Room(acc, jid, data);
|
||||
connect(room, &Contact::requestArchive, this, &Roster::onElementRequestArchive);
|
||||
connect(room, &Contact::fileDownloadRequest, this, &Roster::fileDownloadRequest);
|
||||
connect(room, &Contact::unnoticedMessage, this, &Roster::unnoticedMessage);
|
||||
connect(room, &Contact::localPathInvalid, this, &Roster::localPathInvalid);
|
||||
connect(room, &Room::requestArchive, this, &Roster::onElementRequestArchive);
|
||||
connect(room, &Room::fileDownloadRequest, this, &Roster::fileDownloadRequest);
|
||||
connect(room, &Room::unnoticedMessage, this, &Roster::unnoticedMessage);
|
||||
connect(room, &Room::localPathInvalid, this, &Roster::localPathInvalid);
|
||||
connect(room, &Room::unreadMessagesCountChanged, this, &Roster::recalculateUnreadMessages);
|
||||
rooms.insert(std::make_pair(id, room));
|
||||
acc->appendChild(room);
|
||||
}
|
||||
|
@ -907,7 +909,7 @@ bool Models::Roster::groupHasContact(const QString& account, const QString& grou
|
|||
}
|
||||
}
|
||||
|
||||
QString Models::Roster::getContactIconPath(const QString& account, const QString& jid, const QString& resource)
|
||||
QString Models::Roster::getContactIconPath(const QString& account, const QString& jid, const QString& resource) const
|
||||
{
|
||||
ElId id(account, jid);
|
||||
std::map<ElId, Contact*>::const_iterator cItr = contacts.find(id);
|
||||
|
@ -927,9 +929,36 @@ QString Models::Roster::getContactIconPath(const QString& account, const QString
|
|||
return path;
|
||||
}
|
||||
|
||||
Models::Account * Models::Roster::getAccount(const QString& name)
|
||||
Models::Account * Models::Roster::getAccount(const QString& name) {
|
||||
return const_cast<Models::Account*>(getAccountConst(name));}
|
||||
|
||||
const Models::Account * Models::Roster::getAccountConst(const QString& name) const {
|
||||
return accounts.at(name);}
|
||||
|
||||
const Models::Element * Models::Roster::getElementConst(const Models::Roster::ElId& id) const
|
||||
{
|
||||
return accounts.find(name)->second;
|
||||
std::map<ElId, Contact*>::const_iterator cItr = contacts.find(id);
|
||||
|
||||
if (cItr != contacts.end()) {
|
||||
return cItr->second;
|
||||
} else {
|
||||
std::map<ElId, Room*>::const_iterator rItr = rooms.find(id);
|
||||
if (rItr != rooms.end()) {
|
||||
return rItr->second;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool Models::Roster::markMessageAsRead(const Models::Roster::ElId& elementId, const QString& messageId)
|
||||
{
|
||||
const Element* el = getElementConst(elementId);
|
||||
if (el != nullptr) {
|
||||
return el->markMessageAsRead(messageId);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
QModelIndex Models::Roster::getAccountIndex(const QString& name)
|
||||
|
@ -948,7 +977,7 @@ QModelIndex Models::Roster::getGroupIndex(const QString& account, const QString&
|
|||
if (itr == accounts.end()) {
|
||||
return QModelIndex();
|
||||
} else {
|
||||
std::map<ElId, Group*>::const_iterator gItr = groups.find({account, name});
|
||||
std::map<ElId, Group*>::const_iterator gItr = groups.find(ElId(account, name));
|
||||
if (gItr == groups.end()) {
|
||||
return QModelIndex();
|
||||
} else {
|
||||
|
@ -958,6 +987,48 @@ QModelIndex Models::Roster::getGroupIndex(const QString& account, const QString&
|
|||
}
|
||||
}
|
||||
|
||||
QModelIndex Models::Roster::getContactIndex(const QString& account, const QString& jid, const QString& resource)
|
||||
{
|
||||
std::map<QString, Account*>::const_iterator itr = accounts.find(account);
|
||||
if (itr == accounts.end()) {
|
||||
return QModelIndex();
|
||||
} else {
|
||||
Account* acc = itr->second;
|
||||
QModelIndex accIndex = index(acc->row(), 0, QModelIndex());
|
||||
std::map<ElId, Contact*>::const_iterator cItr = contacts.find(ElId(account, jid));
|
||||
if (cItr != contacts.end()) {
|
||||
QModelIndex contactIndex = index(acc->getContact(jid), 0, accIndex);
|
||||
if (resource.size() == 0) {
|
||||
return contactIndex;
|
||||
} else {
|
||||
Presence* pres = cItr->second->getPresence(resource);
|
||||
if (pres != nullptr) {
|
||||
return index(pres->row(), 0, contactIndex);
|
||||
} else {
|
||||
return contactIndex;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
std::map<ElId, Room*>::const_iterator rItr = rooms.find(ElId(account, jid));
|
||||
if (rItr != rooms.end()) {
|
||||
QModelIndex roomIndex = index(rItr->second->row(), 0, accIndex);
|
||||
if (resource.size() == 0) {
|
||||
return roomIndex;
|
||||
} else {
|
||||
Participant* part = rItr->second->getParticipant(resource);
|
||||
if (part != nullptr) {
|
||||
return index(part->row(), 0, roomIndex);
|
||||
} else {
|
||||
return roomIndex;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return QModelIndex();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Models::Roster::onElementRequestArchive(const QString& before)
|
||||
{
|
||||
Element* el = static_cast<Element*>(sender());
|
||||
|
@ -968,7 +1039,7 @@ void Models::Roster::responseArchive(const QString& account, const QString& jid,
|
|||
{
|
||||
ElId id(account, jid);
|
||||
Element* el = getElement(id);
|
||||
if (el != NULL) {
|
||||
if (el != nullptr) {
|
||||
el->responseArchive(list, last);
|
||||
}
|
||||
}
|
||||
|
@ -976,8 +1047,8 @@ void Models::Roster::responseArchive(const QString& account, const QString& jid,
|
|||
void Models::Roster::fileProgress(const std::list<Shared::MessageInfo>& msgs, qreal value, bool up)
|
||||
{
|
||||
for (const Shared::MessageInfo& info : msgs) {
|
||||
Element* el = getElement({info.account, info.jid});
|
||||
if (el != NULL) {
|
||||
Element* el = getElement(ElId(info.account, info.jid));
|
||||
if (el != nullptr) {
|
||||
el->fileProgress(info.messageId, value, up);
|
||||
}
|
||||
}
|
||||
|
@ -986,8 +1057,8 @@ void Models::Roster::fileProgress(const std::list<Shared::MessageInfo>& msgs, qr
|
|||
void Models::Roster::fileComplete(const std::list<Shared::MessageInfo>& msgs, bool up)
|
||||
{
|
||||
for (const Shared::MessageInfo& info : msgs) {
|
||||
Element* el = getElement({info.account, info.jid});
|
||||
if (el != NULL) {
|
||||
Element* el = getElement(ElId(info.account, info.jid));
|
||||
if (el != nullptr) {
|
||||
el->fileComplete(info.messageId, up);
|
||||
}
|
||||
}
|
||||
|
@ -996,8 +1067,8 @@ void Models::Roster::fileComplete(const std::list<Shared::MessageInfo>& msgs, bo
|
|||
void Models::Roster::fileError(const std::list<Shared::MessageInfo>& msgs, const QString& err, bool up)
|
||||
{
|
||||
for (const Shared::MessageInfo& info : msgs) {
|
||||
Element* el = getElement({info.account, info.jid});
|
||||
if (el != NULL) {
|
||||
Element* el = getElement(ElId(info.account, info.jid));
|
||||
if (el != nullptr) {
|
||||
el->fileError(info.messageId, err, up);
|
||||
}
|
||||
}
|
||||
|
@ -1005,20 +1076,20 @@ void Models::Roster::fileError(const std::list<Shared::MessageInfo>& msgs, const
|
|||
|
||||
Models::Element * Models::Roster::getElement(const Models::Roster::ElId& id)
|
||||
{
|
||||
std::map<ElId, Contact*>::iterator cItr = contacts.find(id);
|
||||
|
||||
if (cItr != contacts.end()) {
|
||||
return cItr->second;
|
||||
} else {
|
||||
std::map<ElId, Room*>::iterator rItr = rooms.find(id);
|
||||
if (rItr != rooms.end()) {
|
||||
return rItr->second;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
return const_cast<Models::Element*>(getElementConst(id));
|
||||
}
|
||||
|
||||
Models::Item::Type Models::Roster::getContactType(const Models::Roster::ElId& id) const
|
||||
{
|
||||
const Models::Element* el = getElementConst(id);
|
||||
if (el == nullptr) {
|
||||
return Item::root;
|
||||
}
|
||||
|
||||
return el->type;
|
||||
}
|
||||
|
||||
|
||||
void Models::Roster::onAccountReconnected()
|
||||
{
|
||||
Account* acc = static_cast<Account*>(sender());
|
||||
|
@ -1031,3 +1102,14 @@ void Models::Roster::onAccountReconnected()
|
|||
}
|
||||
}
|
||||
|
||||
void Models::Roster::recalculateUnreadMessages()
|
||||
{
|
||||
int count(0);
|
||||
for (const std::pair<const ElId, Contact*>& pair : contacts) {
|
||||
count += pair.second->getMessagesCount();
|
||||
}
|
||||
for (const std::pair<const ElId, Room*>& pair : rooms) {
|
||||
count += pair.second->getMessagesCount();
|
||||
}
|
||||
emit unreadMessagesCountChanged(count);
|
||||
}
|
||||
|
|
|
@ -46,6 +46,7 @@ public:
|
|||
Roster(QObject* parent = 0);
|
||||
~Roster();
|
||||
|
||||
public slots:
|
||||
void addAccount(const QMap<QString, QVariant> &data);
|
||||
void updateAccount(const QString& account, const QString& field, const QVariant& value);
|
||||
void removeAccount(const QString& account);
|
||||
|
@ -65,7 +66,12 @@ public:
|
|||
void addRoomParticipant(const QString& account, const QString& jid, const QString& name, const QMap<QString, QVariant>& data);
|
||||
void changeRoomParticipant(const QString& account, const QString& jid, const QString& name, const QMap<QString, QVariant>& data);
|
||||
void removeRoomParticipant(const QString& account, const QString& jid, const QString& name);
|
||||
QString getContactName(const QString& account, const QString& jid);
|
||||
|
||||
public:
|
||||
QString getContactName(const QString& account, const QString& jid) const;
|
||||
Item::Type getContactType(const Models::Roster::ElId& id) const;
|
||||
const Element* getElementConst(const ElId& id) const;
|
||||
Element* getElement(const ElId& id);
|
||||
|
||||
QVariant data ( const QModelIndex& index, int role ) const override;
|
||||
Qt::ItemFlags flags(const QModelIndex &index) const override;
|
||||
|
@ -77,10 +83,13 @@ public:
|
|||
|
||||
std::deque<QString> groupList(const QString& account) const;
|
||||
bool groupHasContact(const QString& account, const QString& group, const QString& contactJID) const;
|
||||
QString getContactIconPath(const QString& account, const QString& jid, const QString& resource);
|
||||
QString getContactIconPath(const QString& account, const QString& jid, const QString& resource) const;
|
||||
Account* getAccount(const QString& name);
|
||||
const Account* getAccountConst(const QString& name) const;
|
||||
QModelIndex getAccountIndex(const QString& name);
|
||||
QModelIndex getGroupIndex(const QString& account, const QString& name);
|
||||
QModelIndex getContactIndex(const QString& account, const QString& jid, const QString& resource = "");
|
||||
bool markMessageAsRead(const ElId& elementId, const QString& messageId);
|
||||
void responseArchive(const QString& account, const QString& jid, const std::list<Shared::Message>& list, bool last);
|
||||
|
||||
void fileProgress(const std::list<Shared::MessageInfo>& msgs, qreal value, bool up);
|
||||
|
@ -92,12 +101,10 @@ public:
|
|||
signals:
|
||||
void requestArchive(const QString& account, const QString& jid, const QString& before);
|
||||
void fileDownloadRequest(const QString& url);
|
||||
void unreadMessagesCountChanged(int count);
|
||||
void unnoticedMessage(const QString& account, const Shared::Message& msg);
|
||||
void localPathInvalid(const QString& path);
|
||||
|
||||
private:
|
||||
Element* getElement(const ElId& id);
|
||||
|
||||
private slots:
|
||||
void onAccountDataChanged(const QModelIndex& tl, const QModelIndex& br, const QVector<int>& roles);
|
||||
void onAccountReconnected();
|
||||
|
@ -109,7 +116,8 @@ private slots:
|
|||
void onChildIsAboutToBeMoved(Item* source, int first, int last, Item* destination, int newIndex);
|
||||
void onChildMoved();
|
||||
void onElementRequestArchive(const QString& before);
|
||||
|
||||
void recalculateUnreadMessages();
|
||||
|
||||
private:
|
||||
Item* root;
|
||||
std::map<QString, Account*> accounts;
|
||||
|
|
541
ui/squawk.cpp
541
ui/squawk.cpp
|
@ -21,17 +21,14 @@
|
|||
#include <QDebug>
|
||||
#include <QIcon>
|
||||
|
||||
Squawk::Squawk(QWidget *parent) :
|
||||
Squawk::Squawk(Models::Roster& p_rosterModel, QWidget *parent) :
|
||||
QMainWindow(parent),
|
||||
m_ui(new Ui::Squawk),
|
||||
accounts(nullptr),
|
||||
preferences(nullptr),
|
||||
about(nullptr),
|
||||
dialogueQueue(this),
|
||||
rosterModel(),
|
||||
conversations(),
|
||||
rosterModel(p_rosterModel),
|
||||
contextMenu(new QMenu()),
|
||||
dbus("org.freedesktop.Notifications", "/org/freedesktop/Notifications", "org.freedesktop.Notifications", QDBusConnection::sessionBus()),
|
||||
vCards(),
|
||||
currentConversation(nullptr),
|
||||
restoreSelection(),
|
||||
|
@ -65,12 +62,8 @@ Squawk::Squawk(QWidget *parent) :
|
|||
connect(m_ui->roster, &QTreeView::customContextMenuRequested, this, &Squawk::onRosterContextMenu);
|
||||
connect(m_ui->roster, &QTreeView::collapsed, this, &Squawk::onItemCollepsed);
|
||||
connect(m_ui->roster->selectionModel(), &QItemSelectionModel::currentRowChanged, this, &Squawk::onRosterSelectionChanged);
|
||||
connect(&rosterModel, &Models::Roster::unnoticedMessage, this, &Squawk::onUnnoticedMessage);
|
||||
|
||||
connect(rosterModel.accountsModel, &Models::Accounts::sizeChanged, this, &Squawk::onAccountsSizeChanged);
|
||||
connect(&rosterModel, &Models::Roster::requestArchive, this, &Squawk::onRequestArchive);
|
||||
connect(&rosterModel, &Models::Roster::fileDownloadRequest, this, &Squawk::fileDownloadRequest);
|
||||
connect(&rosterModel, &Models::Roster::localPathInvalid, this, &Squawk::localPathInvalid);
|
||||
connect(contextMenu, &QMenu::aboutToHide, this, &Squawk::onContextAboutToHide);
|
||||
connect(m_ui->actionAboutSquawk, &QAction::triggered, this, &Squawk::onAboutSquawkCalled);
|
||||
//m_ui->mainToolBar->addWidget(m_ui->comboBox);
|
||||
|
@ -200,36 +193,25 @@ void Squawk::closeEvent(QCloseEvent* event)
|
|||
about->close();
|
||||
}
|
||||
|
||||
for (Conversations::const_iterator itr = conversations.begin(), end = conversations.end(); itr != end; ++itr) {
|
||||
disconnect(itr->second, &Conversation::destroyed, this, &Squawk::onConversationClosed);
|
||||
itr->second->close();
|
||||
}
|
||||
conversations.clear();
|
||||
|
||||
for (std::map<QString, VCard*>::const_iterator itr = vCards.begin(), end = vCards.end(); itr != end; ++itr) {
|
||||
disconnect(itr->second, &VCard::destroyed, this, &Squawk::onVCardClosed);
|
||||
itr->second->close();
|
||||
}
|
||||
vCards.clear();
|
||||
|
||||
writeSettings();
|
||||
emit closing();;
|
||||
|
||||
QMainWindow::closeEvent(event);
|
||||
}
|
||||
|
||||
void Squawk::onAccountsClosed() {
|
||||
accounts = nullptr;}
|
||||
|
||||
void Squawk::onAccountsClosed()
|
||||
{
|
||||
accounts = nullptr;
|
||||
}
|
||||
void Squawk::onPreferencesClosed() {
|
||||
preferences = nullptr;}
|
||||
|
||||
void Squawk::onPreferencesClosed()
|
||||
{
|
||||
preferences = nullptr;
|
||||
}
|
||||
|
||||
void Squawk::newAccount(const QMap<QString, QVariant>& account)
|
||||
{
|
||||
rosterModel.addAccount(account);
|
||||
}
|
||||
void Squawk::onAboutSquawkClosed() {
|
||||
about = nullptr;}
|
||||
|
||||
void Squawk::onComboboxActivated(int index)
|
||||
{
|
||||
|
@ -237,85 +219,11 @@ void Squawk::onComboboxActivated(int index)
|
|||
emit changeState(av);
|
||||
}
|
||||
|
||||
void Squawk::changeAccount(const QString& account, const QMap<QString, QVariant>& data)
|
||||
{
|
||||
for (QMap<QString, QVariant>::const_iterator itr = data.begin(), end = data.end(); itr != end; ++itr) {
|
||||
QString attr = itr.key();
|
||||
rosterModel.updateAccount(account, attr, *itr);
|
||||
}
|
||||
}
|
||||
void Squawk::expand(const QModelIndex& index) {
|
||||
m_ui->roster->expand(index);}
|
||||
|
||||
void Squawk::addContact(const QString& account, const QString& jid, const QString& group, const QMap<QString, QVariant>& data)
|
||||
{
|
||||
rosterModel.addContact(account, jid, group, data);
|
||||
|
||||
QSettings settings;
|
||||
settings.beginGroup("ui");
|
||||
settings.beginGroup("roster");
|
||||
settings.beginGroup(account);
|
||||
if (settings.value("expanded", false).toBool()) {
|
||||
QModelIndex ind = rosterModel.getAccountIndex(account);
|
||||
m_ui->roster->expand(ind);
|
||||
}
|
||||
settings.endGroup();
|
||||
settings.endGroup();
|
||||
settings.endGroup();
|
||||
}
|
||||
|
||||
void Squawk::addGroup(const QString& account, const QString& name)
|
||||
{
|
||||
rosterModel.addGroup(account, name);
|
||||
|
||||
QSettings settings;
|
||||
settings.beginGroup("ui");
|
||||
settings.beginGroup("roster");
|
||||
settings.beginGroup(account);
|
||||
if (settings.value("expanded", false).toBool()) {
|
||||
QModelIndex ind = rosterModel.getAccountIndex(account);
|
||||
m_ui->roster->expand(ind);
|
||||
if (settings.value(name + "/expanded", false).toBool()) {
|
||||
m_ui->roster->expand(rosterModel.getGroupIndex(account, name));
|
||||
}
|
||||
}
|
||||
settings.endGroup();
|
||||
settings.endGroup();
|
||||
settings.endGroup();
|
||||
}
|
||||
|
||||
void Squawk::removeGroup(const QString& account, const QString& name)
|
||||
{
|
||||
rosterModel.removeGroup(account, name);
|
||||
}
|
||||
|
||||
void Squawk::changeContact(const QString& account, const QString& jid, const QMap<QString, QVariant>& data)
|
||||
{
|
||||
rosterModel.changeContact(account, jid, data);
|
||||
}
|
||||
|
||||
void Squawk::removeContact(const QString& account, const QString& jid)
|
||||
{
|
||||
rosterModel.removeContact(account, jid);
|
||||
}
|
||||
|
||||
void Squawk::removeContact(const QString& account, const QString& jid, const QString& group)
|
||||
{
|
||||
rosterModel.removeContact(account, jid, group);
|
||||
}
|
||||
|
||||
void Squawk::addPresence(const QString& account, const QString& jid, const QString& name, const QMap<QString, QVariant>& data)
|
||||
{
|
||||
rosterModel.addPresence(account, jid, name, data);
|
||||
}
|
||||
|
||||
void Squawk::removePresence(const QString& account, const QString& jid, const QString& name)
|
||||
{
|
||||
rosterModel.removePresence(account, jid, name);
|
||||
}
|
||||
|
||||
void Squawk::stateChanged(Shared::Availability state)
|
||||
{
|
||||
m_ui->comboBox->setCurrentIndex(static_cast<int>(state));
|
||||
}
|
||||
void Squawk::stateChanged(Shared::Availability state) {
|
||||
m_ui->comboBox->setCurrentIndex(static_cast<int>(state));}
|
||||
|
||||
void Squawk::onRosterItemDoubleClicked(const QModelIndex& item)
|
||||
{
|
||||
|
@ -326,212 +234,33 @@ void Squawk::onRosterItemDoubleClicked(const QModelIndex& item)
|
|||
}
|
||||
Models::Contact* contact = nullptr;
|
||||
Models::Room* room = nullptr;
|
||||
QString res;
|
||||
Models::Roster::ElId* id = nullptr;
|
||||
switch (node->type) {
|
||||
case Models::Item::contact:
|
||||
contact = static_cast<Models::Contact*>(node);
|
||||
id = new Models::Roster::ElId(contact->getAccountName(), contact->getJid());
|
||||
emit openConversation(Models::Roster::ElId(contact->getAccountName(), contact->getJid()));
|
||||
break;
|
||||
case Models::Item::presence:
|
||||
contact = static_cast<Models::Contact*>(node->parentItem());
|
||||
id = new Models::Roster::ElId(contact->getAccountName(), contact->getJid());
|
||||
res = node->getName();
|
||||
emit openConversation(Models::Roster::ElId(contact->getAccountName(), contact->getJid()), node->getName());
|
||||
break;
|
||||
case Models::Item::room:
|
||||
room = static_cast<Models::Room*>(node);
|
||||
id = new Models::Roster::ElId(room->getAccountName(), room->getJid());
|
||||
emit openConversation(Models::Roster::ElId(room->getAccountName(), room->getJid()));
|
||||
break;
|
||||
default:
|
||||
m_ui->roster->expand(item);
|
||||
break;
|
||||
}
|
||||
|
||||
if (id != nullptr) {
|
||||
Conversations::const_iterator itr = conversations.find(*id);
|
||||
Models::Account* acc = rosterModel.getAccount(id->account);
|
||||
Conversation* conv = nullptr;
|
||||
bool created = false;
|
||||
if (itr != conversations.end()) {
|
||||
conv = itr->second;
|
||||
} else if (contact != nullptr) {
|
||||
created = true;
|
||||
conv = new Chat(acc, contact);
|
||||
} else if (room != nullptr) {
|
||||
created = true;
|
||||
conv = new Room(acc, room);
|
||||
|
||||
if (!room->getJoined()) {
|
||||
emit setRoomJoined(id->account, id->name, true);
|
||||
}
|
||||
}
|
||||
|
||||
if (conv != nullptr) {
|
||||
if (created) {
|
||||
conv->setAttribute(Qt::WA_DeleteOnClose);
|
||||
subscribeConversation(conv);
|
||||
conversations.insert(std::make_pair(*id, conv));
|
||||
}
|
||||
|
||||
conv->show();
|
||||
conv->raise();
|
||||
conv->activateWindow();
|
||||
|
||||
if (res.size() > 0) {
|
||||
conv->setPalResource(res);
|
||||
}
|
||||
}
|
||||
|
||||
delete id;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Squawk::onConversationClosed(QObject* parent)
|
||||
void Squawk::closeCurrentConversation()
|
||||
{
|
||||
Conversation* conv = static_cast<Conversation*>(sender());
|
||||
Models::Roster::ElId id(conv->getAccount(), conv->getJid());
|
||||
Conversations::const_iterator itr = conversations.find(id);
|
||||
if (itr != conversations.end()) {
|
||||
conversations.erase(itr);
|
||||
}
|
||||
if (conv->isMuc) {
|
||||
Room* room = static_cast<Room*>(conv);
|
||||
if (!room->autoJoined()) {
|
||||
emit setRoomJoined(id.account, id.name, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Squawk::fileProgress(const std::list<Shared::MessageInfo> msgs, qreal value, bool up)
|
||||
{
|
||||
rosterModel.fileProgress(msgs, value, up);
|
||||
}
|
||||
|
||||
void Squawk::fileDownloadComplete(const std::list<Shared::MessageInfo> msgs, const QString& path)
|
||||
{
|
||||
rosterModel.fileComplete(msgs, false);
|
||||
}
|
||||
|
||||
void Squawk::fileError(const std::list<Shared::MessageInfo> msgs, const QString& error, bool up)
|
||||
{
|
||||
rosterModel.fileError(msgs, error, up);
|
||||
}
|
||||
|
||||
void Squawk::fileUploadComplete(const std::list<Shared::MessageInfo> msgs, const QString& url, const QString& path)
|
||||
{
|
||||
rosterModel.fileComplete(msgs, true);
|
||||
}
|
||||
|
||||
void Squawk::accountMessage(const QString& account, const Shared::Message& data)
|
||||
{
|
||||
rosterModel.addMessage(account, data);
|
||||
}
|
||||
|
||||
void Squawk::onUnnoticedMessage(const QString& account, const Shared::Message& msg)
|
||||
{
|
||||
notify(account, msg); //Telegram does this way - notifies even if the app is visible
|
||||
QApplication::alert(this);
|
||||
}
|
||||
|
||||
void Squawk::changeMessage(const QString& account, const QString& jid, const QString& id, const QMap<QString, QVariant>& data)
|
||||
{
|
||||
rosterModel.changeMessage(account, jid, id, data);
|
||||
}
|
||||
|
||||
void Squawk::notify(const QString& account, const Shared::Message& msg)
|
||||
{
|
||||
QString name = QString(rosterModel.getContactName(account, msg.getPenPalJid()));
|
||||
QString path = QString(rosterModel.getContactIconPath(account, msg.getPenPalJid(), msg.getPenPalResource()));
|
||||
QVariantList args;
|
||||
args << QString(QCoreApplication::applicationName());
|
||||
args << QVariant(QVariant::UInt); //TODO some normal id
|
||||
if (path.size() > 0) {
|
||||
args << path;
|
||||
} else {
|
||||
args << QString("mail-message"); //TODO should here better be unknown user icon?
|
||||
}
|
||||
if (msg.getType() == Shared::Message::groupChat) {
|
||||
args << msg.getFromResource() + " from " + name;
|
||||
} else {
|
||||
args << name;
|
||||
}
|
||||
|
||||
QString body(msg.getBody());
|
||||
QString oob(msg.getOutOfBandUrl());
|
||||
if (body == oob) {
|
||||
body = tr("Attached file");
|
||||
}
|
||||
|
||||
args << body;
|
||||
args << QStringList();
|
||||
args << QVariantMap();
|
||||
args << 3000;
|
||||
dbus.callWithArgumentList(QDBus::AutoDetect, "Notify", args);
|
||||
}
|
||||
|
||||
void Squawk::onConversationMessage(const Shared::Message& msg)
|
||||
{
|
||||
Conversation* conv = static_cast<Conversation*>(sender());
|
||||
QString acc = conv->getAccount();
|
||||
|
||||
rosterModel.addMessage(acc, msg);
|
||||
emit sendMessage(acc, msg);
|
||||
}
|
||||
|
||||
void Squawk::onConversationReplaceMessage(const QString& originalId, const Shared::Message& msg)
|
||||
{
|
||||
Conversation* conv = static_cast<Conversation*>(sender());
|
||||
QString acc = conv->getAccount();
|
||||
|
||||
rosterModel.changeMessage(acc, msg.getPenPalJid(), originalId, {
|
||||
{"state", static_cast<uint>(Shared::Message::State::pending)}
|
||||
});
|
||||
emit replaceMessage(acc, originalId, msg);
|
||||
}
|
||||
|
||||
void Squawk::onConversationResend(const QString& id)
|
||||
{
|
||||
Conversation* conv = static_cast<Conversation*>(sender());
|
||||
QString acc = conv->getAccount();
|
||||
QString jid = conv->getJid();
|
||||
|
||||
emit resendMessage(acc, jid, id);
|
||||
}
|
||||
|
||||
void Squawk::onRequestArchive(const QString& account, const QString& jid, const QString& before)
|
||||
{
|
||||
emit requestArchive(account, jid, 20, before); //TODO amount as a settings value
|
||||
}
|
||||
|
||||
void Squawk::responseArchive(const QString& account, const QString& jid, const std::list<Shared::Message>& list, bool last)
|
||||
{
|
||||
rosterModel.responseArchive(account, jid, list, last);
|
||||
}
|
||||
|
||||
void Squawk::removeAccount(const QString& account)
|
||||
{
|
||||
Conversations::const_iterator itr = conversations.begin();
|
||||
while (itr != conversations.end()) {
|
||||
if (itr->first.account == account) {
|
||||
Conversations::const_iterator lItr = itr;
|
||||
++itr;
|
||||
Conversation* conv = lItr->second;
|
||||
disconnect(conv, &Conversation::destroyed, this, &Squawk::onConversationClosed);
|
||||
conv->close();
|
||||
conversations.erase(lItr);
|
||||
} else {
|
||||
++itr;
|
||||
}
|
||||
}
|
||||
|
||||
if (currentConversation != nullptr && currentConversation->getAccount() == account) {
|
||||
if (currentConversation != nullptr) {
|
||||
currentConversation->deleteLater();
|
||||
currentConversation = nullptr;
|
||||
m_ui->filler->show();
|
||||
}
|
||||
|
||||
rosterModel.removeAccount(account);
|
||||
}
|
||||
|
||||
void Squawk::onRosterContextMenu(const QPoint& point)
|
||||
|
@ -569,13 +298,13 @@ void Squawk::onRosterContextMenu(const QPoint& point)
|
|||
break;
|
||||
case Models::Item::contact: {
|
||||
Models::Contact* cnt = static_cast<Models::Contact*>(item);
|
||||
Models::Roster::ElId id(cnt->getAccountName(), cnt->getJid());
|
||||
QString cntName = cnt->getName();
|
||||
hasMenu = true;
|
||||
|
||||
QAction* dialog = contextMenu->addAction(Shared::icon("mail-message"), tr("Open dialog"));
|
||||
dialog->setEnabled(active);
|
||||
connect(dialog, &QAction::triggered, [this, index]() {
|
||||
onRosterItemDoubleClicked(index);
|
||||
});
|
||||
connect(dialog, &QAction::triggered, std::bind(&Squawk::onRosterItemDoubleClicked, this, index));
|
||||
|
||||
Shared::SubscriptionState state = cnt->getState();
|
||||
switch (state) {
|
||||
|
@ -583,9 +312,7 @@ void Squawk::onRosterContextMenu(const QPoint& point)
|
|||
case Shared::SubscriptionState::to: {
|
||||
QAction* unsub = contextMenu->addAction(Shared::icon("news-unsubscribe"), tr("Unsubscribe"));
|
||||
unsub->setEnabled(active);
|
||||
connect(unsub, &QAction::triggered, [this, cnt]() {
|
||||
emit unsubscribeContact(cnt->getAccountName(), cnt->getJid(), "");
|
||||
});
|
||||
connect(unsub, &QAction::triggered, std::bind(&Squawk::changeSubscription, this, id, false));
|
||||
}
|
||||
break;
|
||||
case Shared::SubscriptionState::from:
|
||||
|
@ -593,75 +320,68 @@ void Squawk::onRosterContextMenu(const QPoint& point)
|
|||
case Shared::SubscriptionState::none: {
|
||||
QAction* sub = contextMenu->addAction(Shared::icon("news-subscribe"), tr("Subscribe"));
|
||||
sub->setEnabled(active);
|
||||
connect(sub, &QAction::triggered, [this, cnt]() {
|
||||
emit subscribeContact(cnt->getAccountName(), cnt->getJid(), "");
|
||||
});
|
||||
connect(sub, &QAction::triggered, std::bind(&Squawk::changeSubscription, this, id, true));
|
||||
}
|
||||
}
|
||||
QString accName = cnt->getAccountName();
|
||||
QString cntJID = cnt->getJid();
|
||||
QString cntName = cnt->getName();
|
||||
|
||||
QAction* rename = contextMenu->addAction(Shared::icon("edit-rename"), tr("Rename"));
|
||||
rename->setEnabled(active);
|
||||
connect(rename, &QAction::triggered, [this, cntName, accName, cntJID]() {
|
||||
connect(rename, &QAction::triggered, [this, cntName, id]() {
|
||||
QInputDialog* dialog = new QInputDialog(this);
|
||||
connect(dialog, &QDialog::accepted, [this, dialog, cntName, accName, cntJID]() {
|
||||
connect(dialog, &QDialog::accepted, [this, dialog, cntName, id]() {
|
||||
QString newName = dialog->textValue();
|
||||
if (newName != cntName) {
|
||||
emit renameContactRequest(accName, cntJID, newName);
|
||||
emit renameContactRequest(id.account, id.name, newName);
|
||||
}
|
||||
dialog->deleteLater();
|
||||
});
|
||||
connect(dialog, &QDialog::rejected, dialog, &QObject::deleteLater);
|
||||
dialog->setInputMode(QInputDialog::TextInput);
|
||||
dialog->setLabelText(tr("Input new name for %1\nor leave it empty for the contact \nto be displayed as %1").arg(cntJID));
|
||||
dialog->setWindowTitle(tr("Renaming %1").arg(cntJID));
|
||||
dialog->setLabelText(tr("Input new name for %1\nor leave it empty for the contact \nto be displayed as %1").arg(id.name));
|
||||
dialog->setWindowTitle(tr("Renaming %1").arg(id.name));
|
||||
dialog->setTextValue(cntName);
|
||||
dialog->exec();
|
||||
});
|
||||
|
||||
|
||||
QMenu* groupsMenu = contextMenu->addMenu(Shared::icon("group"), tr("Groups"));
|
||||
std::deque<QString> groupList = rosterModel.groupList(accName);
|
||||
std::deque<QString> groupList = rosterModel.groupList(id.account);
|
||||
for (QString groupName : groupList) {
|
||||
QAction* gr = groupsMenu->addAction(groupName);
|
||||
gr->setCheckable(true);
|
||||
gr->setChecked(rosterModel.groupHasContact(accName, groupName, cntJID));
|
||||
gr->setChecked(rosterModel.groupHasContact(id.account, groupName, id.name));
|
||||
gr->setEnabled(active);
|
||||
connect(gr, &QAction::toggled, [this, accName, groupName, cntJID](bool checked) {
|
||||
connect(gr, &QAction::toggled, [this, groupName, id](bool checked) {
|
||||
if (checked) {
|
||||
emit addContactToGroupRequest(accName, cntJID, groupName);
|
||||
emit addContactToGroupRequest(id.account, id.name, groupName);
|
||||
} else {
|
||||
emit removeContactFromGroupRequest(accName, cntJID, groupName);
|
||||
emit removeContactFromGroupRequest(id.account, id.name, groupName);
|
||||
}
|
||||
});
|
||||
}
|
||||
QAction* newGroup = groupsMenu->addAction(Shared::icon("group-new"), tr("New group"));
|
||||
newGroup->setEnabled(active);
|
||||
connect(newGroup, &QAction::triggered, [this, accName, cntJID]() {
|
||||
connect(newGroup, &QAction::triggered, [this, id]() {
|
||||
QInputDialog* dialog = new QInputDialog(this);
|
||||
connect(dialog, &QDialog::accepted, [this, dialog, accName, cntJID]() {
|
||||
emit addContactToGroupRequest(accName, cntJID, dialog->textValue());
|
||||
connect(dialog, &QDialog::accepted, [this, dialog, id]() {
|
||||
emit addContactToGroupRequest(id.account, id.name, dialog->textValue());
|
||||
dialog->deleteLater();
|
||||
});
|
||||
connect(dialog, &QDialog::rejected, dialog, &QObject::deleteLater);
|
||||
dialog->setInputMode(QInputDialog::TextInput);
|
||||
dialog->setLabelText(tr("New group name"));
|
||||
dialog->setWindowTitle(tr("Add %1 to a new group").arg(cntJID));
|
||||
dialog->setWindowTitle(tr("Add %1 to a new group").arg(id.name));
|
||||
dialog->exec();
|
||||
});
|
||||
|
||||
|
||||
QAction* card = contextMenu->addAction(Shared::icon("user-properties"), tr("VCard"));
|
||||
card->setEnabled(active);
|
||||
connect(card, &QAction::triggered, std::bind(&Squawk::onActivateVCard, this, accName, cnt->getJid(), false));
|
||||
connect(card, &QAction::triggered, std::bind(&Squawk::onActivateVCard, this, id.account, id.name, false));
|
||||
|
||||
QAction* remove = contextMenu->addAction(Shared::icon("edit-delete"), tr("Remove"));
|
||||
remove->setEnabled(active);
|
||||
connect(remove, &QAction::triggered, [this, cnt]() {
|
||||
emit removeContactRequest(cnt->getAccountName(), cnt->getJid());
|
||||
});
|
||||
connect(remove, &QAction::triggered, std::bind(&Squawk::removeContactRequest, this, id.account, id.name));
|
||||
|
||||
}
|
||||
break;
|
||||
|
@ -680,32 +400,16 @@ void Squawk::onRosterContextMenu(const QPoint& point)
|
|||
if (room->getAutoJoin()) {
|
||||
QAction* unsub = contextMenu->addAction(Shared::icon("news-unsubscribe"), tr("Unsubscribe"));
|
||||
unsub->setEnabled(active);
|
||||
connect(unsub, &QAction::triggered, [this, id]() {
|
||||
emit setRoomAutoJoin(id.account, id.name, false);
|
||||
if (conversations.find(id) == conversations.end()
|
||||
&& (currentConversation == nullptr || currentConversation->getId() != id)
|
||||
) { //to leave the room if it's not opened in a conversation window
|
||||
emit setRoomJoined(id.account, id.name, false);
|
||||
}
|
||||
});
|
||||
connect(unsub, &QAction::triggered, std::bind(&Squawk::changeSubscription, this, id, false));
|
||||
} else {
|
||||
QAction* unsub = contextMenu->addAction(Shared::icon("news-subscribe"), tr("Subscribe"));
|
||||
unsub->setEnabled(active);
|
||||
connect(unsub, &QAction::triggered, [this, id]() {
|
||||
emit setRoomAutoJoin(id.account, id.name, true);
|
||||
if (conversations.find(id) == conversations.end()
|
||||
&& (currentConversation == nullptr || currentConversation->getId() != id)
|
||||
) { //to join the room if it's not already joined
|
||||
emit setRoomJoined(id.account, id.name, true);
|
||||
}
|
||||
});
|
||||
QAction* sub = contextMenu->addAction(Shared::icon("news-subscribe"), tr("Subscribe"));
|
||||
sub->setEnabled(active);
|
||||
connect(sub, &QAction::triggered, std::bind(&Squawk::changeSubscription, this, id, true));
|
||||
}
|
||||
|
||||
QAction* remove = contextMenu->addAction(Shared::icon("edit-delete"), tr("Remove"));
|
||||
remove->setEnabled(active);
|
||||
connect(remove, &QAction::triggered, [this, id]() {
|
||||
emit removeRoomRequest(id.account, id.name);
|
||||
});
|
||||
connect(remove, &QAction::triggered, std::bind(&Squawk::removeRoomRequest, this, id.account, id.name));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
@ -717,36 +421,6 @@ void Squawk::onRosterContextMenu(const QPoint& point)
|
|||
}
|
||||
}
|
||||
|
||||
void Squawk::addRoom(const QString& account, const QString jid, const QMap<QString, QVariant>& data)
|
||||
{
|
||||
rosterModel.addRoom(account, jid, data);
|
||||
}
|
||||
|
||||
void Squawk::changeRoom(const QString& account, const QString jid, const QMap<QString, QVariant>& data)
|
||||
{
|
||||
rosterModel.changeRoom(account, jid, data);
|
||||
}
|
||||
|
||||
void Squawk::removeRoom(const QString& account, const QString jid)
|
||||
{
|
||||
rosterModel.removeRoom(account, jid);
|
||||
}
|
||||
|
||||
void Squawk::addRoomParticipant(const QString& account, const QString& jid, const QString& name, const QMap<QString, QVariant>& data)
|
||||
{
|
||||
rosterModel.addRoomParticipant(account, jid, name, data);
|
||||
}
|
||||
|
||||
void Squawk::changeRoomParticipant(const QString& account, const QString& jid, const QString& name, const QMap<QString, QVariant>& data)
|
||||
{
|
||||
rosterModel.changeRoomParticipant(account, jid, name, data);
|
||||
}
|
||||
|
||||
void Squawk::removeRoomParticipant(const QString& account, const QString& jid, const QString& name)
|
||||
{
|
||||
rosterModel.removeRoomParticipant(account, jid, name);
|
||||
}
|
||||
|
||||
void Squawk::responseVCard(const QString& jid, const Shared::VCard& card)
|
||||
{
|
||||
std::map<QString, VCard*>::const_iterator itr = vCards.find(jid);
|
||||
|
@ -804,61 +478,40 @@ void Squawk::onVCardSave(const Shared::VCard& card, const QString& account)
|
|||
widget->deleteLater();
|
||||
}
|
||||
|
||||
void Squawk::readSettings()
|
||||
{
|
||||
QSettings settings;
|
||||
settings.beginGroup("ui");
|
||||
int avail;
|
||||
if (settings.contains("availability")) {
|
||||
avail = settings.value("availability").toInt();
|
||||
} else {
|
||||
avail = static_cast<int>(Shared::Availability::online);
|
||||
}
|
||||
settings.endGroup();
|
||||
m_ui->comboBox->setCurrentIndex(avail);
|
||||
|
||||
emit changeState(Shared::Global::fromInt<Shared::Availability>(avail));
|
||||
}
|
||||
|
||||
void Squawk::writeSettings()
|
||||
{
|
||||
QSettings settings;
|
||||
settings.beginGroup("ui");
|
||||
settings.beginGroup("window");
|
||||
settings.setValue("geometry", saveGeometry());
|
||||
settings.setValue("state", saveState());
|
||||
settings.endGroup();
|
||||
|
||||
settings.setValue("splitter", m_ui->splitter->saveState());
|
||||
|
||||
settings.setValue("availability", m_ui->comboBox->currentIndex());
|
||||
|
||||
settings.remove("roster");
|
||||
settings.beginGroup("roster");
|
||||
int size = rosterModel.accountsModel->rowCount(QModelIndex());
|
||||
for (int i = 0; i < size; ++i) {
|
||||
QModelIndex acc = rosterModel.index(i, 0, QModelIndex());
|
||||
Models::Account* account = rosterModel.accountsModel->getAccount(i);
|
||||
QString accName = account->getName();
|
||||
settings.beginGroup(accName);
|
||||
|
||||
settings.setValue("expanded", m_ui->roster->isExpanded(acc));
|
||||
std::deque<QString> groups = rosterModel.groupList(accName);
|
||||
for (const QString& groupName : groups) {
|
||||
settings.beginGroup(groupName);
|
||||
QModelIndex gIndex = rosterModel.getGroupIndex(accName, groupName);
|
||||
settings.setValue("expanded", m_ui->roster->isExpanded(gIndex));
|
||||
settings.endGroup();
|
||||
}
|
||||
|
||||
settings.beginGroup("window");
|
||||
settings.setValue("geometry", saveGeometry());
|
||||
settings.setValue("state", saveState());
|
||||
settings.endGroup();
|
||||
|
||||
settings.setValue("splitter", m_ui->splitter->saveState());
|
||||
settings.remove("roster");
|
||||
settings.beginGroup("roster");
|
||||
int size = rosterModel.accountsModel->rowCount(QModelIndex());
|
||||
for (int i = 0; i < size; ++i) {
|
||||
QModelIndex acc = rosterModel.index(i, 0, QModelIndex());
|
||||
Models::Account* account = rosterModel.accountsModel->getAccount(i);
|
||||
QString accName = account->getName();
|
||||
settings.beginGroup(accName);
|
||||
|
||||
settings.setValue("expanded", m_ui->roster->isExpanded(acc));
|
||||
std::deque<QString> groups = rosterModel.groupList(accName);
|
||||
for (const QString& groupName : groups) {
|
||||
settings.beginGroup(groupName);
|
||||
QModelIndex gIndex = rosterModel.getGroupIndex(accName, groupName);
|
||||
settings.setValue("expanded", m_ui->roster->isExpanded(gIndex));
|
||||
settings.endGroup();
|
||||
}
|
||||
|
||||
settings.endGroup();
|
||||
}
|
||||
settings.endGroup();
|
||||
}
|
||||
settings.endGroup();
|
||||
settings.endGroup();
|
||||
|
||||
settings.sync();
|
||||
|
||||
qDebug() << "Saved settings";
|
||||
}
|
||||
|
||||
void Squawk::onItemCollepsed(const QModelIndex& index)
|
||||
|
@ -880,24 +533,6 @@ void Squawk::onItemCollepsed(const QModelIndex& index)
|
|||
}
|
||||
}
|
||||
|
||||
void Squawk::requestPassword(const QString& account, bool authenticationError) {
|
||||
if (authenticationError) {
|
||||
dialogueQueue.addAction(account, DialogQueue::askCredentials);
|
||||
} else {
|
||||
dialogueQueue.addAction(account, DialogQueue::askPassword);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void Squawk::subscribeConversation(Conversation* conv)
|
||||
{
|
||||
connect(conv, &Conversation::destroyed, this, &Squawk::onConversationClosed);
|
||||
connect(conv, &Conversation::sendMessage, this, &Squawk::onConversationMessage);
|
||||
connect(conv, &Conversation::replaceMessage, this, &Squawk::onConversationReplaceMessage);
|
||||
connect(conv, &Conversation::resendMessage, this, &Squawk::onConversationResend);
|
||||
connect(conv, &Conversation::notifyableMessage, this, &Squawk::notify);
|
||||
}
|
||||
|
||||
void Squawk::onRosterSelectionChanged(const QModelIndex& current, const QModelIndex& previous)
|
||||
{
|
||||
if (restoreSelection.isValid() && restoreSelection == current) {
|
||||
|
@ -969,16 +604,12 @@ void Squawk::onRosterSelectionChanged(const QModelIndex& current, const QModelIn
|
|||
currentConversation = new Chat(acc, contact);
|
||||
} else if (room != nullptr) {
|
||||
currentConversation = new Room(acc, room);
|
||||
|
||||
if (!room->getJoined()) {
|
||||
emit setRoomJoined(id->account, id->name, true);
|
||||
}
|
||||
}
|
||||
if (!testAttribute(Qt::WA_TranslucentBackground)) {
|
||||
currentConversation->setFeedFrames(true, false, true, true);
|
||||
}
|
||||
|
||||
subscribeConversation(currentConversation);
|
||||
emit openedConversation();
|
||||
|
||||
if (res.size() > 0) {
|
||||
currentConversation->setPalResource(res);
|
||||
|
@ -988,18 +619,10 @@ void Squawk::onRosterSelectionChanged(const QModelIndex& current, const QModelIn
|
|||
|
||||
delete id;
|
||||
} else {
|
||||
if (currentConversation != nullptr) {
|
||||
currentConversation->deleteLater();
|
||||
currentConversation = nullptr;
|
||||
m_ui->filler->show();
|
||||
}
|
||||
closeCurrentConversation();
|
||||
}
|
||||
} else {
|
||||
if (currentConversation != nullptr) {
|
||||
currentConversation->deleteLater();
|
||||
currentConversation = nullptr;
|
||||
m_ui->filler->show();
|
||||
}
|
||||
closeCurrentConversation();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1024,7 +647,17 @@ void Squawk::onAboutSquawkCalled()
|
|||
about->show();
|
||||
}
|
||||
|
||||
void Squawk::onAboutSquawkClosed()
|
||||
Models::Roster::ElId Squawk::currentConversationId() const
|
||||
{
|
||||
about = nullptr;
|
||||
if (currentConversation == nullptr) {
|
||||
return Models::Roster::ElId();
|
||||
} else {
|
||||
return Models::Roster::ElId(currentConversation->getAccount(), currentConversation->getJid());
|
||||
}
|
||||
}
|
||||
|
||||
void Squawk::select(QModelIndex index)
|
||||
{
|
||||
m_ui->roster->scrollTo(index, QAbstractItemView::EnsureVisible);
|
||||
m_ui->roster->selectionModel()->setCurrentIndex(index, QItemSelectionModel::ClearAndSelect);
|
||||
}
|
||||
|
|
80
ui/squawk.h
80
ui/squawk.h
|
@ -22,7 +22,6 @@
|
|||
#include <QMainWindow>
|
||||
#include <QScopedPointer>
|
||||
#include <QCloseEvent>
|
||||
#include <QtDBus/QDBusInterface>
|
||||
#include <QSettings>
|
||||
#include <QInputDialog>
|
||||
|
||||
|
@ -40,94 +39,67 @@
|
|||
#include "widgets/vcard/vcard.h"
|
||||
#include "widgets/settings/settings.h"
|
||||
#include "widgets/about.h"
|
||||
#include "dialogqueue.h"
|
||||
|
||||
#include "shared/shared.h"
|
||||
#include "shared/global.h"
|
||||
|
||||
namespace Ui {
|
||||
class Squawk;
|
||||
}
|
||||
|
||||
class Application;
|
||||
|
||||
class Squawk : public QMainWindow
|
||||
{
|
||||
Q_OBJECT
|
||||
friend class DialogQueue;
|
||||
friend class Application;
|
||||
public:
|
||||
explicit Squawk(QWidget *parent = nullptr);
|
||||
explicit Squawk(Models::Roster& rosterModel, QWidget *parent = nullptr);
|
||||
~Squawk() override;
|
||||
|
||||
signals:
|
||||
void closing();
|
||||
void newAccountRequest(const QMap<QString, QVariant>&);
|
||||
void modifyAccountRequest(const QString&, const QMap<QString, QVariant>&);
|
||||
void removeAccountRequest(const QString&);
|
||||
void connectAccount(const QString&);
|
||||
void disconnectAccount(const QString&);
|
||||
void changeState(Shared::Availability state);
|
||||
void sendMessage(const QString& account, const Shared::Message& data);
|
||||
void replaceMessage(const QString& account, const QString& originalId, const Shared::Message& data);
|
||||
void resendMessage(const QString& account, const QString& jid, const QString& id);
|
||||
void requestArchive(const QString& account, const QString& jid, int count, const QString& before);
|
||||
void subscribeContact(const QString& account, const QString& jid, const QString& reason);
|
||||
void unsubscribeContact(const QString& account, const QString& jid, const QString& reason);
|
||||
void removeContactRequest(const QString& account, const QString& jid);
|
||||
void addContactRequest(const QString& account, const QString& jid, const QString& name, const QSet<QString>& groups);
|
||||
void addContactToGroupRequest(const QString& account, const QString& jid, const QString& groupName);
|
||||
void removeContactFromGroupRequest(const QString& account, const QString& jid, const QString& groupName);
|
||||
void renameContactRequest(const QString& account, const QString& jid, const QString& newName);
|
||||
void setRoomJoined(const QString& account, const QString& jid, bool joined);
|
||||
void setRoomAutoJoin(const QString& account, const QString& jid, bool joined);
|
||||
void addRoomRequest(const QString& account, const QString& jid, const QString& nick, const QString& password, bool autoJoin);
|
||||
void removeRoomRequest(const QString& account, const QString& jid);
|
||||
void fileDownloadRequest(const QString& url);
|
||||
void requestVCard(const QString& account, const QString& jid);
|
||||
void uploadVCard(const QString& account, const Shared::VCard& card);
|
||||
void responsePassword(const QString& account, const QString& password);
|
||||
void localPathInvalid(const QString& path);
|
||||
void changeDownloadsPath(const QString& path);
|
||||
|
||||
void notify(const QString& account, const Shared::Message& msg);
|
||||
void changeSubscription(const Models::Roster::ElId& id, bool subscribe);
|
||||
void openedConversation();
|
||||
void openConversation(const Models::Roster::ElId& id, const QString& resource = "");
|
||||
|
||||
void modifyAccountRequest(const QString&, const QMap<QString, QVariant>&);
|
||||
|
||||
public:
|
||||
Models::Roster::ElId currentConversationId() const;
|
||||
void closeCurrentConversation();
|
||||
|
||||
public slots:
|
||||
void writeSettings();
|
||||
void readSettings();
|
||||
void newAccount(const QMap<QString, QVariant>& account);
|
||||
void changeAccount(const QString& account, const QMap<QString, QVariant>& data);
|
||||
void removeAccount(const QString& account);
|
||||
void addGroup(const QString& account, const QString& name);
|
||||
void removeGroup(const QString& account, const QString& name);
|
||||
void addContact(const QString& account, const QString& jid, const QString& group, const QMap<QString, QVariant>& data);
|
||||
void removeContact(const QString& account, const QString& jid, const QString& group);
|
||||
void removeContact(const QString& account, const QString& jid);
|
||||
void changeContact(const QString& account, const QString& jid, const QMap<QString, QVariant>& data);
|
||||
void addPresence(const QString& account, const QString& jid, const QString& name, const QMap<QString, QVariant>& data);
|
||||
void removePresence(const QString& account, const QString& jid, const QString& name);
|
||||
void stateChanged(Shared::Availability state);
|
||||
void accountMessage(const QString& account, const Shared::Message& data);
|
||||
void responseArchive(const QString& account, const QString& jid, const std::list<Shared::Message>& list, bool last);
|
||||
void addRoom(const QString& account, const QString jid, const QMap<QString, QVariant>& data);
|
||||
void changeRoom(const QString& account, const QString jid, const QMap<QString, QVariant>& data);
|
||||
void removeRoom(const QString& account, const QString jid);
|
||||
void addRoomParticipant(const QString& account, const QString& jid, const QString& name, const QMap<QString, QVariant>& data);
|
||||
void changeRoomParticipant(const QString& account, const QString& jid, const QString& name, const QMap<QString, QVariant>& data);
|
||||
void removeRoomParticipant(const QString& account, const QString& jid, const QString& name);
|
||||
void fileError(const std::list<Shared::MessageInfo> msgs, const QString& error, bool up);
|
||||
void fileProgress(const std::list<Shared::MessageInfo> msgs, qreal value, bool up);
|
||||
void fileDownloadComplete(const std::list<Shared::MessageInfo> msgs, const QString& path);
|
||||
void fileUploadComplete(const std::list<Shared::MessageInfo> msgs, const QString& url, const QString& path);
|
||||
void responseVCard(const QString& jid, const Shared::VCard& card);
|
||||
void changeMessage(const QString& account, const QString& jid, const QString& id, const QMap<QString, QVariant>& data);
|
||||
void requestPassword(const QString& account, bool authenticationError);
|
||||
void select(QModelIndex index);
|
||||
|
||||
private:
|
||||
typedef std::map<Models::Roster::ElId, Conversation*> Conversations;
|
||||
QScopedPointer<Ui::Squawk> m_ui;
|
||||
|
||||
Accounts* accounts;
|
||||
Settings* preferences;
|
||||
About* about;
|
||||
DialogQueue dialogueQueue;
|
||||
Models::Roster rosterModel;
|
||||
Conversations conversations;
|
||||
Models::Roster& rosterModel;
|
||||
QMenu* contextMenu;
|
||||
QDBusInterface dbus;
|
||||
std::map<QString, VCard*> vCards;
|
||||
Conversation* currentConversation;
|
||||
QModelIndex restoreSelection;
|
||||
|
@ -135,9 +107,7 @@ private:
|
|||
|
||||
protected:
|
||||
void closeEvent(QCloseEvent * event) override;
|
||||
|
||||
protected slots:
|
||||
void notify(const QString& account, const Shared::Message& msg);
|
||||
void expand(const QModelIndex& index);
|
||||
|
||||
private slots:
|
||||
void onAccounts();
|
||||
|
@ -149,27 +119,17 @@ private slots:
|
|||
void onAccountsSizeChanged(unsigned int size);
|
||||
void onAccountsClosed();
|
||||
void onPreferencesClosed();
|
||||
void onConversationClosed(QObject* parent = 0);
|
||||
void onVCardClosed();
|
||||
void onVCardSave(const Shared::VCard& card, const QString& account);
|
||||
void onActivateVCard(const QString& account, const QString& jid, bool edition = false);
|
||||
void onComboboxActivated(int index);
|
||||
void onRosterItemDoubleClicked(const QModelIndex& item);
|
||||
void onConversationMessage(const Shared::Message& msg);
|
||||
void onConversationReplaceMessage(const QString& originalId, const Shared::Message& msg);
|
||||
void onConversationResend(const QString& id);
|
||||
void onRequestArchive(const QString& account, const QString& jid, const QString& before);
|
||||
void onRosterContextMenu(const QPoint& point);
|
||||
void onItemCollepsed(const QModelIndex& index);
|
||||
void onRosterSelectionChanged(const QModelIndex& current, const QModelIndex& previous);
|
||||
void onContextAboutToHide();
|
||||
void onAboutSquawkCalled();
|
||||
void onAboutSquawkClosed();
|
||||
|
||||
void onUnnoticedMessage(const QString& account, const Shared::Message& msg);
|
||||
|
||||
private:
|
||||
void subscribeConversation(Conversation* conv);
|
||||
};
|
||||
|
||||
#endif // SQUAWK_H
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
#include <QFileDialog>
|
||||
#include <QMimeDatabase>
|
||||
#include <QAbstractTextDocumentLayout>
|
||||
#include <QCoreApplication>
|
||||
#include <QApplication>
|
||||
#include <QTemporaryFile>
|
||||
#include <QDir>
|
||||
#include <QMenu>
|
||||
|
@ -498,6 +498,16 @@ void Conversation::onFeedContext(const QPoint& pos)
|
|||
emit resendMessage(id);
|
||||
});
|
||||
}
|
||||
|
||||
QString body = item->getBody();
|
||||
if (body.size() > 0) {
|
||||
showMenu = true;
|
||||
QAction* copy = contextMenu->addAction(Shared::icon("edit-copy"), tr("Copy message"));
|
||||
connect(copy, &QAction::triggered, [body] () {
|
||||
QClipboard* cb = QApplication::clipboard();
|
||||
cb->setText(body);
|
||||
});
|
||||
}
|
||||
|
||||
QString path = Shared::resolvePath(item->getAttachPath());
|
||||
if (path.size() > 0) {
|
||||
|
|
|
@ -664,9 +664,32 @@ int MessageDelegate::paintBody(const Models::FeedItem& data, QPainter* painter,
|
|||
if (data.text.size() > 0) {
|
||||
bodyRenderer->setHtml(Shared::processMessageBody(data.text));
|
||||
bodyRenderer->setTextWidth(option.rect.size().width());
|
||||
painter->setBackgroundMode(Qt::BGMode::OpaqueMode);
|
||||
painter->save();
|
||||
// QTextCursor cursor(bodyRenderer);
|
||||
// cursor.setPosition(2, QTextCursor::KeepAnchor);
|
||||
painter->translate(option.rect.topLeft());
|
||||
// QTextFrameFormat format = bodyRenderer->rootFrame()->frameFormat();
|
||||
// format.setBackground(option.palette.brush(QPalette::Active, QPalette::Highlight));
|
||||
// bodyRenderer->rootFrame()->setFrameFormat(format);
|
||||
bodyRenderer->drawContents(painter);
|
||||
// QColor c = option.palette.color(QPalette::Active, QPalette::Highlight);
|
||||
// QTextBlock b = bodyRenderer->begin();
|
||||
// QTextBlockFormat format = b.blockFormat();
|
||||
// format.setBackground(option.palette.brush(QPalette::Active, QPalette::Highlight));
|
||||
// format.setProperty(QTextFormat::BackgroundBrush, option.palette.brush(QPalette::Active, QPalette::Highlight));
|
||||
// QTextCursor cursor(bodyRenderer);
|
||||
// cursor.setBlockFormat(format);
|
||||
// b = bodyRenderer->begin();
|
||||
// while (b.isValid() > 0) {
|
||||
// QTextLayout* lay = b.layout();
|
||||
// QTextLayout::FormatRange range;
|
||||
// range.format = b.charFormat();
|
||||
// range.start = 0;
|
||||
// range.length = 2;
|
||||
// lay->draw(painter, option.rect.topLeft(), {range});
|
||||
// b = b.next();
|
||||
// }
|
||||
painter->restore();
|
||||
QSize bodySize(std::ceil(bodyRenderer->idealWidth()), std::ceil(bodyRenderer->size().height()));
|
||||
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
#include <QPushButton>
|
||||
#include <QProgressBar>
|
||||
#include <QLabel>
|
||||
#include <QTextDocument>
|
||||
|
||||
#include "shared/icons.h"
|
||||
#include "shared/global.h"
|
||||
|
|
|
@ -163,6 +163,12 @@ void Models::MessageFeed::changeMessage(const QString& id, const QMap<QString, Q
|
|||
}
|
||||
|
||||
emit dataChanged(index, index, cr);
|
||||
|
||||
if (observersAmount == 0 && !msg->getForwarded() && changeRoles.count(MessageRoles::Text) > 0) {
|
||||
unreadMessages->insert(id);
|
||||
emit unreadMessagesCountChanged();
|
||||
emit unnoticedMessage(*msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -312,12 +318,7 @@ QVariant Models::MessageFeed::data(const QModelIndex& index, int role) const
|
|||
case Bulk: {
|
||||
FeedItem item;
|
||||
item.id = msg->getId();
|
||||
|
||||
std::set<QString>::const_iterator umi = unreadMessages->find(item.id);
|
||||
if (umi != unreadMessages->end()) {
|
||||
unreadMessages->erase(umi);
|
||||
emit unreadMessagesCountChanged();
|
||||
}
|
||||
markMessageAsRead(item.id);
|
||||
|
||||
item.sentByMe = sentByMe(*msg);
|
||||
item.date = msg->getTime();
|
||||
|
@ -367,6 +368,17 @@ int Models::MessageFeed::rowCount(const QModelIndex& parent) const
|
|||
return storage.size();
|
||||
}
|
||||
|
||||
bool Models::MessageFeed::markMessageAsRead(const QString& id) const
|
||||
{
|
||||
std::set<QString>::const_iterator umi = unreadMessages->find(id);
|
||||
if (umi != unreadMessages->end()) {
|
||||
unreadMessages->erase(umi);
|
||||
emit unreadMessagesCountChanged();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned int Models::MessageFeed::unreadMessagesCount() const
|
||||
{
|
||||
return unreadMessages->size();
|
||||
|
|
|
@ -72,6 +72,7 @@ public:
|
|||
void reportLocalPathInvalid(const QString& messageId);
|
||||
|
||||
unsigned int unreadMessagesCount() const;
|
||||
bool markMessageAsRead(const QString& id) const;
|
||||
void fileProgress(const QString& messageId, qreal value, bool up);
|
||||
void fileError(const QString& messageId, const QString& error, bool up);
|
||||
void fileComplete(const QString& messageId, bool up);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue