diff --git a/core/account.cpp b/core/account.cpp index a35c60e..5ffe182 100644 --- a/core/account.cpp +++ b/core/account.cpp @@ -23,6 +23,7 @@ Account::Account(const QString& p_login, const QString& p_server, const QString& config.setUser(p_login); config.setDomain(p_server); config.setPassword(p_password); + config.setAutoAcceptSubscriptions(true); QObject::connect(&client, SIGNAL(connected()), this, SLOT(onClientConnected())); QObject::connect(&client, SIGNAL(disconnected()), this, SLOT(onClientDisconnected())); @@ -183,7 +184,7 @@ void Core::Account::onRosterItemChanged(const QString& bareJid) contact->setGroups(re.groups()); contact->setSubscriptionState(state); - contact->setName(name); + contact->setName(re.name()); } void Core::Account::onRosterItemRemoved(const QString& bareJid) @@ -738,3 +739,25 @@ void Core::Account::onClientError(QXmppClient::Error err) qDebug() << errorType << errorText; emit error(errorText); } + + +void Core::Account::subscribeToContact(const QString& jid, const QString& reason) +{ + if (state == Shared::connected) { + QXmppRosterManager& rm = client.rosterManager(); + rm.subscribe(jid, reason); + } else { + qDebug() << "An attempt to subscribe an account " << name << " to jid " << jid << " but the account is not in the connected state, skipping"; + } +} + +void Core::Account::unsubscribeFromContact(const QString& jid, const QString& reason) +{ + if (state == Shared::connected) { + QXmppRosterManager& rm = client.rosterManager(); + rm.unsubscribe(jid, reason); + } else { + qDebug() << "An attempt to unsubscribe an account " << name << " from jid " << jid << " but the account is not in the connected state, skipping"; + } +} + diff --git a/core/account.h b/core/account.h index d66b519..a26524b 100644 --- a/core/account.h +++ b/core/account.h @@ -44,6 +44,8 @@ public: void sendMessage(const Shared::Message& data); void requestArchive(const QString& jid, int count, const QString& before); void setReconnectTimes(unsigned int times); + void subscribeToContact(const QString& jid, const QString& reason); + void unsubscribeFromContact(const QString& jid, const QString& reason); signals: void connectionStateChanged(int); diff --git a/core/squawk.cpp b/core/squawk.cpp index c8570b7..0fd7c7c 100644 --- a/core/squawk.cpp +++ b/core/squawk.cpp @@ -331,3 +331,26 @@ void Core::Squawk::removeAccountRequest(const QString& name) emit removeAccount(name); acc->deleteLater(); } + + +void Core::Squawk::subscribeContact(const QString& account, const QString& jid, const QString& reason) +{ + AccountsMap::const_iterator itr = amap.find(account); + if (itr == amap.end()) { + qDebug("An attempt to subscribe to the contact with non existing account, skipping"); + return; + } + + itr->second->subscribeToContact(jid, reason); +} + +void Core::Squawk::unsubscribeContact(const QString& account, const QString& jid, const QString& reason) +{ + AccountsMap::const_iterator itr = amap.find(account); + if (itr == amap.end()) { + qDebug("An attempt to subscribe to the contact with non existing account, skipping"); + return; + } + + itr->second->unsubscribeFromContact(jid, reason); +} diff --git a/core/squawk.h b/core/squawk.h index 61e5156..c56715d 100644 --- a/core/squawk.h +++ b/core/squawk.h @@ -49,6 +49,8 @@ public slots: void changeState(int state); void sendMessage(const QString& account, const Shared::Message& data); 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); private: typedef std::deque Accounts; diff --git a/main.cpp b/main.cpp index 66bdbfc..dfe8f8a 100644 --- a/main.cpp +++ b/main.cpp @@ -41,6 +41,10 @@ int main(int argc, char *argv[]) QObject::connect(&w, SIGNAL(sendMessage(const QString&, const Shared::Message&)), squawk, SLOT(sendMessage(const QString&, const Shared::Message&))); QObject::connect(&w, SIGNAL(requestArchive(const QString&, const QString&, int, const QString&)), squawk, SLOT(requestArchive(const QString&, const QString&, int, const QString&))); + QObject::connect(&w, SIGNAL(subscribeContact(const QString&, const QString&, const QString&)), + squawk, SLOT(subscribeContact(const QString&, const QString&, const QString&))); + QObject::connect(&w, SIGNAL(unsubscribeContact(const QString&, const QString&, const QString&)), + squawk, SLOT(unsubscribeContact(const QString&, const QString&, const QString&))); QObject::connect(squawk, SIGNAL(newAccount(const QMap&)), &w, SLOT(newAccount(const QMap&))); QObject::connect(squawk, SIGNAL(addContact(const QString&, const QString&, const QString&, const QMap&)), diff --git a/ui/models/roster.cpp b/ui/models/roster.cpp index 26796da..9d75ef1 100644 --- a/ui/models/roster.cpp +++ b/ui/models/roster.cpp @@ -455,7 +455,6 @@ void Models::Roster::onChildIsAboutToBeRemoved(Models::Item* parent, int first, if (parent != root) { row = parent->row(); } - qDebug() << "Removing row" << parent->child(first)->getName() << "from" << parent->getName() << "index is" << first; beginRemoveRows(createIndex(row, 0, parent), first, last); } diff --git a/ui/squawk.cpp b/ui/squawk.cpp index bf194fb..0c6fe4e 100644 --- a/ui/squawk.cpp +++ b/ui/squawk.cpp @@ -8,10 +8,12 @@ Squawk::Squawk(QWidget *parent) : m_ui(new Ui::Squawk), accounts(0), rosterModel(), - conversations() + conversations(), + contextMenu(new QMenu()) { m_ui->setupUi(this); m_ui->roster->setModel(&rosterModel); + m_ui->roster->setContextMenuPolicy(Qt::CustomContextMenu); for (int i = 0; i < Shared::availabilityNames.size(); ++i) { m_ui->comboBox->addItem(QIcon::fromTheme(Shared::availabilityThemeIcons[i]), Shared::availabilityNames[i]); @@ -21,11 +23,12 @@ Squawk::Squawk(QWidget *parent) : connect(m_ui->actionAccounts, SIGNAL(triggered()), this, SLOT(onAccounts())); connect(m_ui->comboBox, SIGNAL(activated(int)), this, SLOT(onComboboxActivated(int))); connect(m_ui->roster, SIGNAL(doubleClicked(const QModelIndex&)), this, SLOT(onRosterItemDoubleClicked(const QModelIndex&))); + connect(m_ui->roster, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(onRosterContextMenu(const QPoint&))); //m_ui->mainToolBar->addWidget(m_ui->comboBox); } Squawk::~Squawk() { - + delete contextMenu; } void Squawk::onAccounts() @@ -272,3 +275,76 @@ void Squawk::removeAccount(const QString& account) } rosterModel.removeAccount(account); } + +void Squawk::onRosterContextMenu(const QPoint& point) +{ + QModelIndex index = m_ui->roster->indexAt(point); + if (index.isValid()) { + Models::Item* item = static_cast(index.internalPointer()); + + contextMenu->clear(); + bool hasMenu = false; + switch (item->type) { + case Models::Item::account: { + Models::Account* acc = static_cast(item); + hasMenu = true; + QString name = acc->getName(); + + if (acc->getState() != Shared::disconnected) { + QAction* con = contextMenu->addAction(QIcon::fromTheme("network-disconnect"), "Disconnect"); + connect(con, &QAction::triggered, [this, name]() { + emit disconnectAccount(name); + }); + } else { + QAction* con = contextMenu->addAction(QIcon::fromTheme("network-connect"), "Connect"); + connect(con, &QAction::triggered, [this, name]() { + emit connectAccount(name); + }); + } + + QAction* remove = contextMenu->addAction(QIcon::fromTheme("edit-delete"), "Remove"); + connect(remove, &QAction::triggered, [this, name]() { + emit removeAccount(name); + }); + + } + break; + case Models::Item::contact: { + Models::Contact* cnt = static_cast(item); + hasMenu = true; + + QAction* remove = contextMenu->addAction(QIcon::fromTheme("mail-message"), "Open dialog"); + connect(remove, &QAction::triggered, [this, index]() { + onRosterItemDoubleClicked(index); + }); + + Shared::SubscriptionState state = cnt->getState(); + switch (state) { + case Shared::both: + case Shared::to: { + QAction* remove = contextMenu->addAction(QIcon::fromTheme("news-unsubscribe"), "Unsubscribe"); + connect(remove, &QAction::triggered, [this, cnt]() { + emit unsubscribeContact(cnt->getAccountName(), cnt->getJid(), ""); + }); + } + break; + case Shared::from: + case Shared::unknown: + case Shared::none: { + QAction* remove = contextMenu->addAction(QIcon::fromTheme("news-subscribe"), "Subscribe"); + connect(remove, &QAction::triggered, [this, cnt]() { + emit subscribeContact(cnt->getAccountName(), cnt->getJid(), ""); + }); + } + } + + } + break; + default: + break; + } + if (hasMenu) { + contextMenu->popup(m_ui->roster->viewport()->mapToGlobal(point)); + } + } +} diff --git a/ui/squawk.h b/ui/squawk.h index ad1d703..d427401 100644 --- a/ui/squawk.h +++ b/ui/squawk.h @@ -35,6 +35,8 @@ signals: void changeState(int state); void sendMessage(const QString& account, const Shared::Message& data); 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); public slots: void newAccount(const QMap& account); @@ -59,6 +61,7 @@ private: Accounts* accounts; Models::Roster rosterModel; Conversations conversations; + QMenu* contextMenu; protected: void closeEvent(QCloseEvent * event) override; @@ -71,6 +74,7 @@ private slots: void onRosterItemDoubleClicked(const QModelIndex& item); void onConversationMessage(const Shared::Message& msg); void onConversationRequestArchive(const QString& before); + void onRosterContextMenu(const QPoint& point); };