forked from blue/squawk
Basic presence with subnodes
This commit is contained in:
parent
de21036456
commit
e8eaced6e9
@ -1,5 +1,6 @@
|
||||
#include "account.h"
|
||||
#include <qxmpp/QXmppRosterManager.h>
|
||||
#include <QDateTime>
|
||||
|
||||
using namespace Core;
|
||||
|
||||
@ -15,7 +16,7 @@ Account::Account(const QString& p_login, const QString& p_server, const QString&
|
||||
{
|
||||
QObject::connect(&client, SIGNAL(connected()), this, SLOT(onClientConnected()));
|
||||
QObject::connect(&client, SIGNAL(disconnected()), this, SLOT(onClientDisconnected()));
|
||||
|
||||
QObject::connect(&client, SIGNAL(presenceReceived(const QXmppPresence&)), this, SLOT(onPresenceReceived(const QXmppPresence&)));
|
||||
|
||||
QXmppRosterManager& rm = client.rosterManager();
|
||||
|
||||
@ -23,6 +24,7 @@ Account::Account(const QString& p_login, const QString& p_server, const QString&
|
||||
QObject::connect(&rm, SIGNAL(itemAdded(const QString&)), this, SLOT(onRosterItemAdded(const QString&)));
|
||||
QObject::connect(&rm, SIGNAL(itemRemoved(const QString&)), this, SLOT(onRosterItemRemoved(const QString&)));
|
||||
QObject::connect(&rm, SIGNAL(itemChanged(const QString&)), this, SLOT(onRosterItemChanged(const QString&)));
|
||||
//QObject::connect(&rm, SIGNAL(presenceChanged(const QString&, const QString&)), this, SLOT(onRosterPresenceChanged(const QString&, const QString&)));
|
||||
}
|
||||
|
||||
Account::~Account()
|
||||
@ -116,6 +118,9 @@ void Core::Account::onRosterItemChanged(const QString& bareJid)
|
||||
QSet<QString> newGroups = re.groups();
|
||||
QSet<QString> oldGroups;
|
||||
|
||||
|
||||
QStringList res = rm.getResources(bareJid);
|
||||
|
||||
emit changeContact(bareJid, re.name());
|
||||
|
||||
for (std::map<QString, std::set<QString>>::iterator itr = groups.begin(), end = groups.end(); itr != end; ++itr) {
|
||||
@ -204,3 +209,50 @@ void Core::Account::addedAccount(const QString& jid)
|
||||
}
|
||||
}
|
||||
|
||||
void Core::Account::onPresenceReceived(const QXmppPresence& presence)
|
||||
{
|
||||
QString id = presence.from();
|
||||
QStringList comps = id.split("/");
|
||||
QString jid = comps.front();
|
||||
QString resource = comps.back();
|
||||
|
||||
switch (presence.type()) {
|
||||
case QXmppPresence::Error:
|
||||
qDebug() << "An error reported by presence from " << id;
|
||||
break;
|
||||
case QXmppPresence::Available:{
|
||||
QDateTime lastInteraction = presence.lastUserInteraction();
|
||||
if (!lastInteraction.isValid()) {
|
||||
lastInteraction = QDateTime::currentDateTime();
|
||||
}
|
||||
emit addPresence(jid, resource, {
|
||||
{"lastActivity", lastInteraction},
|
||||
{"availability", presence.availableStatusType()}, //TODO check and handle invisible
|
||||
{"status", presence.statusText()}
|
||||
});
|
||||
}
|
||||
break;
|
||||
case QXmppPresence::Unavailable:
|
||||
emit removePresence(jid, resource);
|
||||
break;
|
||||
case QXmppPresence::Subscribe:
|
||||
qDebug("xmpp presence \"subscribe\" received, do not yet know what to do, skipping");
|
||||
case QXmppPresence::Subscribed:
|
||||
qDebug("xmpp presence \"subscribed\" received, do not yet know what to do, skipping");
|
||||
case QXmppPresence::Unsubscribe:
|
||||
qDebug("xmpp presence \"unsubscribe\" received, do not yet know what to do, skipping");
|
||||
case QXmppPresence::Unsubscribed:
|
||||
qDebug("xmpp presence \"unsubscribed\" received, do not yet know what to do, skipping");
|
||||
case QXmppPresence::Probe:
|
||||
qDebug("xmpp presence \"probe\" received, do not yet know what to do, skipping");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void Core::Account::onRosterPresenceChanged(const QString& bareJid, const QString& resource)
|
||||
{
|
||||
//not used for now;
|
||||
qDebug() << "presence changed for " << bareJid << " resource " << resource;
|
||||
const QXmppPresence& presence = client.rosterManager().getPresence(bareJid, resource);
|
||||
}
|
||||
|
||||
|
@ -35,6 +35,8 @@ signals:
|
||||
void removeContact(const QString& jid);
|
||||
void removeContact(const QString& jid, const QString& group);
|
||||
void changeContact(const QString& jid, const QString& name);
|
||||
void addPresence(const QString& jid, const QString& name, const QMap<QString, QVariant>& data);
|
||||
void removePresence(const QString& jid, const QString& name);
|
||||
|
||||
private:
|
||||
QString name;
|
||||
@ -49,9 +51,11 @@ private slots:
|
||||
void onClientConnected();
|
||||
void onClientDisconnected();
|
||||
void onRosterReceived();
|
||||
void onRosterItemAdded(const QString &bareJid);
|
||||
void onRosterItemChanged(const QString &bareJid);
|
||||
void onRosterItemRemoved(const QString &bareJid);
|
||||
void onRosterItemAdded(const QString& bareJid);
|
||||
void onRosterItemChanged(const QString& bareJid);
|
||||
void onRosterItemRemoved(const QString& bareJid);
|
||||
void onRosterPresenceChanged(const QString& bareJid, const QString& resource);
|
||||
void onPresenceReceived(const QXmppPresence& presence);
|
||||
|
||||
private:
|
||||
void addedAccount(const QString &bareJid);
|
||||
|
@ -80,6 +80,9 @@ void Core::Squawk::addAccount(const QString& login, const QString& server, const
|
||||
connect(acc, SIGNAL(removeContact(const QString&)), this, SLOT(onAccountRemoveContact(const QString&)));
|
||||
connect(acc, SIGNAL(removeContact(const QString&, const QString&)), this, SLOT(onAccountRemoveContact(const QString&, const QString&)));
|
||||
connect(acc, SIGNAL(changeContact(const QString&, const QString&)), this, SLOT(onAccountChangeContact(const QString&, const QString&)));
|
||||
connect(acc, SIGNAL(addPresence(const QString&, const QString&, const QMap<QString, QVariant>&)),
|
||||
this, SLOT(onAccountAddPresence(const QString&, const QString&, const QMap<QString, QVariant>&)));
|
||||
connect(acc, SIGNAL(removePresence(const QString&, const QString&)), this, SLOT(onAccountRemovePresence(const QString&, const QString&)));
|
||||
|
||||
QMap<QString, QVariant> map = {
|
||||
{"login", login},
|
||||
@ -153,3 +156,15 @@ void Core::Squawk::onAccountRemoveContact(const QString& jid, const QString& gro
|
||||
Account* acc = static_cast<Account*>(sender());
|
||||
emit removeContact(acc->getName(), jid, group);
|
||||
}
|
||||
|
||||
void Core::Squawk::onAccountAddPresence(const QString& jid, const QString& name, const QMap<QString, QVariant>& data)
|
||||
{
|
||||
Account* acc = static_cast<Account*>(sender());
|
||||
emit addPresence(acc->getName(), jid, name, data);
|
||||
}
|
||||
|
||||
void Core::Squawk::onAccountRemovePresence(const QString& jid, const QString& name)
|
||||
{
|
||||
Account* acc = static_cast<Account*>(sender());
|
||||
emit removePresence(acc->getName(), jid, name);
|
||||
}
|
||||
|
@ -31,6 +31,8 @@ signals:
|
||||
void removeContact(const QString& account, const QString& jid);
|
||||
void removeContact(const QString& account, const QString& jid, const QString& group);
|
||||
void changeContact(const QString& account, const QString& jid, const QString& name);
|
||||
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);
|
||||
|
||||
public slots:
|
||||
void start();
|
||||
@ -57,6 +59,8 @@ private slots:
|
||||
void onAccountRemoveContact(const QString& jid);
|
||||
void onAccountRemoveContact(const QString& jid, const QString& group);
|
||||
void onAccountChangeContact(const QString& jid, const QString& name);
|
||||
void onAccountAddPresence(const QString& jid, const QString& name, const QMap<QString, QVariant>& data);
|
||||
void onAccountRemovePresence(const QString& jid, const QString& name);
|
||||
};
|
||||
|
||||
}
|
||||
|
12
global.h
12
global.h
@ -13,6 +13,18 @@ enum ConnectionState {
|
||||
error
|
||||
};
|
||||
|
||||
enum Availability {
|
||||
online,
|
||||
away,
|
||||
extendedAway,
|
||||
busy,
|
||||
chatty,
|
||||
offline
|
||||
};
|
||||
|
||||
static const Availability availabilityHighest = offline;
|
||||
static const Availability availabilityLowest = online;
|
||||
|
||||
static const std::deque<QString> ConnectionStateNames = {"Disconnected", "Connecting", "Connected", "Error"};
|
||||
static const std::deque<QString> ConnectionStateThemeIcons = {"network-disconnect", "view-refresh", "network-connect", "state-error"};
|
||||
|
||||
|
3
main.cpp
3
main.cpp
@ -41,6 +41,9 @@ int main(int argc, char *argv[])
|
||||
QObject::connect(squawk, SIGNAL(removeContact(const QString&, const QString&)), &w, SLOT(removeContact(const QString&, const QString&)));
|
||||
QObject::connect(squawk, SIGNAL(removeContact(const QString&, const QString&, const QString&)), &w, SLOT(removeContact(const QString&, const QString&, const QString&)));
|
||||
QObject::connect(squawk, SIGNAL(changeContact(const QString&, const QString&, const QString&)), &w, SLOT(changeContact(const QString&, const QString&, const QString&)));
|
||||
QObject::connect(squawk, SIGNAL(addPresence(const QString&, const QString&, const QString&, const QMap<QString, QVariant>&)),
|
||||
&w, SLOT(addPresence(const QString&, const QString&, const QString&, const QMap<QString, QVariant>&)));
|
||||
QObject::connect(squawk, SIGNAL(removePresence(const QString&, const QString&, const QString&)), &w, SLOT(removePresence(const QString&, const QString&, const QString&)));
|
||||
|
||||
coreThread->start();
|
||||
|
||||
|
@ -18,6 +18,7 @@ set(squawkUI_SRC
|
||||
models/item.cpp
|
||||
models/account.cpp
|
||||
models/contact.cpp
|
||||
models/presence.cpp
|
||||
)
|
||||
|
||||
# Tell CMake to create the helloworld executable
|
||||
|
@ -17,7 +17,7 @@ void Models::Account::setState(int p_state)
|
||||
{
|
||||
if (state != p_state) {
|
||||
state = p_state;
|
||||
emit changed(2);
|
||||
changed(2);
|
||||
}
|
||||
}
|
||||
|
||||
@ -45,7 +45,7 @@ void Models::Account::setLogin(const QString& p_login)
|
||||
{
|
||||
if (login != p_login) {
|
||||
login = p_login;
|
||||
emit changed(3);
|
||||
changed(3);
|
||||
}
|
||||
}
|
||||
|
||||
@ -53,7 +53,7 @@ void Models::Account::setPassword(const QString& p_password)
|
||||
{
|
||||
if (password != p_password) {
|
||||
password = p_password;
|
||||
emit changed(4);
|
||||
changed(4);
|
||||
}
|
||||
}
|
||||
|
||||
@ -61,7 +61,7 @@ void Models::Account::setServer(const QString& p_server)
|
||||
{
|
||||
if (server != p_server) {
|
||||
server = p_server;
|
||||
emit changed(1);
|
||||
changed(1);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -63,17 +63,19 @@ void Models::Accounts::addAccount(Account* account)
|
||||
{
|
||||
beginInsertRows(QModelIndex(), accs.size(), accs.size());
|
||||
accs.push_back(account);
|
||||
connect(account, SIGNAL(changed(int)), this, SLOT(onAccountChanged(int)));
|
||||
connect(account, SIGNAL(childChanged(Item*, int, int)), this, SLOT(onAccountChanged(Item*, int, int)));
|
||||
endInsertRows();
|
||||
}
|
||||
|
||||
void Models::Accounts::onAccountChanged(int column)
|
||||
void Models::Accounts::onAccountChanged(Item* item, int row, int col)
|
||||
{
|
||||
Account* acc = static_cast<Account*>(sender());
|
||||
Account* acc = getAccount(row);
|
||||
if (item != acc) {
|
||||
return; //it means the signal is emitted by one of accounts' children, not exactly him, this model has no interest in that
|
||||
}
|
||||
|
||||
if (column < columnCount(QModelIndex())) {
|
||||
int row = acc->row();
|
||||
emit dataChanged(createIndex(row, column, this), createIndex(row, column, this));
|
||||
if (col < columnCount(QModelIndex())) {
|
||||
emit dataChanged(createIndex(row, col, this), createIndex(row, col, this));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -29,7 +29,7 @@ private:
|
||||
static std::deque<QString> columns;
|
||||
|
||||
private slots:
|
||||
void onAccountChanged(int column);
|
||||
void onAccountChanged(Item* item, int row, int col);
|
||||
|
||||
};
|
||||
}
|
||||
|
@ -1,9 +1,11 @@
|
||||
#include "contact.h"
|
||||
#include <QDebug>
|
||||
|
||||
Models::Contact::Contact(const QMap<QString, QVariant>& data, Models::Item* parentItem):
|
||||
Item(Item::contact, data, parentItem),
|
||||
jid(data.value("jid").toString()),
|
||||
state(data.value("state").toInt())
|
||||
state(Shared::offline),
|
||||
presences()
|
||||
{
|
||||
}
|
||||
|
||||
@ -20,20 +22,20 @@ void Models::Contact::setJid(const QString p_jid)
|
||||
{
|
||||
if (jid != p_jid) {
|
||||
jid = p_jid;
|
||||
emit changed(1);
|
||||
changed(1);
|
||||
}
|
||||
}
|
||||
|
||||
int Models::Contact::getState() const
|
||||
Shared::Availability Models::Contact::getState() const
|
||||
{
|
||||
return state;
|
||||
}
|
||||
|
||||
void Models::Contact::setState(int p_state)
|
||||
void Models::Contact::setState(Shared::Availability p_state)
|
||||
{
|
||||
if (state != p_state) {
|
||||
state = p_state;
|
||||
emit changed(2);
|
||||
changed(2);
|
||||
}
|
||||
}
|
||||
|
||||
@ -67,6 +69,78 @@ void Models::Contact::update(const QString& field, const QVariant& value)
|
||||
} else if (field == "jid") {
|
||||
setJid(value.toString());
|
||||
} else if (field == "state") {
|
||||
setState(value.toInt());
|
||||
unsigned int iState = value.toUInt();
|
||||
if (iState <= Shared::availabilityHighest) {
|
||||
Shared::Availability state = static_cast<Shared::Availability>(iState);
|
||||
setState(state);
|
||||
} else {
|
||||
qDebug("An attempt to set wrong state to the contact");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Models::Contact::addPresence(const QString& p_name, const QMap<QString, QVariant>& data)
|
||||
{
|
||||
QMap<QString, Presence*>::iterator itr = presences.find(p_name);
|
||||
|
||||
if (itr == presences.end()) {
|
||||
Presence* pr = new Presence(data);
|
||||
pr->setName(p_name);
|
||||
presences.insert(p_name, pr);
|
||||
appendChild(pr);
|
||||
} else {
|
||||
Presence* pr = itr.value();
|
||||
for (QMap<QString, QVariant>::const_iterator itr = data.begin(), end = data.end(); itr != end; ++itr) {
|
||||
pr->update(itr.key(), itr.value());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Models::Contact::removePresence(const QString& name)
|
||||
{
|
||||
QMap<QString, Presence*>::iterator itr = presences.find(name);
|
||||
|
||||
if (itr == presences.end()) {
|
||||
} else {
|
||||
Presence* pr = itr.value();
|
||||
presences.erase(itr);
|
||||
removeChild(pr->row());
|
||||
}
|
||||
}
|
||||
|
||||
void Models::Contact::refresh()
|
||||
{
|
||||
QDateTime lastActivity;
|
||||
Presence* presence = 0;
|
||||
for (QMap<QString, Presence*>::iterator itr = presences.begin(), end = presences.end(); itr != end; ++itr) {
|
||||
Presence* pr = itr.value();
|
||||
QDateTime la = pr->getLastActivity();
|
||||
|
||||
if (la > lastActivity) {
|
||||
lastActivity = la;
|
||||
presence = pr;
|
||||
}
|
||||
}
|
||||
|
||||
if (presence != 0) {
|
||||
setState(presence->getAvailability());
|
||||
}
|
||||
}
|
||||
|
||||
void Models::Contact::_removeChild(int index)
|
||||
{
|
||||
Item::_removeChild(index);
|
||||
refresh();
|
||||
}
|
||||
|
||||
void Models::Contact::appendChild(Models::Item* child)
|
||||
{
|
||||
Item::appendChild(child);
|
||||
refresh();
|
||||
}
|
||||
|
||||
void Models::Contact::changed(int col)
|
||||
{
|
||||
Item::changed(col);
|
||||
refresh();
|
||||
}
|
||||
|
@ -2,6 +2,9 @@
|
||||
#define MODELS_CONTACT_H
|
||||
|
||||
#include "item.h"
|
||||
#include "presence.h"
|
||||
#include "../../global.h"
|
||||
#include <QMap>
|
||||
|
||||
namespace Models {
|
||||
|
||||
@ -13,19 +16,32 @@ public:
|
||||
~Contact();
|
||||
|
||||
QString getJid() const;
|
||||
void setJid(const QString p_jid);
|
||||
|
||||
int getState() const;
|
||||
void setState(int p_state);
|
||||
Shared::Availability getState() const;
|
||||
|
||||
int columnCount() const override;
|
||||
QVariant data(int column) const override;
|
||||
|
||||
void update(const QString& field, const QVariant& value);
|
||||
|
||||
void addPresence(const QString& name, const QMap<QString, QVariant>& data);
|
||||
void removePresence(const QString& name);
|
||||
|
||||
void appendChild(Models::Item * child) override;
|
||||
|
||||
protected:
|
||||
void refresh();
|
||||
void changed(int col) override;
|
||||
void _removeChild(int index) override;
|
||||
|
||||
protected:
|
||||
void setState(Shared::Availability p_state);
|
||||
void setJid(const QString p_jid);
|
||||
|
||||
private:
|
||||
QString jid;
|
||||
int state;
|
||||
Shared::Availability state;
|
||||
QMap<QString, Presence*> presences;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -1,7 +1,5 @@
|
||||
#include "item.h"
|
||||
|
||||
using namespace Models;
|
||||
|
||||
Models::Item::Item(Type p_type, const QMap<QString, QVariant> &p_data, Item *p_parent):
|
||||
QObject(),
|
||||
type(p_type),
|
||||
@ -24,13 +22,38 @@ void Models::Item::setName(const QString& p_name)
|
||||
{
|
||||
if (name != p_name) {
|
||||
name = p_name;
|
||||
emit changed(0);
|
||||
changed(0);
|
||||
}
|
||||
}
|
||||
|
||||
void Models::Item::appendChild(Models::Item* child)
|
||||
{
|
||||
bool moving = false;
|
||||
int oldRow = child->row();
|
||||
int newRow = this->childCount();
|
||||
if (child->parent != 0) {
|
||||
moving = true;
|
||||
emit childIsAboutToBeMoved(child->parent, oldRow, oldRow, this, newRow);
|
||||
child->parent->_removeChild(oldRow);
|
||||
} else {
|
||||
emit childIsAboutToBeInserted(this, newRow, newRow);
|
||||
}
|
||||
childItems.push_back(child);
|
||||
child->parent = this;
|
||||
|
||||
QObject::connect(child, SIGNAL(childChanged(Item*, int, int)), this, SIGNAL(childChanged(Item*, int, int)));
|
||||
QObject::connect(child, SIGNAL(childIsAboutToBeInserted(Item*, int, int)), this, SIGNAL(childIsAboutToBeInserted(Item*, int, int)));
|
||||
QObject::connect(child, SIGNAL(childInserted()), this, SIGNAL(childInserted()));
|
||||
QObject::connect(child, SIGNAL(childIsAboutToBeRemoved(Item*, int, int)), this, SIGNAL(childIsAboutToBeRemoved(Item*, int, int)));
|
||||
QObject::connect(child, SIGNAL(childRemoved()), this, SIGNAL(childRemoved()));
|
||||
QObject::connect(child, SIGNAL(childIsAboutToBeMoved(Item*, int, int, Item*, int)), this, SIGNAL(childIsAboutToBeMoved(Item*, int, int, Item*, int)));
|
||||
QObject::connect(child, SIGNAL(childMoved()), this, SIGNAL(childMoved()));
|
||||
|
||||
if (moving) {
|
||||
emit childMoved();
|
||||
} else {
|
||||
emit childInserted();
|
||||
}
|
||||
}
|
||||
|
||||
Models::Item * Models::Item::child(int row)
|
||||
@ -74,7 +97,6 @@ QString Models::Item::getName() const
|
||||
return name;
|
||||
}
|
||||
|
||||
|
||||
QVariant Models::Item::data(int column) const
|
||||
{
|
||||
if (column != 0) {
|
||||
@ -85,14 +107,31 @@ QVariant Models::Item::data(int column) const
|
||||
|
||||
void Models::Item::removeChild(int index)
|
||||
{
|
||||
childItems.erase(childItems.begin() + index);
|
||||
emit childIsAboutToBeRemoved(this, index, index);
|
||||
removeChild(index);
|
||||
emit childRemoved();
|
||||
}
|
||||
|
||||
void Models::Item::setParent(Models::Item* p_parent)
|
||||
void Models::Item::_removeChild(int index)
|
||||
{
|
||||
parent = p_parent;
|
||||
Item* child = childItems[index];
|
||||
|
||||
QObject::connect(child, SIGNAL(childChanged(Item*, int, int)), this, SIGNAL(childChanged(Item*, int, int)));
|
||||
QObject::connect(child, SIGNAL(childIsAboutToBeInserted(Item*, int, int)), this, SIGNAL(childIsAboutToBeInserted(Item*, int, int)));
|
||||
QObject::connect(child, SIGNAL(childInserted()), this, SIGNAL(childInserted()));
|
||||
QObject::connect(child, SIGNAL(childIsAboutToBeRemoved(Item*, int, int)), this, SIGNAL(childIsAboutToBeRemoved(Item*, int, int)));
|
||||
QObject::connect(child, SIGNAL(childRemoved()), this, SIGNAL(childRemoved()));
|
||||
QObject::connect(child, SIGNAL(childIsAboutToBeMoved(Item*, int, int, Item*, int)), this, SIGNAL(childIsAboutToBeMoved(Item*, int, int, Item*, int)));
|
||||
QObject::connect(child, SIGNAL(childMoved()), this, SIGNAL(childMoved()));
|
||||
|
||||
childItems.erase(childItems.begin() + index);
|
||||
child->parent = 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void Models::Item::changed(int col)
|
||||
{
|
||||
if (parent != 0) {
|
||||
emit childChanged(this, row(), col);
|
||||
}
|
||||
}
|
||||
|
@ -17,6 +17,7 @@ class Item : public QObject{
|
||||
group,
|
||||
contact,
|
||||
conversation,
|
||||
presence,
|
||||
root
|
||||
};
|
||||
|
||||
@ -24,11 +25,17 @@ class Item : public QObject{
|
||||
~Item();
|
||||
|
||||
signals:
|
||||
void changed(int col);
|
||||
|
||||
void childChanged(Item* item, int row, int col);
|
||||
void childIsAboutToBeInserted(Item* parent, int first, int last);
|
||||
void childInserted();
|
||||
void childIsAboutToBeRemoved(Item* parent, int first, int last);
|
||||
void childRemoved();
|
||||
void childIsAboutToBeMoved(Item* source, int first, int last, Item* destination, int newIndex);
|
||||
void childMoved();
|
||||
|
||||
public:
|
||||
void appendChild(Item *child);
|
||||
void removeChild(int index);
|
||||
virtual void appendChild(Item *child);
|
||||
virtual void removeChild(int index);
|
||||
QString getName() const;
|
||||
void setName(const QString& name);
|
||||
|
||||
@ -38,16 +45,32 @@ class Item : public QObject{
|
||||
virtual QVariant data(int column) const;
|
||||
int row() const;
|
||||
Item *parentItem();
|
||||
void setParent(Item* p_parent);
|
||||
|
||||
const Type type;
|
||||
|
||||
protected:
|
||||
virtual void changed(int col);
|
||||
virtual void _removeChild(int index);
|
||||
|
||||
protected:
|
||||
QString name;
|
||||
std::deque<Item*> childItems;
|
||||
Item* parent;
|
||||
|
||||
protected slots:
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
namespace Shared {
|
||||
static const std::deque<QString> AvailabilityIcons = {
|
||||
"im-user-online",
|
||||
"im-user-away",
|
||||
"im-user-away",
|
||||
"im-user-busy",
|
||||
"im-user-online",
|
||||
"im-user-offline"
|
||||
};
|
||||
}
|
||||
|
||||
#endif // MODELS_ITEM_H
|
||||
|
119
ui/models/presence.cpp
Normal file
119
ui/models/presence.cpp
Normal file
@ -0,0 +1,119 @@
|
||||
/*
|
||||
* <one line to give the program's name and a brief idea of what it does.>
|
||||
* 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 "presence.h"
|
||||
|
||||
Models::Presence::Presence(const QMap<QString, QVariant>& data, Item* parentItem):
|
||||
Item(Item::presence, data, parentItem),
|
||||
availability(Shared::offline),
|
||||
lastActivity(data.value("lastActivity").toDateTime()),
|
||||
status(data.value("status").toString())
|
||||
{
|
||||
QMap<QString, QVariant>::const_iterator itr = data.find("availability");
|
||||
if (itr != data.end()) {
|
||||
setAvailability(itr.value().toUInt());
|
||||
}
|
||||
}
|
||||
|
||||
Models::Presence::~Presence()
|
||||
{
|
||||
}
|
||||
|
||||
int Models::Presence::columnCount() const
|
||||
{
|
||||
return 4;
|
||||
}
|
||||
|
||||
QVariant Models::Presence::data(int column) const
|
||||
{
|
||||
switch (column) {
|
||||
case 0:
|
||||
return Item::data(column);
|
||||
case 1:
|
||||
return lastActivity;
|
||||
case 2:
|
||||
return availability;
|
||||
case 3:
|
||||
return status;
|
||||
default:
|
||||
return QVariant();
|
||||
}
|
||||
}
|
||||
|
||||
Shared::Availability Models::Presence::getAvailability() const
|
||||
{
|
||||
return availability;
|
||||
}
|
||||
|
||||
QDateTime Models::Presence::getLastActivity() const
|
||||
{
|
||||
return lastActivity;
|
||||
}
|
||||
|
||||
QString Models::Presence::getStatus() const
|
||||
{
|
||||
return status;
|
||||
}
|
||||
|
||||
void Models::Presence::setAvailability(Shared::Availability p_avail)
|
||||
{
|
||||
if (availability != p_avail) {
|
||||
availability = p_avail;
|
||||
changed(2);
|
||||
}
|
||||
}
|
||||
|
||||
void Models::Presence::setAvailability(unsigned int avail)
|
||||
{
|
||||
if (avail <= Shared::availabilityHighest) {
|
||||
Shared::Availability state = static_cast<Shared::Availability>(avail);
|
||||
setAvailability(state);
|
||||
} else {
|
||||
qDebug("An attempt to set wrong state to the contact");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Models::Presence::setLastActivity(const QDateTime& p_time)
|
||||
{
|
||||
if (lastActivity != p_time) {
|
||||
lastActivity = p_time;
|
||||
changed(1);
|
||||
}
|
||||
}
|
||||
|
||||
void Models::Presence::setStatus(const QString& p_state)
|
||||
{
|
||||
if (status != p_state) {
|
||||
status = p_state;
|
||||
changed(3);
|
||||
}
|
||||
}
|
||||
|
||||
void Models::Presence::update(const QString& key, const QVariant& value)
|
||||
{
|
||||
if (key == "name") {
|
||||
setName(value.toString());
|
||||
} else if (key == "status") {
|
||||
setStatus(value.toString());
|
||||
} else if (key == "availability") {
|
||||
setAvailability(value.toUInt());
|
||||
} else if (key == "lastActivity") {
|
||||
setLastActivity(value.toDateTime());
|
||||
}
|
||||
}
|
58
ui/models/presence.h
Normal file
58
ui/models/presence.h
Normal file
@ -0,0 +1,58 @@
|
||||
/*
|
||||
* <one line to give the program's name and a brief idea of what it does.>
|
||||
* 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 MODELS_PRESENCE_H
|
||||
#define MODELS_PRESENCE_H
|
||||
|
||||
#include "item.h"
|
||||
#include "../../global.h"
|
||||
#include <QDateTime>
|
||||
|
||||
namespace Models {
|
||||
|
||||
class Presence : public Models::Item
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit Presence(const QMap<QString, QVariant> &data, Item *parentItem = 0);
|
||||
~Presence();
|
||||
|
||||
virtual int columnCount() const override;
|
||||
virtual QVariant data(int column) const override;
|
||||
|
||||
Shared::Availability getAvailability() const;
|
||||
void setAvailability(Shared::Availability p_avail);
|
||||
void setAvailability(unsigned int avail);
|
||||
|
||||
QDateTime getLastActivity() const;
|
||||
void setLastActivity(const QDateTime& p_time);
|
||||
|
||||
QString getStatus() const;
|
||||
void setStatus(const QString& p_state);
|
||||
|
||||
void update(const QString& key, const QVariant& value);
|
||||
|
||||
private:
|
||||
Shared::Availability availability;
|
||||
QDateTime lastActivity;
|
||||
QString status;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // MODELS_PRESENCE_H
|
@ -17,6 +17,13 @@ Models::Roster::Roster(QObject* parent):
|
||||
SIGNAL(dataChanged(const QModelIndex&, const QModelIndex&, const QVector<int>&)),
|
||||
this,
|
||||
SLOT(onAccountDataChanged(const QModelIndex&, const QModelIndex&, const QVector<int>&)));
|
||||
connect(root, SIGNAL(childChanged(Item*, int, int)), this, SLOT(onChildChanged(Item*, int, int)));
|
||||
connect(root, SIGNAL(childIsAboutToBeInserted(Item*, int, int)), this, SLOT(onChildIsAboutToBeInserted(Item*, int, int)));
|
||||
connect(root, SIGNAL(childInserted()), this, SLOT(onChildInserted()));
|
||||
connect(root, SIGNAL(childIsAboutToBeRemoved(Item*, int, int)), this, SLOT(onChildIsAboutToBeRemoved(Item*, int, int)));
|
||||
connect(root, SIGNAL(childRemoved()), this, SLOT(onChildRemoved()));
|
||||
connect(root, SIGNAL(childIsAboutToBeMoved(Item*, int, int, Item*, int)), this, SLOT(onChildIsAboutToBeMoved(Item*, int, int, Item*, int)));
|
||||
connect(root, SIGNAL(childMoved()), this, SLOT(onChildMoved()));
|
||||
}
|
||||
|
||||
Models::Roster::~Roster()
|
||||
@ -27,12 +34,10 @@ Models::Roster::~Roster()
|
||||
|
||||
void Models::Roster::addAccount(const QMap<QString, QVariant>& data)
|
||||
{
|
||||
Account* acc = new Account(data, root);
|
||||
beginInsertRows(QModelIndex(), root->childCount(), root->childCount());
|
||||
Account* acc = new Account(data);
|
||||
root->appendChild(acc);
|
||||
accounts.insert(std::make_pair(acc->getName(), acc));
|
||||
accountsModel->addAccount(acc);
|
||||
endInsertRows();
|
||||
}
|
||||
|
||||
QVariant Models::Roster::data (const QModelIndex& index, int role) const
|
||||
@ -70,15 +75,12 @@ QVariant Models::Roster::data (const QModelIndex& index, int role) const
|
||||
break;
|
||||
case Item::contact:{
|
||||
Contact* contact = static_cast<Contact*>(item);
|
||||
int state = contact->getState();
|
||||
switch (state) {
|
||||
case 0:
|
||||
result = QIcon::fromTheme("im-user-offline");
|
||||
break;
|
||||
case 1:
|
||||
result = QIcon::fromTheme("im-user-online");
|
||||
break;
|
||||
}
|
||||
result = QIcon::fromTheme(Shared::AvailabilityIcons[contact->getState()]);
|
||||
}
|
||||
break;
|
||||
case Item::presence:{
|
||||
Presence* presence = static_cast<Presence*>(item);
|
||||
result = QIcon::fromTheme(Shared::AvailabilityIcons[presence->getAvailability()]);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@ -237,11 +239,9 @@ void Models::Roster::addGroup(const QString& account, const QString& name)
|
||||
std::map<QString, Account*>::iterator itr = accounts.find(account);
|
||||
if (itr != accounts.end()) {
|
||||
Account* acc = itr->second;
|
||||
Item* group = new Item(Item::group, {{"name", name}}, acc);
|
||||
beginInsertRows(createIndex(acc->row(), 0, acc), acc->childCount(), acc->childCount());
|
||||
Item* group = new Item(Item::group, {{"name", name}});
|
||||
acc->appendChild(group);
|
||||
groups.insert(std::make_pair(id, group));
|
||||
endInsertRows();
|
||||
} else {
|
||||
qDebug() << "An attempt to add group " << name << " to non existing account " << account << ", skipping";
|
||||
}
|
||||
@ -300,24 +300,16 @@ void Models::Roster::addContact(const QString& account, const QString& jid, cons
|
||||
if (ca->getJid() == jid) {
|
||||
qDebug() << "An attempt to add a already existing contact " << name << " to the group " << group << ", contact will be moved from ungrouped contacts of " << account;
|
||||
|
||||
beginMoveRows(createIndex(acc->row(), 0, acc), i, i, createIndex(parent->row(), 0, parent), parent->childCount());
|
||||
contact = ca;
|
||||
acc->removeChild(i);
|
||||
ca->setParent(parent);
|
||||
parent->appendChild(ca);
|
||||
endMoveRows();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
contact = new Contact({{"name", name}, {"jid", jid}, {"state", 0}}, parent);
|
||||
beginInsertRows(createIndex(parent->row(), 0, parent), parent->childCount(), parent->childCount());
|
||||
contact = new Contact({{"name", name}, {"jid", jid}, {"state", 0}});
|
||||
parent->appendChild(contact);
|
||||
contacts.insert(std::make_pair(id, contact));
|
||||
endInsertRows();
|
||||
|
||||
}
|
||||
|
||||
void Models::Roster::removeGroup(const QString& account, const QString& name)
|
||||
@ -332,9 +324,7 @@ void Models::Roster::removeGroup(const QString& account, const QString& name)
|
||||
Item* parent = item->parentItem();
|
||||
int row = item->row();
|
||||
|
||||
beginRemoveRows(createIndex(parent->row(), 0, parent), row, row);
|
||||
parent->removeChild(row);
|
||||
endRemoveRows();
|
||||
|
||||
std::deque<Contact*> toInsert;
|
||||
for (int i = 0; item->childCount() > 0; ++i) {
|
||||
@ -360,13 +350,10 @@ void Models::Roster::removeGroup(const QString& account, const QString& name)
|
||||
|
||||
if (toInsert.size() > 0) {
|
||||
Account* acc = accounts.find("account")->second;
|
||||
beginInsertRows(createIndex(acc->row(), 0, acc), acc->childCount(), acc->childCount() + toInsert.size() - 1);
|
||||
for (int i = 0; i < toInsert.size(); ++i) {
|
||||
Contact* cont = toInsert[i];
|
||||
cont->setParent(acc);
|
||||
acc->appendChild(cont);
|
||||
acc->appendChild(cont); //TODO optimisation
|
||||
}
|
||||
endInsertRows();
|
||||
}
|
||||
|
||||
delete item;
|
||||
@ -396,10 +383,8 @@ void Models::Roster::removeContact(const QString& account, const QString& jid)
|
||||
if (parent->type == Item::group && parent->childCount() == 1) {
|
||||
toRemove.insert(parent->getName());
|
||||
}
|
||||
int row = contact->row();
|
||||
beginRemoveRows(createIndex(parent->row(), 0, parent), row, row);
|
||||
parent->removeChild(row);
|
||||
endRemoveRows();
|
||||
|
||||
parent->removeChild(contact->row());
|
||||
delete contact;
|
||||
}
|
||||
|
||||
@ -435,13 +420,84 @@ void Models::Roster::removeContact(const QString& account, const QString& jid, c
|
||||
return;
|
||||
}
|
||||
|
||||
int row = cont->row();
|
||||
beginRemoveRows(createIndex(gr->row(), 0, gr), row, row);
|
||||
gr->removeChild(row);
|
||||
endRemoveRows();
|
||||
gr->removeChild(cont->row());
|
||||
delete cont;
|
||||
|
||||
if (gr->childCount() == 0) {
|
||||
removeGroup(account, group);
|
||||
}
|
||||
}
|
||||
|
||||
void Models::Roster::onChildChanged(Models::Item* item, int row, int col)
|
||||
{
|
||||
QModelIndex index = createIndex(row, col, item);
|
||||
emit dataChanged(index, index);
|
||||
}
|
||||
|
||||
void Models::Roster::onChildIsAboutToBeInserted(Models::Item* parent, int first, int last)
|
||||
{
|
||||
int row = 0;
|
||||
if (parent != root) {
|
||||
row = parent->row();
|
||||
beginInsertRows(createIndex(row, 0, parent), first, last);
|
||||
} else {
|
||||
beginInsertRows(QModelIndex(), first, last);
|
||||
}
|
||||
}
|
||||
|
||||
void Models::Roster::onChildIsAboutToBeMoved(Models::Item* source, int first, int last, Models::Item* destination, int newIndex)
|
||||
{
|
||||
int oldRow = 0;
|
||||
if (source != root) {
|
||||
oldRow = source->row();
|
||||
}
|
||||
int newRow = 0;
|
||||
if (destination != root) {
|
||||
newRow = destination->row();
|
||||
}
|
||||
beginMoveRows(createIndex(oldRow, 0, source), first, last, createIndex(newRow, 0, destination), newIndex);
|
||||
}
|
||||
|
||||
void Models::Roster::onChildIsAboutToBeRemoved(Models::Item* parent, int first, int last)
|
||||
{
|
||||
int row = 0;
|
||||
if (parent != root) {
|
||||
row = parent->row();
|
||||
}
|
||||
beginRemoveRows(createIndex(row, 0, parent), first, last);
|
||||
}
|
||||
|
||||
void Models::Roster::onChildInserted()
|
||||
{
|
||||
endInsertRows();
|
||||
}
|
||||
|
||||
void Models::Roster::onChildMoved()
|
||||
{
|
||||
endMoveRows();
|
||||
}
|
||||
|
||||
void Models::Roster::onChildRemoved()
|
||||
{
|
||||
endRemoveRows();
|
||||
}
|
||||
|
||||
void Models::Roster::addPresence(const QString& account, const QString& jid, const QString& name, const QMap<QString, QVariant>& data)
|
||||
{
|
||||
ElId contactId(account, jid);
|
||||
std::multimap<ElId, Contact*>::iterator cBeg = contacts.lower_bound(contactId);
|
||||
std::multimap<ElId, Contact*>::iterator cEnd = contacts.upper_bound(contactId);
|
||||
for (;cBeg != cEnd; ++cBeg) {
|
||||
cBeg->second->addPresence(name, data);
|
||||
}
|
||||
}
|
||||
|
||||
void Models::Roster::removePresence(const QString& account, const QString& jid, const QString& name)
|
||||
{
|
||||
ElId contactId(account, jid);
|
||||
std::multimap<ElId, Contact*>::iterator cBeg = contacts.lower_bound(contactId);
|
||||
std::multimap<ElId, Contact*>::iterator cEnd = contacts.upper_bound(contactId);
|
||||
for (;cBeg != cEnd; ++cBeg) {
|
||||
cBeg->second->removePresence(name);
|
||||
}
|
||||
}
|
||||
|
@ -30,6 +30,8 @@ public:
|
||||
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 QString& name);
|
||||
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);
|
||||
|
||||
QVariant data ( const QModelIndex& index, int role ) const override;
|
||||
Qt::ItemFlags flags(const QModelIndex &index) const override;
|
||||
@ -49,6 +51,13 @@ private:
|
||||
|
||||
private slots:
|
||||
void onAccountDataChanged(const QModelIndex& tl, const QModelIndex& br, const QVector<int>& roles);
|
||||
void onChildChanged(Item* item, int row, int col);
|
||||
void onChildIsAboutToBeInserted(Item* parent, int first, int last);
|
||||
void onChildInserted();
|
||||
void onChildIsAboutToBeRemoved(Item* parent, int first, int last);
|
||||
void onChildRemoved();
|
||||
void onChildIsAboutToBeMoved(Item* source, int first, int last, Item* destination, int newIndex);
|
||||
void onChildMoved();
|
||||
|
||||
private:
|
||||
class ElId {
|
||||
|
@ -116,5 +116,15 @@ void Squawk::removeContact(const QString& account, const QString& jid, const QSt
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
@ -38,6 +38,8 @@ public slots:
|
||||
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 QString& name);
|
||||
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);
|
||||
|
||||
private:
|
||||
QScopedPointer<Ui::Squawk> m_ui;
|
||||
|
Loading…
Reference in New Issue
Block a user