diff options
author | dknn <yoann.blein@free.fr> | 2012-03-24 15:11:14 (GMT) |
---|---|---|
committer | Kevin Smith <git@kismith.co.uk> | 2012-04-08 20:17:23 (GMT) |
commit | fe477c0da80c2e5799a1841ce7fcf4e023ad57bb (patch) | |
tree | 6aedfd75c47c64dee7fcf282e84ebafb6722c65d | |
parent | 36eaae275b39340f44d8225a73ea129bc0c47464 (diff) | |
download | swift-contrib-fe477c0da80c2e5799a1841ce7fcf4e023ad57bb.zip swift-contrib-fe477c0da80c2e5799a1841ce7fcf4e023ad57bb.tar.bz2 |
'Add contact' from MUC right-click menu
This patch allows to add a contact from a MUC, by right clicking a contact in
the rooster. The action is only available if the JID of the user is also
available
License: This patch is BSD-licensed, see Documentation/Licenses/BSD-simplified.txt for details.
-rw-r--r-- | Swift/Controllers/Chat/MUCController.cpp | 7 | ||||
-rw-r--r-- | Swift/Controllers/Chat/UserSearchController.cpp | 10 | ||||
-rw-r--r-- | Swift/Controllers/UIEvents/RequestAddUserDialogUIEvent.h | 14 | ||||
-rw-r--r-- | Swift/Controllers/UIInterfaces/ChatWindow.h | 2 | ||||
-rw-r--r-- | Swift/Controllers/UIInterfaces/UserSearchWindow.h | 1 | ||||
-rw-r--r-- | Swift/QtUI/Roster/QtOccupantListWidget.cpp | 1 | ||||
-rw-r--r-- | Swift/QtUI/UserSearch/QtUserSearchDetailsPage.cpp | 4 | ||||
-rw-r--r-- | Swift/QtUI/UserSearch/QtUserSearchDetailsPage.h | 1 | ||||
-rw-r--r-- | Swift/QtUI/UserSearch/QtUserSearchWindow.cpp | 9 | ||||
-rw-r--r-- | Swift/QtUI/UserSearch/QtUserSearchWindow.h | 1 |
10 files changed, 48 insertions, 2 deletions
diff --git a/Swift/Controllers/Chat/MUCController.cpp b/Swift/Controllers/Chat/MUCController.cpp index b8aa35c..fd37d27 100644 --- a/Swift/Controllers/Chat/MUCController.cpp +++ b/Swift/Controllers/Chat/MUCController.cpp @@ -16,18 +16,19 @@ #include <Swiften/Network/TimerFactory.h> #include <Swiften/Base/foreach.h> #include <SwifTools/TabComplete.h> #include <Swiften/Base/foreach.h> #include <Swift/Controllers/XMPPEvents/EventController.h> #include <Swift/Controllers/UIInterfaces/ChatWindow.h> #include <Swift/Controllers/UIInterfaces/ChatWindowFactory.h> #include <Swift/Controllers/UIEvents/UIEventStream.h> #include <Swift/Controllers/UIEvents/RequestChatUIEvent.h> +#include <Swift/Controllers/UIEvents/RequestAddUserDialogUIEvent.h> #include <Swift/Controllers/Roster/GroupRosterItem.h> #include <Swift/Controllers/Roster/ContactRosterItem.h> #include <Swiften/Avatars/AvatarManager.h> #include <Swiften/Elements/Delay.h> #include <Swiften/MUC/MUC.h> #include <Swiften/Client/StanzaChannel.h> #include <Swift/Controllers/Roster/Roster.h> #include <Swift/Controllers/Roster/SetAvatar.h> #include <Swift/Controllers/Roster/SetPresence.h> @@ -115,35 +116,41 @@ MUCController::~MUCController() { void MUCController::handleWindowOccupantSelectionChanged(ContactRosterItem* item) { std::vector<ChatWindow::OccupantAction> actions; /* FIXME: all of these should be conditional */ if (item) { actions.push_back(ChatWindow::Kick); actions.push_back(ChatWindow::Ban); actions.push_back(ChatWindow::MakeModerator); actions.push_back(ChatWindow::MakeParticipant); actions.push_back(ChatWindow::MakeVisitor); + + // Add contact is available only if the real JID is also available + if (muc_->getOccupant(item->getJID().getResource()).getRealJID()) { + actions.push_back(ChatWindow::AddContact); + } } chatWindow_->setAvailableOccupantActions(actions); } void MUCController::handleActionRequestedOnOccupant(ChatWindow::OccupantAction action, ContactRosterItem* item) { JID mucJID = item->getJID(); MUCOccupant occupant = muc_->getOccupant(mucJID.getResource()); JID realJID; if (occupant.getRealJID()) { realJID = occupant.getRealJID().get(); } switch (action) { case ChatWindow::Kick: muc_->kickOccupant(mucJID);break; case ChatWindow::Ban: muc_->changeAffiliation(realJID, MUCOccupant::Outcast);break; case ChatWindow::MakeModerator: muc_->changeOccupantRole(mucJID, MUCOccupant::Moderator);break; case ChatWindow::MakeParticipant: muc_->changeOccupantRole(mucJID, MUCOccupant::Participant);break; case ChatWindow::MakeVisitor: muc_->changeOccupantRole(mucJID, MUCOccupant::Visitor);break; + case ChatWindow::AddContact: if (occupant.getRealJID()) events_->send(boost::make_shared<RequestAddUserDialogUIEvent>(realJID, occupant.getNick()));break; } } void MUCController::handleBareJIDCapsChanged(const JID& /*jid*/) { ChatWindow::Tristate support = ChatWindow::Yes; bool any = false; foreach (const std::string& nick, currentOccupants_) { DiscoInfo::ref disco = entityCapsProvider_->getCaps(toJID_.toBare().toString() + "/" + nick); if (disco && disco->hasFeature(DiscoInfo::MessageCorrectionFeature)) { diff --git a/Swift/Controllers/Chat/UserSearchController.cpp b/Swift/Controllers/Chat/UserSearchController.cpp index af962e9..47d57d4 100644 --- a/Swift/Controllers/Chat/UserSearchController.cpp +++ b/Swift/Controllers/Chat/UserSearchController.cpp @@ -40,37 +40,45 @@ UserSearchController::~UserSearchController() { window_->onSearchRequested.disconnect(boost::bind(&UserSearchController::handleSearch, this, _1, _2)); delete window_; } vcardManager_->onVCardChanged.disconnect(boost::bind(&UserSearchController::handleVCardChanged, this, _1, _2)); uiEventStream_->onUIEvent.disconnect(boost::bind(&UserSearchController::handleUIEvent, this, _1)); } void UserSearchController::handleUIEvent(boost::shared_ptr<UIEvent> event) { bool handle = false; + boost::shared_ptr<RequestAddUserDialogUIEvent> request = boost::shared_ptr<RequestAddUserDialogUIEvent>(); if (type_ == AddContact) { - if (boost::dynamic_pointer_cast<RequestAddUserDialogUIEvent>(event)) { + if (request = boost::dynamic_pointer_cast<RequestAddUserDialogUIEvent>(event)) { handle = true; } } else { if (boost::dynamic_pointer_cast<RequestChatWithUserDialogUIEvent>(event)) { handle = true; } } if (handle) { if (!window_) { window_ = factory_->createUserSearchWindow(type_ == AddContact ? UserSearchWindow::AddContact : UserSearchWindow::ChatToContact, uiEventStream_, rosterController_->getGroups()); window_->onNameSuggestionRequested.connect(boost::bind(&UserSearchController::handleNameSuggestionRequest, this, _1)); window_->onFormRequested.connect(boost::bind(&UserSearchController::handleFormRequested, this, _1)); window_->onSearchRequested.connect(boost::bind(&UserSearchController::handleSearch, this, _1, _2)); window_->setSelectedService(JID(jid_.getDomain())); window_->clear(); } window_->show(); + if (request) { + const std::string& name = request->getPredefinedName(); + const JID& jid = request->getPredefinedJID(); + if (!name.empty() && jid.isValid()) { + window_->prepopulateJIDAndName(jid, name); + } + } return; } } void UserSearchController::handleFormRequested(const JID& service) { window_->setSearchError(false); window_->setServerSupportsSearch(true); //Abort a previous search if is active diff --git a/Swift/Controllers/UIEvents/RequestAddUserDialogUIEvent.h b/Swift/Controllers/UIEvents/RequestAddUserDialogUIEvent.h index bfa4a8b..26f48cb 100644 --- a/Swift/Controllers/UIEvents/RequestAddUserDialogUIEvent.h +++ b/Swift/Controllers/UIEvents/RequestAddUserDialogUIEvent.h @@ -1,15 +1,29 @@ /* * Copyright (c) 2010 Kevin Smith * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. */ #pragma once #include "Swift/Controllers/UIEvents/UIEvent.h" +#include <string> +#include <Swiften/JID/JID.h> + namespace Swift { class RequestAddUserDialogUIEvent : public UIEvent { + public: + RequestAddUserDialogUIEvent(const JID& predefinedJID, const std::string& predefinedName) : preJID_(predefinedJID), preName_(predefinedName) {}; + RequestAddUserDialogUIEvent() : preJID_(JID()), preName_(std::string()) {}; + + const JID& getPredefinedJID() const { return preJID_; }; + const std::string& getPredefinedName() const { return preName_; }; + + private: + const JID& preJID_; + const std::string& preName_; + }; } diff --git a/Swift/Controllers/UIInterfaces/ChatWindow.h b/Swift/Controllers/UIInterfaces/ChatWindow.h index fe7b6bf..acf2381 100644 --- a/Swift/Controllers/UIInterfaces/ChatWindow.h +++ b/Swift/Controllers/UIInterfaces/ChatWindow.h @@ -28,19 +28,19 @@ namespace Swift { class RosterItem; class ContactRosterItem; class FileTransferController; class ChatWindow { public: enum AckState {Pending, Received, Failed}; enum ReceiptState {ReceiptRequested, ReceiptReceived}; enum Tristate {Yes, No, Maybe}; - enum OccupantAction {Kick, Ban, MakeModerator, MakeParticipant, MakeVisitor}; + enum OccupantAction {Kick, Ban, MakeModerator, MakeParticipant, MakeVisitor, AddContact}; enum FileTransferState {WaitingForAccept, Negotiating, Transferring, Canceled, Finished, FTFailed}; ChatWindow() {} virtual ~ChatWindow() {}; /** Add message to window. * @return id of added message (for acks). */ virtual std::string addMessage(const std::string& message, const std::string& senderName, bool senderIsSelf, boost::shared_ptr<SecurityLabel> label, const std::string& avatarPath, const boost::posix_time::ptime& time) = 0; /** Adds action to window. diff --git a/Swift/Controllers/UIInterfaces/UserSearchWindow.h b/Swift/Controllers/UIInterfaces/UserSearchWindow.h index 7ea6849..a3d69d6 100644 --- a/Swift/Controllers/UIInterfaces/UserSearchWindow.h +++ b/Swift/Controllers/UIInterfaces/UserSearchWindow.h @@ -24,16 +24,17 @@ namespace Swift { virtual void clear() = 0; virtual void setResults(const std::vector<UserSearchResult>& results) = 0; virtual void setResultsForm(const Form::ref results) = 0; virtual void addSavedServices(const std::vector<JID>& services) = 0; virtual void setSelectedService(const JID& service) = 0; virtual void setServerSupportsSearch(bool support) = 0; virtual void setSearchError(bool support) = 0; virtual void setSearchFields(boost::shared_ptr<SearchPayload> fields) = 0; virtual void setNameSuggestions(const std::vector<std::string>& suggestions) = 0; + virtual void prepopulateJIDAndName(const JID& jid, const std::string& name) = 0; virtual void show() = 0; boost::signal<void (const JID&)> onFormRequested; boost::signal<void (boost::shared_ptr<SearchPayload>, const JID&)> onSearchRequested; boost::signal<void (const JID&)> onNameSuggestionRequested; }; } diff --git a/Swift/QtUI/Roster/QtOccupantListWidget.cpp b/Swift/QtUI/Roster/QtOccupantListWidget.cpp index 0b3722c..1469300 100644 --- a/Swift/QtUI/Roster/QtOccupantListWidget.cpp +++ b/Swift/QtUI/Roster/QtOccupantListWidget.cpp @@ -51,18 +51,19 @@ void QtOccupantListWidget::contextMenuEvent(QContextMenuEvent* event) { std::map<QAction*, ChatWindow::OccupantAction> actions; foreach (ChatWindow::OccupantAction availableAction, availableOccupantActions_) { QString text = "Error: missing string"; switch (availableAction) { case ChatWindow::Kick: text = tr("Kick user"); break; case ChatWindow::Ban: text = tr("Kick and ban user"); break; case ChatWindow::MakeModerator: text = tr("Make moderator"); break; case ChatWindow::MakeParticipant: text = tr("Make participant"); break; case ChatWindow::MakeVisitor: text = tr("Remove voice"); break; + case ChatWindow::AddContact: text = tr("Add contact"); break; } QAction* action = contextMenu.addAction(text); actions[action] = availableAction; } QAction* result = contextMenu.exec(event->globalPos()); if (result) { onOccupantActionSelected(actions[result], contact); } } diff --git a/Swift/QtUI/UserSearch/QtUserSearchDetailsPage.cpp b/Swift/QtUI/UserSearch/QtUserSearchDetailsPage.cpp index da89a8d..f4189e7 100644 --- a/Swift/QtUI/UserSearch/QtUserSearchDetailsPage.cpp +++ b/Swift/QtUI/UserSearch/QtUserSearchDetailsPage.cpp @@ -30,18 +30,22 @@ QtUserSearchDetailsPage::~QtUserSearchDetailsPage() { void QtUserSearchDetailsPage::setJID(const JID& jid) { contactJID = jid; } void QtUserSearchDetailsPage::setNameSuggestions(const std::vector<std::string>& nameSuggestions) { editWidget->setNameSuggestions(nameSuggestions); } +void QtUserSearchDetailsPage::setName(const std::string& name) { + editWidget->setName(name); +} + std::set<std::string> QtUserSearchDetailsPage::getSelectedGroups() { return editWidget->getSelectedGroups(); } std::string QtUserSearchDetailsPage::getName() { return editWidget->getName(); } void QtUserSearchDetailsPage::clear() { diff --git a/Swift/QtUI/UserSearch/QtUserSearchDetailsPage.h b/Swift/QtUI/UserSearch/QtUserSearchDetailsPage.h index 9409493..63fd241 100644 --- a/Swift/QtUI/UserSearch/QtUserSearchDetailsPage.h +++ b/Swift/QtUI/UserSearch/QtUserSearchDetailsPage.h @@ -21,18 +21,19 @@ namespace Swift { class QtUserSearchDetailsPage : public QWizardPage { Q_OBJECT public: QtUserSearchDetailsPage(const std::set<std::string>& availableGroups); virtual ~QtUserSearchDetailsPage(); void setJID(const JID& jid); void setNameSuggestions(const std::vector<std::string>& nameSuggestions); + void setName(const std::string& name); std::set<std::string> getSelectedGroups(); std::string getName(); void clear(); signals: void onUserTriggersFinish(); diff --git a/Swift/QtUI/UserSearch/QtUserSearchWindow.cpp b/Swift/QtUI/UserSearch/QtUserSearchWindow.cpp index 949d65c..b8a44e5 100644 --- a/Swift/QtUI/UserSearch/QtUserSearchWindow.cpp +++ b/Swift/QtUI/UserSearch/QtUserSearchWindow.cpp @@ -230,18 +230,27 @@ void QtUserSearchWindow::setSearchFields(boost::shared_ptr<SearchPayload> fields fieldsPage_->emitCompletenessCheck(); } void QtUserSearchWindow::setNameSuggestions(const std::vector<std::string>& suggestions) { if (detailsPage_) { detailsPage_->setNameSuggestions(suggestions); } } +void QtUserSearchWindow::prepopulateJIDAndName(const JID& jid, const std::string& name) { + firstPage_->jid_->setText(P2QSTRING(jid.toBare().toString())); + detailsPage_->setJID(jid); + lastPage_ = 1; + restart(); + next(); + detailsPage_->setName(name); +} + void QtUserSearchWindow::setResults(const std::vector<UserSearchResult>& results) { UserSearchModel *newModel = new UserSearchModel(); newModel->setResults(results); resultsPage_->results_->setModel(newModel); resultsPage_->results_->setItemDelegate(delegate_); resultsPage_->results_->setHeaderHidden(true); delete model_; model_ = newModel; } diff --git a/Swift/QtUI/UserSearch/QtUserSearchWindow.h b/Swift/QtUI/UserSearch/QtUserSearchWindow.h index 9173ba9..32e851a 100644 --- a/Swift/QtUI/UserSearch/QtUserSearchWindow.h +++ b/Swift/QtUI/UserSearch/QtUserSearchWindow.h @@ -34,18 +34,19 @@ namespace Swift { virtual void clear(); virtual void show(); virtual void setResults(const std::vector<UserSearchResult>& results); virtual void setResultsForm(Form::ref results); virtual void setSelectedService(const JID& jid); virtual void setServerSupportsSearch(bool error); virtual void setSearchError(bool error); virtual void setSearchFields(boost::shared_ptr<SearchPayload> fields); virtual void setNameSuggestions(const std::vector<std::string>& suggestions); + virtual void prepopulateJIDAndName(const JID& jid, const std::string& name); protected: virtual int nextId() const; private slots: void handleFirstPageRadioChange(); virtual void handleCurrentChanged(int); virtual void handleAccepted(); private: void clearForm(); |