From a5d24c0e3ae1799f6e58f2f523719fe009d8fdd5 Mon Sep 17 00:00:00 2001 From: blue Date: Sun, 7 Apr 2019 23:14:15 +0300 Subject: [PATCH] Bugfixes, availabilities statuses support --- core/account.cpp | 96 +++++++++++++++++++++++++++++++++++++----- core/account.h | 19 ++++++--- core/squawk.cpp | 38 ++++++++++++++--- core/squawk.h | 13 ++++-- global.h | 27 +++++++++++- main.cpp | 10 +++-- ui/models/account.cpp | 71 ++++++++++++++++++++++++++++--- ui/models/account.h | 15 +++++-- ui/models/accounts.cpp | 2 +- ui/models/contact.cpp | 83 ++++++++++++++++++++++++++++-------- ui/models/contact.h | 16 ++++--- ui/models/item.cpp | 2 +- ui/models/item.h | 11 ----- ui/models/roster.cpp | 39 +++++++---------- ui/models/roster.h | 4 +- ui/squawk.cpp | 32 ++++++++++---- ui/squawk.h | 7 ++- ui/squawk.ui | 20 +-------- 18 files changed, 374 insertions(+), 131 deletions(-) diff --git a/core/account.cpp b/core/account.cpp index 26dae31..86bbc6f 100644 --- a/core/account.cpp +++ b/core/account.cpp @@ -7,13 +7,16 @@ using namespace Core; Account::Account(const QString& p_login, const QString& p_server, const QString& p_password, const QString& p_name, QObject* parent): QObject(parent), name(p_name), - login(p_login), - server(p_server), - password(p_password), client(), + config(), + presence(), state(Shared::disconnected), groups() { + config.setUser(p_login); + config.setDomain(p_server); + config.setPassword(p_password); + 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&))); @@ -39,7 +42,7 @@ Shared::ConnectionState Core::Account::getState() const void Core::Account::connect() { if (state == Shared::disconnected) { - client.connectToServer(login + "@" + server, password); + client.connectToServer(config, presence); state = Shared::connecting; emit connectionStateChanged(state); } else { @@ -83,17 +86,17 @@ QString Core::Account::getName() const QString Core::Account::getLogin() const { - return login; + return config.user(); } QString Core::Account::getPassword() const { - return password; + return config.password(); } QString Core::Account::getServer() const { - return server; + return config.domain(); } void Core::Account::onRosterReceived() @@ -120,8 +123,16 @@ void Core::Account::onRosterItemChanged(const QString& bareJid) QStringList res = rm.getResources(bareJid); + unsigned int state = re.subscriptionType(); + if (state == QXmppRosterIq::Item::NotSet) { + state = Shared::unknown; + } + QMap cData({ + {"name", re.name()}, + {"state", state} + }); - emit changeContact(bareJid, re.name()); + emit changeContact(bareJid, cData); for (std::map>::iterator itr = groups.begin(), end = groups.end(); itr != end; ++itr) { std::set& contacts = itr->second; @@ -153,7 +164,7 @@ void Core::Account::onRosterItemChanged(const QString& bareJid) emit addGroup(groupName); } cItr->second.insert(bareJid); - emit addContact(bareJid, re.name(), groupName); + emit addContact(bareJid, groupName, cData); } for (QSet::iterator itr = removeGroups.begin(), end = removeGroups.end(); itr != end; ++itr) { @@ -191,6 +202,14 @@ void Core::Account::addedAccount(const QString& jid) QXmppRosterManager& rm = client.rosterManager(); QXmppRosterIq::Item re = rm.getRosterEntry(jid); QSet gr = re.groups(); + unsigned int state = re.subscriptionType(); + if (state == QXmppRosterIq::Item::NotSet) { + state = Shared::unknown; + } + QMap cData({ + {"name", re.name()}, + {"state", state} + }); int grCount = 0; for (QSet::const_iterator itr = gr.begin(), end = gr.end(); itr != end; ++itr) { const QString& groupName = *itr; @@ -200,12 +219,12 @@ void Core::Account::addedAccount(const QString& jid) emit addGroup(groupName); } gItr->second.insert(jid); - emit addContact(jid, re.name(), groupName); + emit addContact(jid, groupName, cData); grCount++; } if (grCount == 0) { - emit addContact(jid, re.name(), ""); + emit addContact(jid, "", cData); } } @@ -216,6 +235,16 @@ void Core::Account::onPresenceReceived(const QXmppPresence& presence) QString jid = comps.front(); QString resource = comps.back(); + QString myJid = getLogin() + "@" + getServer(); + + if (jid == myJid) { + if (resource == getResource()) { + emit availabilityChanged(presence.availableStatusType()); + } else { + qDebug() << "Received a presence for another resource of my " << name << " account, skipping"; + } + } + switch (presence.type()) { case QXmppPresence::Error: qDebug() << "An error reported by presence from " << id; @@ -256,3 +285,48 @@ void Core::Account::onRosterPresenceChanged(const QString& bareJid, const QStrin const QXmppPresence& presence = client.rosterManager().getPresence(bareJid, resource); } +void Core::Account::setLogin(const QString& p_login) +{ + config.setUser(p_login); +} + +void Core::Account::setName(const QString& p_name) +{ + name = p_name; +} + +void Core::Account::setPassword(const QString& p_password) +{ + config.setPassword(p_password); +} + +void Core::Account::setServer(const QString& p_server) +{ + config.setDomain(p_server); +} + +Shared::Availability Core::Account::getAvailability() const +{ + QXmppPresence::AvailableStatusType pres = presence.availableStatusType(); + return static_cast(pres); //TODO that's a shame! gotta do something about it +} + +void Core::Account::setAvailability(Shared::Availability avail) +{ + QXmppPresence::AvailableStatusType pres = static_cast(avail); + + presence.setAvailableStatusType(pres); + if (state != Shared::disconnected) { //TODO not sure how to do here - changing state may cause connection or disconnection + client.setClientPresence(presence); + } +} + +QString Core::Account::getResource() const +{ + return config.resource(); +} + +void Core::Account::setResource(const QString& p_resource) +{ + config.setResource(p_resource); +} diff --git a/core/account.h b/core/account.h index 1e09957..9f3f10e 100644 --- a/core/account.h +++ b/core/account.h @@ -26,24 +26,33 @@ public: QString getLogin() const; QString getServer() const; QString getPassword() const; + QString getResource() const; + Shared::Availability getAvailability() const; + + void setName(const QString& p_name); + void setLogin(const QString& p_login); + void setServer(const QString& p_server); + void setPassword(const QString& p_password); + void setResource(const QString& p_resource); + void setAvailability(Shared::Availability avail); signals: void connectionStateChanged(int); + void availabilityChanged(int); void addGroup(const QString& name); void removeGroup(const QString& name); - void addContact(const QString& jid, const QString& name, const QString& group); + void addContact(const QString& jid, const QString& group, const QMap& data); void removeContact(const QString& jid); void removeContact(const QString& jid, const QString& group); - void changeContact(const QString& jid, const QString& name); + void changeContact(const QString& jid, const QMap& data); void addPresence(const QString& jid, const QString& name, const QMap& data); void removePresence(const QString& jid, const QString& name); private: QString name; - QString login; - QString server; - QString password; QXmppClient client; + QXmppConfiguration config; + QXmppPresence presence; Shared::ConnectionState state; std::map> groups; diff --git a/core/squawk.cpp b/core/squawk.cpp index 67a4277..f69b172 100644 --- a/core/squawk.cpp +++ b/core/squawk.cpp @@ -74,12 +74,15 @@ void Core::Squawk::addAccount(const QString& login, const QString& server, const amap.insert(std::make_pair(name, acc)); connect(acc, SIGNAL(connectionStateChanged(int)), this, SLOT(onAccountConnectionStateChanged(int))); - connect(acc, SIGNAL(addContact(const QString&, const QString&, const QString&)), this, SLOT(onAccountAddContact(const QString&, const QString&, const QString&))); + connect(acc, SIGNAL(availabilityChanged(int)), this, SLOT(onAccountAvailabilityChanged(int))); + connect(acc, SIGNAL(addContact(const QString&, const QString&, const QMap&)), + this, SLOT(onAccountAddContact(const QString&, const QString&, const QMap&))); connect(acc, SIGNAL(addGroup(const QString&)), this, SLOT(onAccountAddGroup(const QString&))); connect(acc, SIGNAL(removeGroup(const QString&)), this, SLOT(onAccountRemoveGroup(const QString&))); 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(changeContact(const QString&, const QMap&)), + this, SLOT(onAccountChangeContact(const QString&, const QMap&))); connect(acc, SIGNAL(addPresence(const QString&, const QString&, const QMap&)), this, SLOT(onAccountAddPresence(const QString&, const QString&, const QMap&))); connect(acc, SIGNAL(removePresence(const QString&, const QString&)), this, SLOT(onAccountRemovePresence(const QString&, const QString&))); @@ -89,11 +92,26 @@ void Core::Squawk::addAccount(const QString& login, const QString& server, const {"server", server}, {"name", name}, {"password", password}, - {"state", Shared::disconnected} + {"state", Shared::disconnected}, + {"offline", Shared::offline} }; emit newAccount(map); } +void Core::Squawk::changeState(int p_state) +{ + Shared::Availability avail; + if (p_state < Shared::availabilityLowest && p_state > Shared::availabilityHighest) { + qDebug("An attempt to set invalid availability to Squawk core, skipping"); + } + avail = static_cast(p_state); + state = avail; + + for (std::deque::iterator itr = accounts.begin(), end = accounts.end(); itr != end; ++itr) { + (*itr)->setAvailability(state); + } +} + void Core::Squawk::connectAccount(const QString& account) { AccountsMap::const_iterator itr = amap.find(account); @@ -121,10 +139,10 @@ void Core::Squawk::onAccountConnectionStateChanged(int state) emit accountConnectionStateChanged(acc->getName(), state); } -void Core::Squawk::onAccountAddContact(const QString& jid, const QString& name, const QString& group) +void Core::Squawk::onAccountAddContact(const QString& jid, const QString& group, const QMap& data) { Account* acc = static_cast(sender()); - emit addContact(acc->getName(), jid, name, group); + emit addContact(acc->getName(), jid, group, data); } void Core::Squawk::onAccountAddGroup(const QString& name) @@ -139,10 +157,10 @@ void Core::Squawk::onAccountRemoveGroup(const QString& name) emit removeGroup(acc->getName(), name); } -void Core::Squawk::onAccountChangeContact(const QString& jid, const QString& name) +void Core::Squawk::onAccountChangeContact(const QString& jid, const QMap& data) { Account* acc = static_cast(sender()); - emit changeContact(acc->getName(), jid, name); + emit changeContact(acc->getName(), jid, data); } void Core::Squawk::onAccountRemoveContact(const QString& jid) @@ -168,3 +186,9 @@ void Core::Squawk::onAccountRemovePresence(const QString& jid, const QString& na Account* acc = static_cast(sender()); emit removePresence(acc->getName(), jid, name); } + +void Core::Squawk::onAccountAvailabilityChanged(int state) +{ + Account* acc = static_cast(sender()); + emit accountAvailabilityChanged(acc->getName(), state); +} diff --git a/core/squawk.h b/core/squawk.h index 594e711..41f7d0e 100644 --- a/core/squawk.h +++ b/core/squawk.h @@ -25,14 +25,16 @@ signals: void quit(); void newAccount(const QMap&); void accountConnectionStateChanged(const QString&, int); + void accountAvailabilityChanged(const QString&, int); 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& name, const QString& group); + void addContact(const QString& account, const QString& jid, const QString& group, const QMap& data); 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 changeContact(const QString& account, const QString& jid, const QMap& data); void addPresence(const QString& account, const QString& jid, const QString& name, const QMap& data); void removePresence(const QString& account, const QString& jid, const QString& name); + void stateChanged(int state); public slots: void start(); @@ -40,6 +42,7 @@ public slots: void newAccountRequest(const QMap& map); void connectAccount(const QString& account); void disconnectAccount(const QString& account); + void changeState(int state); private: typedef std::deque Accounts; @@ -47,18 +50,20 @@ private: Accounts accounts; AccountsMap amap; + Shared::Availability state; private: void addAccount(const QString& login, const QString& server, const QString& password, const QString& name); private slots: void onAccountConnectionStateChanged(int state); + void onAccountAvailabilityChanged(int state); void onAccountAddGroup(const QString& name); void onAccountRemoveGroup(const QString& name); - void onAccountAddContact(const QString& jid, const QString& name, const QString& group); + void onAccountAddContact(const QString& jid, const QString& group, const QMap& data); void onAccountRemoveContact(const QString& jid); void onAccountRemoveContact(const QString& jid, const QString& group); - void onAccountChangeContact(const QString& jid, const QString& name); + void onAccountChangeContact(const QString& jid, const QMap& data); void onAccountAddPresence(const QString& jid, const QString& name, const QMap& data); void onAccountRemovePresence(const QString& jid, const QString& name); }; diff --git a/global.h b/global.h index c08c3d4..38fb83d 100644 --- a/global.h +++ b/global.h @@ -22,11 +22,34 @@ enum Availability { offline }; +enum SubscriptionState { + none, + from, + to, + both, + unknown +}; + static const Availability availabilityHighest = offline; static const Availability availabilityLowest = online; -static const std::deque ConnectionStateNames = {"Disconnected", "Connecting", "Connected", "Error"}; -static const std::deque ConnectionStateThemeIcons = {"network-disconnect", "view-refresh", "network-connect", "state-error"}; +static const SubscriptionState subscriptionStateHighest = unknown; +static const SubscriptionState subscriptionStateLowest = none; + +static const std::deque connectionStateNames = {"Disconnected", "Connecting", "Connected", "Error"}; +static const std::deque connectionStateThemeIcons = {"network-disconnect", "view-refresh", "network-connect", "state-error"}; + +static const std::deque availabilityThemeIcons = { + "im-user-online", + "im-user-away", + "im-user-away", + "im-user-busy", + "im-user-online", + "im-user-offline" +}; +static const std::deque availabilityNames = {"Online", "Away", "Absent", "Busy", "Chatty", "Offline"}; + +static const std::deque subscriptionStateThemeIcons = {"edit-none", "arrow-down-double", "arrow-up-double", "dialog-ok", "question"}; }; diff --git a/main.cpp b/main.cpp index c135168..110d250 100644 --- a/main.cpp +++ b/main.cpp @@ -31,19 +31,23 @@ int main(int argc, char *argv[]) QObject::connect(&w, SIGNAL(newAccountRequest(const QMap&)), squawk, SLOT(newAccountRequest(const QMap&))); QObject::connect(&w, SIGNAL(connectAccount(const QString&)), squawk, SLOT(connectAccount(const QString&))); QObject::connect(&w, SIGNAL(disconnectAccount(const QString&)), squawk, SLOT(disconnectAccount(const QString&))); + QObject::connect(&w, SIGNAL(changeState(int)), squawk, SLOT(changeState(int))); QObject::connect(squawk, SIGNAL(newAccount(const QMap&)), &w, SLOT(newAccount(const QMap&))); + QObject::connect(squawk, SIGNAL(accountAvailabilityChanged(const QString&, int)), &w, SLOT(accountAvailabilityChanged(const QString&, int))); QObject::connect(squawk, SIGNAL(accountConnectionStateChanged(const QString&, int)), &w, SLOT(accountConnectionStateChanged(const QString&, int))); - QObject::connect(squawk, SIGNAL(addContact(const QString&, const QString&, const QString&, const QString&)), - &w, SLOT(addContact(const QString&, const QString&, const QString&, const QString&))); + QObject::connect(squawk, SIGNAL(addContact(const QString&, const QString&, const QString&, const QMap&)), + &w, SLOT(addContact(const QString&, const QString&, const QString&, const QMap&))); QObject::connect(squawk, SIGNAL(addGroup(const QString&, const QString&)), &w, SLOT(addGroup(const QString&, const QString&))); QObject::connect(squawk, SIGNAL(removeGroup(const QString&, const QString&)), &w, SLOT(removeGroup(const QString&, const QString&))); 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(changeContact(const QString&, const QString&, const QMap&)), + &w, SLOT(changeContact(const QString&, const QString&, const QMap&))); QObject::connect(squawk, SIGNAL(addPresence(const QString&, const QString&, const QString&, const QMap&)), &w, SLOT(addPresence(const QString&, const QString&, const QString&, const QMap&))); QObject::connect(squawk, SIGNAL(removePresence(const QString&, const QString&, const QString&)), &w, SLOT(removePresence(const QString&, const QString&, const QString&))); + QObject::connect(squawk, SIGNAL(stateChanged(int)), &w, SLOT(stateChanged(int))); coreThread->start(); diff --git a/ui/models/account.cpp b/ui/models/account.cpp index a0d4ad0..5a2d295 100644 --- a/ui/models/account.cpp +++ b/ui/models/account.cpp @@ -1,19 +1,29 @@ #include "account.h" +#include Models::Account::Account(const QMap& data, Models::Item* parentItem): Item(account, data, parentItem), login(data.value("login").toString()), password(data.value("password").toString()), server(data.value("server").toString()), - state(data.value("state").toInt()) + state(Shared::disconnected), + availability(Shared::offline) { + QMap::const_iterator sItr = data.find("state"); + if (sItr != data.end()) { + setState(sItr.value().toUInt()); + } + QMap::const_iterator aItr = data.find("availability"); + if (aItr != data.end()) { + setAvailability(aItr.value().toUInt()); + } } Models::Account::~Account() { } -void Models::Account::setState(int p_state) +void Models::Account::setState(Shared::ConnectionState p_state) { if (state != p_state) { state = p_state; @@ -21,6 +31,51 @@ void Models::Account::setState(int p_state) } } +void Models::Account::setAvailability(unsigned int p_state) +{ + if (p_state <= Shared::availabilityHighest) { + Shared::Availability state = static_cast(p_state); + setAvailability(state); + } else { + qDebug() << "An attempt to set invalid availability " << p_state << " to the account " << name; + } +} + +void Models::Account::setState(unsigned int p_state) +{ + if (p_state <= Shared::subscriptionStateHighest) { + Shared::ConnectionState state = static_cast(p_state); + setState(state); + } else { + qDebug() << "An attempt to set invalid subscription state " << p_state << " to the account " << name; + } +} + +Shared::Availability Models::Account::getAvailability() const +{ + return availability; +} + +void Models::Account::setAvailability(Shared::Availability p_avail) +{ + if (availability != p_avail) { + availability = p_avail; + changed(5); + } +} + +QIcon Models::Account::getStatusIcon() const +{ + if (state == Shared::connected) { + return QIcon::fromTheme(Shared::availabilityThemeIcons[availability]); + } else if (state == Shared::disconnected) { + return QIcon::fromTheme(Shared::availabilityThemeIcons[Shared::offline]); + } else { + return QIcon::fromTheme(Shared::connectionStateThemeIcons[state]); + } +} + + QString Models::Account::getLogin() const { return login; @@ -36,7 +91,7 @@ QString Models::Account::getServer() const return server; } -int Models::Account::getState() const +Shared::ConnectionState Models::Account::getState() const { return state; } @@ -73,11 +128,13 @@ QVariant Models::Account::data(int column) const case 1: return server; case 2: - return Shared::ConnectionStateNames[state]; + return Shared::connectionStateNames[state]; case 3: return login; case 4: return password; + case 5: + return Shared::availabilityNames[availability]; default: return QVariant(); } @@ -85,7 +142,7 @@ QVariant Models::Account::data(int column) const int Models::Account::columnCount() const { - return 5; + return 6; } void Models::Account::update(const QString& field, const QVariant& value) @@ -99,6 +156,8 @@ void Models::Account::update(const QString& field, const QVariant& value) } else if (field == "password") { setPassword(value.toString()); } else if (field == "state") { - setState(value.toInt()); + setState(value.toUInt()); + } else if (field == "availability") { + setAvailability(value.toUInt()); } } diff --git a/ui/models/account.h b/ui/models/account.h index ce7d5e6..b6e8b07 100644 --- a/ui/models/account.h +++ b/ui/models/account.h @@ -4,6 +4,7 @@ #include "../../global.h" #include "item.h" #include +#include namespace Models { class Account : public Item { @@ -11,8 +12,9 @@ namespace Models { explicit Account(const QMap &data, Item *parentItem = 0); ~Account(); - void setState(int p_state); - int getState() const; + void setState(unsigned int p_state); + void setState(Shared::ConnectionState p_state); + Shared::ConnectionState getState() const; void setLogin(const QString& p_login); QString getLogin() const; @@ -23,6 +25,12 @@ namespace Models { void setPassword(const QString& p_password); QString getPassword() const; + void setAvailability(Shared::Availability p_avail); + void setAvailability(unsigned int p_avail); + Shared::Availability getAvailability() const; + + QIcon getStatusIcon() const; + QVariant data(int column) const override; int columnCount() const override; @@ -32,7 +40,8 @@ namespace Models { QString login; QString password; QString server; - int state; + Shared::ConnectionState state; + Shared::Availability availability; }; } diff --git a/ui/models/accounts.cpp b/ui/models/accounts.cpp index 80b8e48..4a3cf51 100644 --- a/ui/models/accounts.cpp +++ b/ui/models/accounts.cpp @@ -30,7 +30,7 @@ QVariant Models::Accounts::data (const QModelIndex& index, int role) const break; case Qt::DecorationRole: if (index.column() == 2) { - answer = QIcon::fromTheme(Shared::ConnectionStateThemeIcons[accs[index.row()]->getState()]); + answer = QIcon::fromTheme(Shared::connectionStateThemeIcons[accs[index.row()]->getState()]); } break; default: diff --git a/ui/models/contact.cpp b/ui/models/contact.cpp index f4eef9b..fb27780 100644 --- a/ui/models/contact.cpp +++ b/ui/models/contact.cpp @@ -1,12 +1,17 @@ #include "contact.h" #include -Models::Contact::Contact(const QMap& data, Models::Item* parentItem): +Models::Contact::Contact(const QString& p_jid ,const QMap &data, Item *parentItem): Item(Item::contact, data, parentItem), - jid(data.value("jid").toString()), - state(Shared::offline), + jid(p_jid), + availability(Shared::offline), + state(Shared::none), presences() { + QMap::const_iterator itr = data.find("state"); + if (itr != data.end()) { + setState(itr.value().toUInt()); + } } Models::Contact::~Contact() @@ -26,22 +31,42 @@ void Models::Contact::setJid(const QString p_jid) } } -Shared::Availability Models::Contact::getState() const +void Models::Contact::setAvailability(unsigned int p_state) { - return state; + if (p_state <= Shared::availabilityHighest) { + Shared::Availability state = static_cast(p_state); + setAvailability(state); + } else { + qDebug() << "An attempt to set invalid availability " << p_state << " to the contact " << jid; + } } -void Models::Contact::setState(Shared::Availability p_state) +void Models::Contact::setState(unsigned int p_state) { - if (state != p_state) { - state = p_state; - changed(2); + if (p_state <= Shared::subscriptionStateHighest) { + Shared::SubscriptionState state = static_cast(p_state); + setState(state); + } else { + qDebug() << "An attempt to set invalid subscription state " << p_state << " to the contact " << jid; + } +} + +Shared::Availability Models::Contact::getAvailability() const +{ + return availability; +} + +void Models::Contact::setAvailability(Shared::Availability p_state) +{ + if (availability != p_state) { + availability = p_state; + changed(3); } } int Models::Contact::columnCount() const { - return 3; + return 4; } QVariant Models::Contact::data(int column) const @@ -56,6 +81,8 @@ QVariant Models::Contact::data(int column) const case 1: return jid; case 2: + return availability; + case 3: return state; default: return QVariant(); @@ -68,14 +95,10 @@ void Models::Contact::update(const QString& field, const QVariant& value) setName(value.toString()); } else if (field == "jid") { setJid(value.toString()); + } else if (field == "availability") { + setAvailability(value.toUInt()); } else if (field == "state") { - unsigned int iState = value.toUInt(); - if (iState <= Shared::availabilityHighest) { - Shared::Availability state = static_cast(iState); - setState(state); - } else { - qDebug("An attempt to set wrong state to the contact"); - } + setState(value.toUInt()); } } @@ -123,7 +146,9 @@ void Models::Contact::refresh() } if (presence != 0) { - setState(presence->getAvailability()); + setAvailability(presence->getAvailability()); + } else { + setAvailability(Shared::offline); } } @@ -144,3 +169,25 @@ void Models::Contact::changed(int col) Item::changed(col); refresh(); } + +Shared::SubscriptionState Models::Contact::getState() const +{ + return state; +} + +void Models::Contact::setState(Shared::SubscriptionState p_state) +{ + if (state != p_state) { + state = p_state; + changed(2); + } +} + +QIcon Models::Contact::getStatusIcon() const +{ + if (state == Shared::both) { + return QIcon::fromTheme(Shared::availabilityThemeIcons[availability]); + } else { + return QIcon::fromTheme(Shared::subscriptionStateThemeIcons[state]); + } +} diff --git a/ui/models/contact.h b/ui/models/contact.h index ffe6380..4ce42b1 100644 --- a/ui/models/contact.h +++ b/ui/models/contact.h @@ -5,6 +5,7 @@ #include "presence.h" #include "../../global.h" #include +#include namespace Models { @@ -12,12 +13,13 @@ class Contact : public Item { Q_OBJECT public: - Contact(const QMap &data, Item *parentItem = 0); + Contact(const QString& p_jid ,const QMap &data, Item *parentItem = 0); ~Contact(); QString getJid() const; - - Shared::Availability getState() const; + Shared::Availability getAvailability() const; + Shared::SubscriptionState getState() const; + QIcon getStatusIcon() const; int columnCount() const override; QVariant data(int column) const override; @@ -35,12 +37,16 @@ protected: void _removeChild(int index) override; protected: - void setState(Shared::Availability p_state); + void setAvailability(Shared::Availability p_state); + void setAvailability(unsigned int p_state); + void setState(Shared::SubscriptionState p_state); + void setState(unsigned int p_state); void setJid(const QString p_jid); private: QString jid; - Shared::Availability state; + Shared::Availability availability; + Shared::SubscriptionState state; QMap presences; }; diff --git a/ui/models/item.cpp b/ui/models/item.cpp index da7eaf5..11b038c 100644 --- a/ui/models/item.cpp +++ b/ui/models/item.cpp @@ -108,7 +108,7 @@ QVariant Models::Item::data(int column) const void Models::Item::removeChild(int index) { emit childIsAboutToBeRemoved(this, index, index); - removeChild(index); + _removeChild(index); emit childRemoved(); } diff --git a/ui/models/item.h b/ui/models/item.h index 95f6bec..06944c9 100644 --- a/ui/models/item.h +++ b/ui/models/item.h @@ -62,15 +62,4 @@ class Item : public QObject{ } -namespace Shared { - static const std::deque AvailabilityIcons = { - "im-user-online", - "im-user-away", - "im-user-away", - "im-user-busy", - "im-user-online", - "im-user-offline" - }; -} - #endif // MODELS_ITEM_H diff --git a/ui/models/roster.cpp b/ui/models/roster.cpp index 21b4b3e..e18de87 100644 --- a/ui/models/roster.cpp +++ b/ui/models/roster.cpp @@ -59,28 +59,17 @@ QVariant Models::Roster::data (const QModelIndex& index, int role) const switch (item->type) { case Item::account:{ Account* acc = static_cast(item); - int state = acc->getState(); - switch (state) { - case Shared::disconnected: - result = QIcon::fromTheme("im-user-offline"); - break; - case Shared::connecting: - result = QIcon::fromTheme(Shared::ConnectionStateThemeIcons[state]); - break; - case Shared::connected: - result = QIcon::fromTheme("im-user-online"); - break; - } + result = acc->getStatusIcon(); } break; case Item::contact:{ Contact* contact = static_cast(item); - result = QIcon::fromTheme(Shared::AvailabilityIcons[contact->getState()]); + result = contact->getStatusIcon(); } break; case Item::presence:{ Presence* presence = static_cast(item); - result = QIcon::fromTheme(Shared::AvailabilityIcons[presence->getAvailability()]); + result = QIcon::fromTheme(Shared::availabilityThemeIcons[presence->getAvailability()]); } break; default: @@ -247,7 +236,7 @@ void Models::Roster::addGroup(const QString& account, const QString& name) } } -void Models::Roster::addContact(const QString& account, const QString& jid, const QString& name, const QString& group) +void Models::Roster::addContact(const QString& account, const QString& jid, const QString& group, const QMap& data) { Item* parent; Account* acc; @@ -257,7 +246,7 @@ void Models::Roster::addContact(const QString& account, const QString& jid, cons { std::map::iterator itr = accounts.find(account); if (itr == accounts.end()) { - qDebug() << "An attempt to add a contact " << name << " to non existing account " << account << ", skipping"; + qDebug() << "An attempt to add a contact " << jid << " to non existing account " << account << ", skipping"; return; } acc = itr->second; @@ -268,7 +257,7 @@ void Models::Roster::addContact(const QString& account, const QString& jid, cons std::multimap::iterator eItr = contacts.upper_bound(id); while (itr != eItr) { if (itr->second->parentItem() == acc) { - qDebug() << "An attempt to add a contact " << name << " ungrouped to non the account " << account << " for the second time, skipping"; + qDebug() << "An attempt to add a contact " << jid << " ungrouped to non the account " << account << " for the second time, skipping"; return; } } @@ -276,7 +265,7 @@ void Models::Roster::addContact(const QString& account, const QString& jid, cons } else { std::map::iterator itr = groups.find({account, group}); if (itr == groups.end()) { - qDebug() << "An attempt to add a contact " << name << " to non existing group " << group << ", skipping"; + qDebug() << "An attempt to add a contact " << jid << " to non existing group " << group << ", skipping"; return; } @@ -287,7 +276,7 @@ void Models::Roster::addContact(const QString& account, const QString& jid, cons if (item->type == Item::contact) { Contact* ca = static_cast(item); if (ca->getJid() == jid) { - qDebug() << "An attempt to add a contact " << name << " to the group " << group << " for the second time, skipping"; + qDebug() << "An attempt to add a contact " << jid << " to the group " << group << " for the second time, skipping"; return; } } @@ -298,7 +287,7 @@ void Models::Roster::addContact(const QString& account, const QString& jid, cons if (item->type == Item::contact) { Contact* ca = static_cast(item); 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; + qDebug() << "An attempt to add a already existing contact " << jid << " to the group " << group << ", contact will be moved from ungrouped contacts of " << account; parent->appendChild(ca); return; @@ -307,7 +296,7 @@ void Models::Roster::addContact(const QString& account, const QString& jid, cons } } - contact = new Contact({{"name", name}, {"jid", jid}, {"state", 0}}); + contact = new Contact(jid, data); parent->appendChild(contact); contacts.insert(std::make_pair(id, contact)); } @@ -359,14 +348,16 @@ void Models::Roster::removeGroup(const QString& account, const QString& name) delete item; } -void Models::Roster::changeContact(const QString& account, const QString& jid, const QString& name) +void Models::Roster::changeContact(const QString& account, const QString& jid, const QMap& data) { ElId id(account, jid); std::multimap::iterator cBeg = contacts.lower_bound(id); std::multimap::iterator cEnd = contacts.upper_bound(id); for (; cBeg != cEnd; ++cBeg) { - cBeg->second->setName(name); + for (QMap::const_iterator itr = data.begin(), end = data.end(); itr != end; ++itr) { + cBeg->second->update(itr.key(), itr.value());; + } } } @@ -430,7 +421,7 @@ void Models::Roster::removeContact(const QString& account, const QString& jid, c void Models::Roster::onChildChanged(Models::Item* item, int row, int col) { - QModelIndex index = createIndex(row, col, item); + QModelIndex index = createIndex(row, 0, item); emit dataChanged(index, index); } diff --git a/ui/models/roster.h b/ui/models/roster.h index bdd93d4..669afcf 100644 --- a/ui/models/roster.h +++ b/ui/models/roster.h @@ -26,10 +26,10 @@ public: void updateAccount(const QString& account, const QString& field, const QVariant& value); 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& name, const QString& group); + void addContact(const QString& account, const QString& jid, const QString& group, const QMap& 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 QString& name); + void changeContact(const QString& account, const QString& jid, const QMap& data); void addPresence(const QString& account, const QString& jid, const QString& name, const QMap& data); void removePresence(const QString& account, const QString& jid, const QString& name); diff --git a/ui/squawk.cpp b/ui/squawk.cpp index 5629574..5164b2a 100644 --- a/ui/squawk.cpp +++ b/ui/squawk.cpp @@ -1,6 +1,7 @@ #include "squawk.h" #include "ui_squawk.h" #include +#include Squawk::Squawk(QWidget *parent) : QMainWindow(parent), @@ -11,6 +12,11 @@ Squawk::Squawk(QWidget *parent) : m_ui->setupUi(this); m_ui->roster->setModel(&rosterModel); + for (int i = 0; i < Shared::availabilityNames.size(); ++i) { + m_ui->comboBox->addItem(QIcon::fromTheme(Shared::availabilityThemeIcons[i]), Shared::availabilityNames[i]); + } + m_ui->comboBox->setCurrentIndex(Shared::offline); + connect(m_ui->actionAccounts, SIGNAL(triggered()), this, SLOT(onAccounts())); connect(m_ui->comboBox, SIGNAL(activated(int)), this, SLOT(onComboboxActivated(int))); //m_ui->mainToolBar->addWidget(m_ui->comboBox); @@ -58,9 +64,10 @@ void Squawk::newAccount(const QMap& account) void Squawk::onComboboxActivated(int index) { - if (index == 0) { + if (index != Shared::offline) { int size = rosterModel.accountsModel->rowCount(QModelIndex()); if (size > 0) { + emit changeState(index); for (int i = 0; i < size; ++i) { Models::Account* acc = rosterModel.accountsModel->getAccount(i); if (acc->getState() == Shared::disconnected) { @@ -68,9 +75,10 @@ void Squawk::onComboboxActivated(int index) } } } else { - m_ui->comboBox->setCurrentIndex(1); + m_ui->comboBox->setCurrentIndex(Shared::offline); } - } else if (index == 1) { + } else { + emit changeState(index); int size = rosterModel.accountsModel->rowCount(QModelIndex()); for (int i = 0; i != size; ++i) { Models::Account* acc = rosterModel.accountsModel->getAccount(i); @@ -86,9 +94,14 @@ void Squawk::accountConnectionStateChanged(const QString& account, int state) rosterModel.updateAccount(account, "state", state); } -void Squawk::addContact(const QString& account, const QString& jid, const QString& name, const QString& group) +void Squawk::accountAvailabilityChanged(const QString& account, int state) { - rosterModel.addContact(account, jid, name, group); + rosterModel.updateAccount(account, "availability", state); +} + +void Squawk::addContact(const QString& account, const QString& jid, const QString& group, const QMap& data) +{ + rosterModel.addContact(account, jid, group, data); } void Squawk::addGroup(const QString& account, const QString& name) @@ -101,9 +114,9 @@ void Squawk::removeGroup(const QString& account, const QString& name) rosterModel.removeGroup(account, name); } -void Squawk::changeContact(const QString& account, const QString& jid, const QString& name) +void Squawk::changeContact(const QString& account, const QString& jid, const QMap& data) { - rosterModel.changeContact(account, jid, name); + rosterModel.changeContact(account, jid, data); } void Squawk::removeContact(const QString& account, const QString& jid) @@ -126,5 +139,8 @@ void Squawk::removePresence(const QString& account, const QString& jid, const QS rosterModel.removePresence(account, jid, name); } - +void Squawk::stateChanged(int state) +{ + m_ui->comboBox->setCurrentIndex(state); +} diff --git a/ui/squawk.h b/ui/squawk.h index 2fb74a7..a80fb78 100644 --- a/ui/squawk.h +++ b/ui/squawk.h @@ -28,18 +28,21 @@ signals: void newAccountRequest(const QMap&); void connectAccount(const QString&); void disconnectAccount(const QString&); + void changeState(int state); public slots: void newAccount(const QMap& account); void accountConnectionStateChanged(const QString& account, int state); + void accountAvailabilityChanged(const QString& account, int state); 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& name, const QString& group); + void addContact(const QString& account, const QString& jid, const QString& group, const QMap& 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 QString& name); + void changeContact(const QString& account, const QString& jid, const QMap& data); void addPresence(const QString& account, const QString& jid, const QString& name, const QMap& data); void removePresence(const QString& account, const QString& jid, const QString& name); + void stateChanged(int state); private: QScopedPointer m_ui; diff --git a/ui/squawk.ui b/ui/squawk.ui index 50c4549..c7ee941 100644 --- a/ui/squawk.ui +++ b/ui/squawk.ui @@ -36,27 +36,11 @@ false - Disconnected + - 1 + -1 - - - Available - - - - - - - - Disconnected - - - - -