diff options
-rw-r--r-- | Swift/Controllers/Chat/UserSearchController.cpp | 23 | ||||
-rw-r--r-- | Swift/Controllers/Chat/UserSearchController.h | 8 | ||||
-rw-r--r-- | Swift/Controllers/ContactEditController.cpp | 37 | ||||
-rw-r--r-- | Swift/Controllers/ContactEditController.h | 10 | ||||
-rw-r--r-- | Swift/Controllers/MainController.cpp | 6 | ||||
-rw-r--r-- | Swift/Controllers/UIInterfaces/ContactEditWindow.h | 4 | ||||
-rw-r--r-- | Swift/Controllers/UIInterfaces/UserSearchWindow.h | 6 | ||||
-rw-r--r-- | Swift/QtUI/QtContactEditWidget.cpp | 71 | ||||
-rw-r--r-- | Swift/QtUI/QtContactEditWidget.h | 10 | ||||
-rw-r--r-- | Swift/QtUI/QtContactEditWindow.cpp | 13 | ||||
-rw-r--r-- | Swift/QtUI/QtContactEditWindow.h | 3 | ||||
-rw-r--r-- | Swift/QtUI/UserSearch/QtUserSearchDetailsPage.cpp | 18 | ||||
-rw-r--r-- | Swift/QtUI/UserSearch/QtUserSearchDetailsPage.h | 14 | ||||
-rw-r--r-- | Swift/QtUI/UserSearch/QtUserSearchWindow.cpp | 71 | ||||
-rw-r--r-- | Swift/QtUI/UserSearch/QtUserSearchWindow.h | 5 |
15 files changed, 244 insertions, 55 deletions
diff --git a/Swift/Controllers/Chat/UserSearchController.cpp b/Swift/Controllers/Chat/UserSearchController.cpp index d90a3f8..d6a920d 100644 --- a/Swift/Controllers/Chat/UserSearchController.cpp +++ b/Swift/Controllers/Chat/UserSearchController.cpp @@ -1,89 +1,95 @@ /* * Copyright (c) 2010 Kevin Smith * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. */ #include <Swift/Controllers/Chat/UserSearchController.h> #include <boost/bind.hpp> #include <boost/shared_ptr.hpp> #include <Swiften/Base/foreach.h> #include <Swiften/Disco/GetDiscoInfoRequest.h> #include <Swiften/Disco/GetDiscoItemsRequest.h> #include <Swiften/Disco/DiscoServiceWalker.h> +#include <Swiften/VCards/VCardManager.h> +#include <Swift/Controllers/ContactEditController.h> #include <Swift/Controllers/UIEvents/UIEventStream.h> #include <Swift/Controllers/UIEvents/RequestChatWithUserDialogUIEvent.h> #include <Swift/Controllers/UIEvents/RequestAddUserDialogUIEvent.h> #include <Swift/Controllers/UIInterfaces/UserSearchWindow.h> #include <Swift/Controllers/UIInterfaces/UserSearchWindowFactory.h> #include <Swift/Controllers/Roster/RosterController.h> namespace Swift { -UserSearchController::UserSearchController(Type type, const JID& jid, UIEventStream* uiEventStream, UserSearchWindowFactory* factory, IQRouter* iqRouter, RosterController* rosterController) : type_(type), jid_(jid), uiEventStream_(uiEventStream), factory_(factory), iqRouter_(iqRouter), rosterController_(rosterController) { +UserSearchController::UserSearchController(Type type, const JID& jid, UIEventStream* uiEventStream, VCardManager* vcardManager, UserSearchWindowFactory* factory, IQRouter* iqRouter, RosterController* rosterController) : type_(type), jid_(jid), uiEventStream_(uiEventStream), vcardManager_(vcardManager), factory_(factory), iqRouter_(iqRouter), rosterController_(rosterController) { uiEventStream_->onUIEvent.connect(boost::bind(&UserSearchController::handleUIEvent, this, _1)); + vcardManager_->onVCardChanged.connect(boost::bind(&UserSearchController::handleVCardChanged, this, _1, _2)); window_ = NULL; discoWalker_ = NULL; } UserSearchController::~UserSearchController() { endDiscoWalker(); delete discoWalker_; if (window_) { + window_->onNameSuggestionRequested.disconnect(boost::bind(&UserSearchController::handleNameSuggestionRequest, this, _1)); window_->onFormRequested.disconnect(boost::bind(&UserSearchController::handleFormRequested, this, _1)); 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; if (type_ == AddContact) { if (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(); return; } } void UserSearchController::handleFormRequested(const JID& service) { window_->setSearchError(false); window_->setServerSupportsSearch(true); //Abort a previous search if is active endDiscoWalker(); delete discoWalker_; discoWalker_ = new DiscoServiceWalker(service, iqRouter_); discoWalker_->onServiceFound.connect(boost::bind(&UserSearchController::handleDiscoServiceFound, this, _1, _2)); discoWalker_->onWalkComplete.connect(boost::bind(&UserSearchController::handleDiscoWalkFinished, this)); discoWalker_->beginWalk(); } void UserSearchController::endDiscoWalker() { if (discoWalker_) { discoWalker_->endWalk(); discoWalker_->onServiceFound.disconnect(boost::bind(&UserSearchController::handleDiscoServiceFound, this, _1, _2)); discoWalker_->onWalkComplete.disconnect(boost::bind(&UserSearchController::handleDiscoWalkFinished, this)); } } void UserSearchController::handleDiscoServiceFound(const JID& jid, boost::shared_ptr<DiscoInfo> info) { //bool isUserDirectory = false; bool supports55 = false; @@ -111,41 +117,56 @@ void UserSearchController::handleFormResponse(boost::shared_ptr<SearchPayload> f } window_->setSearchFields(fields); } void UserSearchController::handleSearch(boost::shared_ptr<SearchPayload> fields, const JID& jid) { boost::shared_ptr<GenericRequest<SearchPayload> > searchRequest(new GenericRequest<SearchPayload>(IQ::Set, jid, fields, iqRouter_)); searchRequest->onResponse.connect(boost::bind(&UserSearchController::handleSearchResponse, this, _1, _2)); searchRequest->send(); } void UserSearchController::handleSearchResponse(boost::shared_ptr<SearchPayload> resultsPayload, ErrorPayload::ref error) { if (error || !resultsPayload) { window_->setSearchError(true); return; } std::vector<UserSearchResult> results; if (resultsPayload->getForm()) { window_->setResultsForm(resultsPayload->getForm()); } else { foreach (SearchPayload::Item item, resultsPayload->getItems()) { JID jid(item.jid); std::map<std::string, std::string> fields; fields["first"] = item.first; fields["last"] = item.last; fields["nick"] = item.nick; fields["email"] = item.email; UserSearchResult result(jid, fields); results.push_back(result); } window_->setResults(results); } } +void UserSearchController::handleNameSuggestionRequest(const JID &jid) { + suggestionsJID_= jid; + VCard::ref vcard = vcardManager_->getVCardAndRequestWhenNeeded(jid); + if (vcard) { + handleVCardChanged(jid, vcard); + } +} + +void UserSearchController::handleVCardChanged(const JID& jid, VCard::ref vcard) { + if (jid == suggestionsJID_) { + window_->setNameSuggestions(ContactEditController::nameSuggestionsFromVCard(vcard)); + suggestionsJID_ = JID(); + } +} + void UserSearchController::handleDiscoWalkFinished() { window_->setServerSupportsSearch(false); endDiscoWalker(); } } diff --git a/Swift/Controllers/Chat/UserSearchController.h b/Swift/Controllers/Chat/UserSearchController.h index 071ec33..ce0754c 100644 --- a/Swift/Controllers/Chat/UserSearchController.h +++ b/Swift/Controllers/Chat/UserSearchController.h @@ -1,66 +1,72 @@ /* * Copyright (c) 2010 Kevin Smith * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. */ #pragma once #include <boost/shared_ptr.hpp> #include <map> #include <vector> #include <Swiften/Base/boost_bsignals.h> #include <Swiften/Elements/SearchPayload.h> #include <string> #include <Swiften/JID/JID.h> #include <Swiften/Elements/DiscoInfo.h> #include <Swiften/Elements/DiscoItems.h> #include <Swiften/Elements/ErrorPayload.h> +#include <Swiften/Elements/VCard.h> namespace Swift { class UIEventStream; class UIEvent; class UserSearchWindow; class UserSearchWindowFactory; class IQRouter; class DiscoServiceWalker; class RosterController; + class VCardManager; class UserSearchResult { public: UserSearchResult(const JID& jid, const std::map<std::string, std::string>& fields) : jid_(jid), fields_(fields) {} const JID& getJID() const {return jid_;} const std::map<std::string, std::string>& getFields() const {return fields_;} private: JID jid_; std::map<std::string, std::string> fields_; }; class UserSearchController { public: enum Type {AddContact, StartChat}; - UserSearchController(Type type, const JID& jid, UIEventStream* uiEventStream, UserSearchWindowFactory* userSearchWindowFactory, IQRouter* iqRouter, RosterController* rosterController); + UserSearchController(Type type, const JID& jid, UIEventStream* uiEventStream, VCardManager* vcardManager, UserSearchWindowFactory* userSearchWindowFactory, IQRouter* iqRouter, RosterController* rosterController); ~UserSearchController(); private: void handleUIEvent(boost::shared_ptr<UIEvent> event); void handleFormRequested(const JID& service); void handleDiscoServiceFound(const JID& jid, boost::shared_ptr<DiscoInfo> info); void handleDiscoWalkFinished(); void handleFormResponse(boost::shared_ptr<SearchPayload> items, ErrorPayload::ref error); void handleSearch(boost::shared_ptr<SearchPayload> fields, const JID& jid); void handleSearchResponse(boost::shared_ptr<SearchPayload> results, ErrorPayload::ref error); + void handleNameSuggestionRequest(const JID& jid); + void handleVCardChanged(const JID& jid, VCard::ref vcard); void endDiscoWalker(); private: Type type_; JID jid_; + JID suggestionsJID_; UIEventStream* uiEventStream_; + VCardManager* vcardManager_; UserSearchWindowFactory* factory_; IQRouter* iqRouter_; RosterController* rosterController_; UserSearchWindow* window_; DiscoServiceWalker* discoWalker_; }; } diff --git a/Swift/Controllers/ContactEditController.cpp b/Swift/Controllers/ContactEditController.cpp index b4729a8..a8b171c 100644 --- a/Swift/Controllers/ContactEditController.cpp +++ b/Swift/Controllers/ContactEditController.cpp @@ -1,75 +1,108 @@ /* * Copyright (c) 2010 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. */ #include <Swift/Controllers/ContactEditController.h> +#include <boost/algorithm/string.hpp> #include <boost/bind.hpp> #include <boost/smart_ptr/make_shared.hpp> #include <Swift/Controllers/UIEvents/RequestContactEditorUIEvent.h> #include <Swift/Controllers/UIEvents/UIEventStream.h> #include <Swift/Controllers/UIEvents/RemoveRosterItemUIEvent.h> #include <Swift/Controllers/UIInterfaces/ContactEditWindowFactory.h> #include <Swift/Controllers/Roster/RosterController.h> +#include <Swiften/VCards/VCardManager.h> namespace Swift { -ContactEditController::ContactEditController(RosterController* rosterController, ContactEditWindowFactory* contactEditWindowFactory, UIEventStream* uiEventStream) : rosterController(rosterController), contactEditWindowFactory(contactEditWindowFactory), uiEventStream(uiEventStream), contactEditWindow(NULL) { +ContactEditController::ContactEditController(RosterController* rosterController, VCardManager* vcardManager, ContactEditWindowFactory* contactEditWindowFactory, UIEventStream* uiEventStream) : rosterController(rosterController), vcardManager(vcardManager), contactEditWindowFactory(contactEditWindowFactory), uiEventStream(uiEventStream), contactEditWindow(NULL) { uiEventStream->onUIEvent.connect(boost::bind(&ContactEditController::handleUIEvent, this, _1)); } ContactEditController::~ContactEditController() { if (contactEditWindow) { contactEditWindow->onChangeContactRequest.disconnect(boost::bind(&ContactEditController::handleChangeContactRequest, this, _1, _2)); contactEditWindow->onRemoveContactRequest.disconnect(boost::bind(&ContactEditController::handleRemoveContactRequest, this)); delete contactEditWindow; } uiEventStream->onUIEvent.disconnect(boost::bind(&ContactEditController::handleUIEvent, this, _1)); } void ContactEditController::handleUIEvent(UIEvent::ref event) { RequestContactEditorUIEvent::ref editEvent = boost::dynamic_pointer_cast<RequestContactEditorUIEvent>(event); if (!editEvent) { return; } if (!contactEditWindow) { contactEditWindow = contactEditWindowFactory->createContactEditWindow(); contactEditWindow->onRemoveContactRequest.connect(boost::bind(&ContactEditController::handleRemoveContactRequest, this)); contactEditWindow->onChangeContactRequest.connect(boost::bind(&ContactEditController::handleChangeContactRequest, this, _1, _2)); } currentContact = rosterController->getItem(editEvent->getJID()); assert(currentContact); - contactEditWindow->setContact(currentContact->getJID(), currentContact->getName(), currentContact->getGroups(), rosterController->getGroups()); + jid = rosterController->getItem(editEvent->getJID())->getJID(); + contactEditWindow->setContact(jid, currentContact->getName(), currentContact->getGroups(), rosterController->getGroups()); contactEditWindow->show(); + + if (vcardManager) { + VCard::ref vcard = vcardManager->getVCardAndRequestWhenNeeded(jid); + if (vcard) { + handleVCardChanged(jid, vcard); + } + } +} + +void ContactEditController::handleVCardChanged(const JID &jid, VCard::ref vcard) { + if (jid == this->jid) { + contactEditWindow->setNameSuggestions(nameSuggestionsFromVCard(vcard)); + } } void ContactEditController::setAvailable(bool b) { if (contactEditWindow) { contactEditWindow->setEnabled(b); } } +std::vector<std::string> ContactEditController::nameSuggestionsFromVCard(VCard::ref vcard) { + std::vector<std::string> suggestions; + if (!vcard->getNickname().empty()) { + suggestions.push_back(vcard->getNickname()); + } + if (!vcard->getFullName().empty()) { + suggestions.push_back(vcard->getFullName()); + } + if (!vcard->getGivenName().empty()) { + std::string suggestedName; + suggestedName = vcard->getGivenName(); + boost::algorithm::trim(suggestedName); + suggestions.push_back(suggestedName); + } + return suggestions; +} + void ContactEditController::handleRemoveContactRequest() { assert(currentContact); uiEventStream->send(boost::make_shared<RemoveRosterItemUIEvent>(currentContact->getJID())); contactEditWindow->hide(); } void ContactEditController::handleChangeContactRequest(const std::string& name, const std::set<std::string>& newGroups) { std::vector<std::string> oldGroupsVector = currentContact->getGroups(); std::set<std::string> oldGroups(oldGroupsVector.begin(), oldGroupsVector.end()); if (oldGroups != newGroups || currentContact->getName() != name) { XMPPRosterItem newContact(*currentContact); newContact.setName(name); newContact.setGroups(std::vector<std::string>(newGroups.begin(), newGroups.end())); rosterController->updateItem(newContact); } contactEditWindow->hide(); } } diff --git a/Swift/Controllers/ContactEditController.h b/Swift/Controllers/ContactEditController.h index 1947944..5f64a6a 100644 --- a/Swift/Controllers/ContactEditController.h +++ b/Swift/Controllers/ContactEditController.h @@ -1,46 +1,54 @@ /* * Copyright (c) 2010 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. */ #pragma once #include <vector> #include <set> #include <boost/optional.hpp> #include <Swiften/JID/JID.h> #include <string> +#include <Swiften/Elements/VCard.h> #include <Swift/Controllers/UIEvents/UIEvent.h> #include <Swiften/Roster/XMPPRosterItem.h> namespace Swift { class UIEventStream; class ContactEditWindowFactory; class ContactEditWindow; class RosterController; + class VCardManager; class ContactEditController { public: - ContactEditController(RosterController* rosterController, ContactEditWindowFactory* contactEditWindowFactory, UIEventStream* uiEventStream); + ContactEditController(RosterController* rosterController, VCardManager* vcardManager, ContactEditWindowFactory* contactEditWindowFactory, UIEventStream* uiEventStream); ~ContactEditController(); void setAvailable(bool b); + public: + static std::vector<std::string> nameSuggestionsFromVCard(VCard::ref vcard); + private: void handleRemoveContactRequest(); void handleChangeContactRequest(const std::string& name, const std::set<std::string>& groups); private: void handleUIEvent(UIEvent::ref event); + void handleVCardChanged(const JID& jid, VCard::ref vcard); private: boost::optional<XMPPRosterItem> currentContact; RosterController* rosterController; + VCardManager* vcardManager; ContactEditWindowFactory* contactEditWindowFactory; UIEventStream* uiEventStream; + JID jid; ContactEditWindow* contactEditWindow; }; } diff --git a/Swift/Controllers/MainController.cpp b/Swift/Controllers/MainController.cpp index b154e93..cd7e673 100644 --- a/Swift/Controllers/MainController.cpp +++ b/Swift/Controllers/MainController.cpp @@ -254,98 +254,98 @@ void MainController::resetPendingReconnects() { reconnectTimer_->stop(); reconnectTimer_.reset(); } resetCurrentError(); } void MainController::resetCurrentError() { if (lastDisconnectError_) { lastDisconnectError_->conclude(); lastDisconnectError_ = boost::shared_ptr<ErrorEvent>(); } } void MainController::handleConnected() { boundJID_ = client_->getJID(); resetCurrentError(); resetPendingReconnects(); if (settings_->getSetting(SettingConstants::FORGET_PASSWORDS)) { purgeCachedCredentials(); } bool freshLogin = rosterController_ == NULL; myStatusLooksOnline_ = true; if (freshLogin) { profileController_ = new ProfileController(client_->getVCardManager(), uiFactory_, uiEventStream_); srand(time(NULL)); int randomPort = 10000 + rand() % 10000; client_->getFileTransferManager()->startListeningOnPort(randomPort); ftOverview_ = new FileTransferOverview(client_->getFileTransferManager()); fileTransferListController_->setFileTransferOverview(ftOverview_); rosterController_ = new RosterController(jid_, client_->getRoster(), client_->getAvatarManager(), uiFactory_, client_->getNickManager(), client_->getNickResolver(), client_->getPresenceOracle(), client_->getSubscriptionManager(), eventController_, uiEventStream_, client_->getIQRouter(), settings_, client_->getEntityCapsProvider(), ftOverview_); rosterController_->onChangeStatusRequest.connect(boost::bind(&MainController::handleChangeStatusRequest, this, _1, _2)); rosterController_->onSignOutRequest.connect(boost::bind(&MainController::signOut, this)); - contactEditController_ = new ContactEditController(rosterController_, uiFactory_, uiEventStream_); + contactEditController_ = new ContactEditController(rosterController_, client_->getVCardManager(), uiFactory_, uiEventStream_); chatsManager_ = new ChatsManager(jid_, client_->getStanzaChannel(), client_->getIQRouter(), eventController_, uiFactory_, uiFactory_, client_->getNickResolver(), client_->getPresenceOracle(), client_->getPresenceSender(), uiEventStream_, uiFactory_, useDelayForLatency_, networkFactories_->getTimerFactory(), client_->getMUCRegistry(), client_->getEntityCapsProvider(), client_->getMUCManager(), uiFactory_, profileSettings_, ftOverview_, client_->getRoster(), !settings_->getSetting(SettingConstants::REMEMBER_RECENT_CHATS), settings_); client_->onMessageReceived.connect(boost::bind(&ChatsManager::handleIncomingMessage, chatsManager_, _1)); chatsManager_->setAvatarManager(client_->getAvatarManager()); eventWindowController_ = new EventWindowController(eventController_, uiFactory_); loginWindow_->morphInto(rosterController_->getWindow()); DiscoInfo discoInfo; discoInfo.addIdentity(DiscoInfo::Identity(CLIENT_NAME, "client", "pc")); discoInfo.addFeature(DiscoInfo::ChatStatesFeature); discoInfo.addFeature(DiscoInfo::SecurityLabelsFeature); discoInfo.addFeature(DiscoInfo::MessageCorrectionFeature); #ifdef SWIFT_EXPERIMENTAL_FT discoInfo.addFeature(DiscoInfo::JingleFeature); discoInfo.addFeature(DiscoInfo::JingleFTFeature); discoInfo.addFeature(DiscoInfo::JingleTransportsIBBFeature); discoInfo.addFeature(DiscoInfo::JingleTransportsS5BFeature); #endif discoInfo.addFeature(DiscoInfo::MessageDeliveryReceiptsFeature); client_->getDiscoManager()->setCapsNode(CLIENT_NODE); client_->getDiscoManager()->setDiscoInfo(discoInfo); - userSearchControllerChat_ = new UserSearchController(UserSearchController::StartChat, jid_, uiEventStream_, uiFactory_, client_->getIQRouter(), rosterController_); - userSearchControllerAdd_ = new UserSearchController(UserSearchController::AddContact, jid_, uiEventStream_, uiFactory_, client_->getIQRouter(), rosterController_); + userSearchControllerChat_ = new UserSearchController(UserSearchController::StartChat, jid_, uiEventStream_, client_->getVCardManager(), uiFactory_, client_->getIQRouter(), rosterController_); + userSearchControllerAdd_ = new UserSearchController(UserSearchController::AddContact, jid_, uiEventStream_, client_->getVCardManager(), uiFactory_, client_->getIQRouter(), rosterController_); adHocManager_ = new AdHocManager(JID(boundJID_.getDomain()), uiFactory_, client_->getIQRouter(), uiEventStream_, rosterController_->getWindow()); } loginWindow_->setIsLoggingIn(false); client_->requestRoster(); GetDiscoInfoRequest::ref discoInfoRequest = GetDiscoInfoRequest::create(JID(boundJID_.getDomain()), client_->getIQRouter()); discoInfoRequest->onResponse.connect(boost::bind(&MainController::handleServerDiscoInfoResponse, this, _1, _2)); discoInfoRequest->send(); client_->getVCardManager()->requestOwnVCard(); rosterController_->setEnabled(true); profileController_->setAvailable(true); contactEditController_->setAvailable(true); /* Send presence later to catch all the incoming presences. */ sendPresence(statusTracker_->getNextPresence()); /* Enable chats last of all, so rejoining MUCs has the right sent presence */ chatsManager_->setOnline(true); } void MainController::handleEventQueueLengthChange(int count) { dock_->setNumberOfPendingMessages(count); } void MainController::reconnectAfterError() { if (reconnectTimer_) { reconnectTimer_->stop(); } performLoginFromCachedCredentials(); } void MainController::handleChangeStatusRequest(StatusShow::Type show, const std::string &statusText) { boost::shared_ptr<Presence> presence(new Presence()); diff --git a/Swift/Controllers/UIInterfaces/ContactEditWindow.h b/Swift/Controllers/UIInterfaces/ContactEditWindow.h index 2445456..90f774c 100644 --- a/Swift/Controllers/UIInterfaces/ContactEditWindow.h +++ b/Swift/Controllers/UIInterfaces/ContactEditWindow.h @@ -1,33 +1,35 @@ /* * Copyright (c) 2010 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. */ #pragma once #include <Swiften/Base/boost_bsignals.h> #include <boost/shared_ptr.hpp> #include <set> #include <vector> #include <string> namespace Swift { class JID; + class VCardManager; class ContactEditWindow { public: - virtual ~ContactEditWindow() {}; + virtual ~ContactEditWindow() {} virtual void setEnabled(bool b) = 0; + virtual void setNameSuggestions(const std::vector<std::string>& suggestions) = 0; virtual void setContact(const JID& jid, const std::string& name, const std::vector<std::string>& groups, const std::set<std::string>& allGroups) = 0; virtual void show() = 0; virtual void hide() = 0; boost::signal<void ()> onRemoveContactRequest; boost::signal<void (const std::string& /* name */, const std::set<std::string>& /* groups */)> onChangeContactRequest; }; } diff --git a/Swift/Controllers/UIInterfaces/UserSearchWindow.h b/Swift/Controllers/UIInterfaces/UserSearchWindow.h index 0bfc509..7ea6849 100644 --- a/Swift/Controllers/UIInterfaces/UserSearchWindow.h +++ b/Swift/Controllers/UIInterfaces/UserSearchWindow.h @@ -1,37 +1,39 @@ /* * Copyright (c) 2010 Kevin Smith * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. */ #pragma once #include "Swiften/Base/boost_bsignals.h" #include <vector> - #include <string> + #include "Swiften/JID/JID.h" #include "Swift/Controllers/Chat/UserSearchController.h" namespace Swift { class UserSearchWindow { public: enum Type {AddContact, ChatToContact}; - virtual ~UserSearchWindow() {}; + virtual ~UserSearchWindow() {} 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 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/QtContactEditWidget.cpp b/Swift/QtUI/QtContactEditWidget.cpp index a5134e4..a80eb38 100644 --- a/Swift/QtUI/QtContactEditWidget.cpp +++ b/Swift/QtUI/QtContactEditWidget.cpp @@ -1,100 +1,151 @@ /* * Copyright (c) 2010 Kevin Smith * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. */ #include "QtContactEditWidget.h" #include <algorithm> -#include <QScrollArea> #include <QBoxLayout> -#include <QLabel> #include <QCheckBox> +#include <QLabel> #include <QLineEdit> +#include <QMovie> +#include <QScrollArea> +#include <QRadioButton> #include "Swift/QtUI/QtSwiftUtil.h" namespace Swift { -QtContactEditWidget::QtContactEditWidget(const std::set<std::string>& allGroups, QWidget* parent) : QWidget(parent), groups_(NULL) { +QtContactEditWidget::QtContactEditWidget(const std::set<std::string>& allGroups, QWidget* parent) : QWidget(parent), nameRadioButton_(NULL), groups_(NULL) { QBoxLayout* layout = new QVBoxLayout(this); setContentsMargins(0,0,0,0); layout->setContentsMargins(0,0,0,0); - QHBoxLayout* nameLayout = new QHBoxLayout(); - - QLabel* label = new QLabel(tr("Name:"), this); - nameLayout->addWidget(label); + nameLayout_ = new QHBoxLayout(); + suggestionsLayout_ = new QHBoxLayout(); + nameLayout_->addLayout(suggestionsLayout_); + name_ = new QLineEdit(this); - nameLayout->addWidget(name_); - layout->addLayout(nameLayout); + nameLayout_->addWidget(name_); + + throbberLabel_ = new QLabel(this); + throbberLabel_->setMovie(new QMovie(":/icons/throbber.gif", QByteArray(), this)); + throbberLabel_->movie()->start(); + nameLayout_->addWidget(throbberLabel_); + + layout->addLayout(nameLayout_); layout->addWidget(new QLabel(tr("Groups:"), this)); QScrollArea* groupsArea = new QScrollArea(this); layout->addWidget(groupsArea); groupsArea->setWidgetResizable(true); groupsArea->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); groupsArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded); QWidget* groups = new QWidget(groupsArea); groupsArea->setWidget(groups); QVBoxLayout* scrollLayout = new QVBoxLayout(groups); foreach (std::string group, allGroups) { QCheckBox* check = new QCheckBox(groups); check->setText(P2QSTRING(group)); check->setCheckState(Qt::Unchecked); checkBoxes_[group] = check; scrollLayout->addWidget(check); } QHBoxLayout* newGroupLayout = new QHBoxLayout(); newGroup_ = new QCheckBox(groups); newGroup_->setText(tr("New Group:")); newGroup_->setCheckState(Qt::Unchecked); newGroupLayout->addWidget(newGroup_); newGroupName_ = new QLineEdit(groups); newGroupLayout->addWidget(newGroupName_); scrollLayout->addLayout(newGroupLayout); scrollLayout->addItem(new QSpacerItem(20, 73, QSizePolicy::Minimum, QSizePolicy::Expanding)); } void QtContactEditWidget::setName(const std::string& name) { name_->setText(P2QSTRING(name)); } std::string QtContactEditWidget::getName() const { - return Q2PSTRING(name_->text()); + std::string name; + QList<QRadioButton*> buttons = findChildren<QRadioButton*>(); + foreach(const QRadioButton* button, buttons) { + if (button->isChecked()) { + if (button == nameRadioButton_) { + name = Q2PSTRING(name_->text()); + } else { + name = Q2PSTRING(button->text()); + } + break; + } + } + return name; } void QtContactEditWidget::setSelectedGroups(const std::vector<std::string>& groups) { foreach (std::string group, groups) { checkBoxes_[group]->setCheckState(Qt::Checked); } } std::set<std::string> QtContactEditWidget::getSelectedGroups() const { std::set<std::string> groups; foreach(const CheckBoxMap::value_type& group, checkBoxes_) { if (group.second->checkState() == Qt::Checked) { groups.insert(group.first); } } if (newGroup_->checkState() == Qt::Checked && !newGroupName_->text().isEmpty()) { groups.insert(Q2PSTRING(newGroupName_->text())); } return groups; } +void QtContactEditWidget::setNameSuggestions(const std::vector<std::string>& suggestions) { + throbberLabel_->movie()->stop(); + throbberLabel_->hide(); + + foreach(const std::string& name, suggestions) { + suggestionsLayout_->insertWidget(nameLayout_->count() - 2, new QRadioButton(P2QSTRING(name), this)); + } + + nameRadioButton_ = new QRadioButton(tr("Name:"), this); + suggestionsLayout_->insertWidget(nameLayout_->count(), nameRadioButton_); + + if (name_->text().isEmpty()) { + QRadioButton* suggestedRadioButton = dynamic_cast<QRadioButton*>(suggestionsLayout_->itemAt(0)->widget()); + if (suggestedRadioButton) { + suggestedRadioButton->setChecked(true); + } + } else { + nameRadioButton_->setChecked(true); + } +} + void QtContactEditWidget::clear() { name_->clear(); setSelectedGroups(std::vector<std::string>()); newGroup_->setChecked(false); newGroupName_->clear(); + throbberLabel_->movie()->start(); + throbberLabel_->show(); + + // clear suggestions + while(suggestionsLayout_->count() != 0) { + QLayoutItem *layoutItem = suggestionsLayout_->takeAt(0); + delete layoutItem->widget(); + delete layoutItem; + } + nameRadioButton_ = NULL; } } diff --git a/Swift/QtUI/QtContactEditWidget.h b/Swift/QtUI/QtContactEditWidget.h index 8ff267d..5350762 100644 --- a/Swift/QtUI/QtContactEditWidget.h +++ b/Swift/QtUI/QtContactEditWidget.h @@ -1,44 +1,54 @@ /* * Copyright (c) 2010 Kevin Smith * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. */ #pragma once #include <map> #include <set> #include <boost/shared_ptr.hpp> #include <QWidget> +#include <vector> #include <string> +class QLabel; class QLineEdit; class QCheckBox; +class QHBoxLayout; +class QRadioButton; namespace Swift { class QtContactEditWidget : public QWidget { Q_OBJECT public: QtContactEditWidget(const std::set<std::string>& allGroups, QWidget* parent); void setName(const std::string&); std::string getName() const; void setSelectedGroups(const std::vector<std::string>& groups); std::set<std::string> getSelectedGroups() const; + void setNameSuggestions(const std::vector<std::string>& suggestions); + void clear(); private: typedef std::map<std::string, QCheckBox*> CheckBoxMap; CheckBoxMap checkBoxes_; + QHBoxLayout* nameLayout_; + QHBoxLayout* suggestionsLayout_; + QRadioButton* nameRadioButton_; QLineEdit* name_; QWidget* groups_; QCheckBox* newGroup_; QLineEdit* newGroupName_; + QLabel* throbberLabel_; }; } diff --git a/Swift/QtUI/QtContactEditWindow.cpp b/Swift/QtUI/QtContactEditWindow.cpp index 9b24b23..6520c0a 100644 --- a/Swift/QtUI/QtContactEditWindow.cpp +++ b/Swift/QtUI/QtContactEditWindow.cpp @@ -1,85 +1,96 @@ /* * Copyright (c) 2010 Kevin Smith * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. */ #include "QtContactEditWindow.h" #include <algorithm> +#include <boost/bind.hpp> + #include <QScrollArea> #include <QBoxLayout> #include <QLabel> #include <QCheckBox> #include <QLineEdit> #include <QMessageBox> #include <QPushButton> #include "Swift/QtUI/QtSwiftUtil.h" #include "QtContactEditWidget.h" namespace Swift { QtContactEditWindow::QtContactEditWindow() : contactEditWidget_(NULL) { - resize(300,300); + resize(400,300); setWindowTitle(tr("Edit contact")); setContentsMargins(0,0,0,0); QBoxLayout* layout = new QVBoxLayout(this); jidLabel_ = new QLabel(this); jidLabel_->setAlignment(Qt::AlignHCenter); layout->addWidget(jidLabel_); groupsLayout_ = new QVBoxLayout(); groupsLayout_->setContentsMargins(0,0,0,0); layout->addLayout(groupsLayout_); QHBoxLayout* buttonLayout = new QHBoxLayout(); layout->addLayout(buttonLayout); QPushButton* removeButton = new QPushButton(tr("Remove contact"), this); connect(removeButton, SIGNAL(clicked()), this, SLOT(handleRemoveContact())); buttonLayout->addWidget(removeButton); QPushButton* okButton = new QPushButton(tr("OK"), this); okButton->setDefault( true ); connect(okButton, SIGNAL(clicked()), this, SLOT(handleUpdateContact())); buttonLayout->addStretch(); buttonLayout->addWidget(okButton); } +QtContactEditWindow::~QtContactEditWindow() { +} + +void QtContactEditWindow::setNameSuggestions(const std::vector<std::string>& nameSuggestions) { + if (contactEditWidget_) { + contactEditWidget_->setNameSuggestions(nameSuggestions); + } +} + void QtContactEditWindow::setContact(const JID& jid, const std::string& name, const std::vector<std::string>& groups, const std::set<std::string>& allGroups) { delete contactEditWidget_; jid_ = jid; jidLabel_->setText("<b>" + P2QSTRING(jid.toString()) + "</b>"); contactEditWidget_ = new QtContactEditWidget(allGroups, this); groupsLayout_->addWidget(contactEditWidget_); contactEditWidget_->setName(name); contactEditWidget_->setSelectedGroups(groups); } void QtContactEditWindow::setEnabled(bool b) { QWidget::setEnabled(b); } void QtContactEditWindow::show() { QWidget::show(); QWidget::activateWindow(); } void QtContactEditWindow::hide() { QWidget::hide(); } void QtContactEditWindow::handleRemoveContact() { if (confirmContactDeletion(jid_)) { onRemoveContactRequest(); } } bool QtContactEditWindow::confirmContactDeletion(const JID& jid) { QMessageBox msgBox; msgBox.setWindowTitle(tr("Confirm contact deletion")); msgBox.setText(tr("Are you sure you want to delete this contact?")); msgBox.setInformativeText(QString(tr("This will remove the contact '%1' from all groups they may be in.")).arg(P2QSTRING(jid.toString()))); diff --git a/Swift/QtUI/QtContactEditWindow.h b/Swift/QtUI/QtContactEditWindow.h index b25e8b9..5392b10 100644 --- a/Swift/QtUI/QtContactEditWindow.h +++ b/Swift/QtUI/QtContactEditWindow.h @@ -1,46 +1,49 @@ /* * Copyright (c) 2010 Kevin Smith * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. */ #pragma once #include <QWidget> #include <Swift/Controllers/UIInterfaces/ContactEditWindow.h> #include <string> #include <Swiften/JID/JID.h> +#include <Swiften/Elements/VCard.h> class QLabel; class QVBoxLayout; namespace Swift { class QtContactEditWidget; class QtContactEditWindow : public QWidget, public ContactEditWindow { Q_OBJECT public: QtContactEditWindow(); + virtual ~QtContactEditWindow(); + virtual void setNameSuggestions(const std::vector<std::string>& nameSuggestions); virtual void setContact(const JID& jid, const std::string& name, const std::vector<std::string>& groups, const std::set<std::string>& allGroups); void setEnabled(bool); void show(); void hide(); static bool confirmContactDeletion(const JID& jid); private slots: void handleRemoveContact(); void handleUpdateContact(); private: JID jid_; QVBoxLayout* groupsLayout_; QLabel* jidLabel_; QtContactEditWidget* contactEditWidget_; }; } diff --git a/Swift/QtUI/UserSearch/QtUserSearchDetailsPage.cpp b/Swift/QtUI/UserSearch/QtUserSearchDetailsPage.cpp index 779e547..da89a8d 100644 --- a/Swift/QtUI/UserSearch/QtUserSearchDetailsPage.cpp +++ b/Swift/QtUI/UserSearch/QtUserSearchDetailsPage.cpp @@ -1,35 +1,51 @@ /* * Copyright (c) 2011 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. */ #include "Swift/QtUI/UserSearch/QtUserSearchDetailsPage.h" #include <QVBoxLayout> +#include <boost/bind.hpp> + +#include <Swiften/Base/boost_bsignals.h> +#include <Swiften/JID/JID.h> + #include <Swift/QtUI/QtContactEditWidget.h> namespace Swift { QtUserSearchDetailsPage::QtUserSearchDetailsPage(const std::set<std::string>& groups) { QVBoxLayout* layout = new QVBoxLayout(this); layout->addWidget(new QLabel(tr("Please choose a name for the contact, and select the groups you want to add the contact to."))); editWidget = new QtContactEditWidget(groups, this); layout->addWidget(editWidget); } +QtUserSearchDetailsPage::~QtUserSearchDetailsPage() { + +} + +void QtUserSearchDetailsPage::setJID(const JID& jid) { + contactJID = jid; +} + +void QtUserSearchDetailsPage::setNameSuggestions(const std::vector<std::string>& nameSuggestions) { + editWidget->setNameSuggestions(nameSuggestions); +} + std::set<std::string> QtUserSearchDetailsPage::getSelectedGroups() { return editWidget->getSelectedGroups(); } std::string QtUserSearchDetailsPage::getName() { return editWidget->getName(); } void QtUserSearchDetailsPage::clear() { editWidget->clear(); } - } diff --git a/Swift/QtUI/UserSearch/QtUserSearchDetailsPage.h b/Swift/QtUI/UserSearch/QtUserSearchDetailsPage.h index 70afcba..9409493 100644 --- a/Swift/QtUI/UserSearch/QtUserSearchDetailsPage.h +++ b/Swift/QtUI/UserSearch/QtUserSearchDetailsPage.h @@ -1,33 +1,43 @@ /* * Copyright (c) 2011 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. */ #pragma once #include <QWizardPage> + #include <set> +#include <string> +#include <vector> +#include <Swiften/Elements/VCard.h> +#include <Swiften/JID/JID.h> #include <Swift/QtUI/UserSearch/ui_QtUserSearchFieldsPage.h> namespace Swift { class QtContactEditWidget; 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); std::set<std::string> getSelectedGroups(); std::string getName(); void clear(); signals: - void onUserTriggersFinish(); + void onUserTriggersFinish(); private: - QtContactEditWidget* editWidget; + QtContactEditWidget* editWidget; + JID contactJID; }; } diff --git a/Swift/QtUI/UserSearch/QtUserSearchWindow.cpp b/Swift/QtUI/UserSearch/QtUserSearchWindow.cpp index 933612c..53eac07 100644 --- a/Swift/QtUI/UserSearch/QtUserSearchWindow.cpp +++ b/Swift/QtUI/UserSearch/QtUserSearchWindow.cpp @@ -58,203 +58,216 @@ QtUserSearchWindow::QtUserSearchWindow(UIEventStream* eventStream, UserSearchWin resultsPage_->results_->setAlternatingRowColors(true); #endif if (type == AddContact) { connect(resultsPage_, SIGNAL(onUserTriggersContinue()), this, SLOT(next())); } else { connect(resultsPage_, SIGNAL(onUserTriggersContinue()), this, SLOT(accept())); } setPage(3, resultsPage_); detailsPage_ = new QtUserSearchDetailsPage(groups); setPage(4, detailsPage_); connect(this, SIGNAL(currentIdChanged(int)), this, SLOT(handleCurrentChanged(int))); connect(this, SIGNAL(accepted()), this, SLOT(handleAccepted())); clear(); } QtUserSearchWindow::~QtUserSearchWindow() { delete model_; } void QtUserSearchWindow::handleCurrentChanged(int page) { if (page == 2 && lastPage_ == 1) { setError(""); /* next won't be called if JID is selected */ JID server = getServerToSearch(); clearForm(); onFormRequested(server); } else if (page == 3 && lastPage_ == 2) { handleSearch(); } else if (page == 4) { detailsPage_->clear(); + detailsPage_->setJID(getContactJID()); + onNameSuggestionRequested(getContactJID()); } lastPage_ = page; } JID QtUserSearchWindow::getServerToSearch() { return firstPage_->byRemoteSearch_->isChecked() ? JID(Q2PSTRING(firstPage_->service_->currentText())) : myServer_; } void QtUserSearchWindow::handleAccepted() { - JID jid; - if (!firstPage_->byJID_->isChecked()) { - if (dynamic_cast<UserSearchModel*>(model_)) { - UserSearchResult* userItem = static_cast<UserSearchResult*>(resultsPage_->results_->currentIndex().internalPointer()); - if (userItem) { /* Remember to leave this if we change to dynamic cast */ - jid = userItem->getJID(); - } - } else { - int row = resultsPage_->results_->currentIndex().row(); - - Form::FormItem item = dynamic_cast<QtFormResultItemModel*>(model_)->getForm()->getItems().at(row); - JID fallbackJid; - foreach(FormField::ref field, item) { - if (boost::dynamic_pointer_cast<JIDSingleFormField>(field)) { - jid = JID(field->getRawValues().at(0)); - break; - } - if (field->getName() == "jid") { - fallbackJid = field->getRawValues().at(0); - } - } - if (!jid.isValid()) { - jid = fallbackJid; - } - } - } - else { - jid = JID(Q2PSTRING(firstPage_->jid_->text())); - } + JID jid = getContactJID(); if (type_ == AddContact) { eventStream_->send(boost::make_shared<AddContactUIEvent>(jid, detailsPage_->getName(), detailsPage_->getSelectedGroups())); } else { boost::shared_ptr<UIEvent> event(new RequestChatUIEvent(jid)); eventStream_->send(event); } } int QtUserSearchWindow::nextId() const { switch (currentId()) { case 1: return firstPage_->byJID_->isChecked() ? (type_ == AddContact ? 4 : -1) : 2; case 2: return 3; case 3: return type_ == AddContact ? 4 : -1; case 4: return -1; default: return -1; } } void QtUserSearchWindow::handleFirstPageRadioChange() { if (firstPage_->byJID_->isChecked()) { firstPage_->jid_->setText(""); firstPage_->jid_->setEnabled(true); firstPage_->service_->setEnabled(false); restart(); } else if (firstPage_->byRemoteSearch_->isChecked()) { firstPage_->service_->setEditText(""); firstPage_->jid_->setEnabled(false); firstPage_->service_->setEnabled(true); //firstPage_->jid_->setText(""); restart(); } else { firstPage_->jid_->setEnabled(false); firstPage_->service_->setEnabled(false); restart(); } } void QtUserSearchWindow::handleSearch() { boost::shared_ptr<SearchPayload> search(new SearchPayload()); if (fieldsPage_->getFormWidget()) { search->setForm(fieldsPage_->getFormWidget()->getCompletedForm()); } else { if (fieldsPage_->nickInput_->isEnabled()) { search->setNick(Q2PSTRING(fieldsPage_->nickInput_->text())); } if (fieldsPage_->firstInput_->isEnabled()) { search->setFirst(Q2PSTRING(fieldsPage_->firstInput_->text())); } if (fieldsPage_->lastInput_->isEnabled()) { search->setLast(Q2PSTRING(fieldsPage_->lastInput_->text())); } if (fieldsPage_->emailInput_->isEnabled()) { search->setEMail(Q2PSTRING(fieldsPage_->emailInput_->text())); } } onSearchRequested(search, getServerToSearch()); } +JID QtUserSearchWindow::getContactJID() const { + JID jid; + if (!firstPage_->byJID_->isChecked()) { + if (dynamic_cast<UserSearchModel*>(model_)) { + UserSearchResult* userItem = static_cast<UserSearchResult*>(resultsPage_->results_->currentIndex().internalPointer()); + if (userItem) { /* Remember to leave this if we change to dynamic cast */ + jid = userItem->getJID(); + } + } else { + int row = resultsPage_->results_->currentIndex().row(); + + Form::FormItem item = dynamic_cast<QtFormResultItemModel*>(model_)->getForm()->getItems().at(row); + JID fallbackJid; + foreach(FormField::ref field, item) { + if (boost::dynamic_pointer_cast<JIDSingleFormField>(field)) { + jid = JID(field->getRawValues().at(0)); + break; + } + if (field->getName() == "jid") { + fallbackJid = field->getRawValues().at(0); + } + } + if (!jid.isValid()) { + jid = fallbackJid; + } + } + } + else { + jid = JID(Q2PSTRING(firstPage_->jid_->text())); + } + return jid; +} + void QtUserSearchWindow::show() { clear(); QWidget::show(); } void QtUserSearchWindow::addSavedServices(const std::vector<JID>& services) { firstPage_->service_->clear(); foreach (JID jid, services) { firstPage_->service_->addItem(P2QSTRING(jid.toString())); } firstPage_->service_->clearEditText(); } void QtUserSearchWindow::setSearchFields(boost::shared_ptr<SearchPayload> fields) { fieldsPage_->fetchingThrobber_->hide(); fieldsPage_->fetchingThrobber_->movie()->stop(); fieldsPage_->fetchingLabel_->hide(); fieldsPage_->instructionsLabel_->setText(fields->getInstructions() ? P2QSTRING(fields->getInstructions().get()) : "Enter search terms"); if (fields->getForm()) { fieldsPage_->setFormWidget(new QtFormWidget(fields->getForm(), fieldsPage_)); } else { fieldsPage_->setFormWidget(NULL); bool enabled[8] = {fields->getNick(), fields->getNick(), fields->getFirst(), fields->getFirst(), fields->getLast(), fields->getLast(), fields->getEMail(), fields->getEMail()}; QWidget* legacySearchWidgets[8] = {fieldsPage_->nickInputLabel_, fieldsPage_->nickInput_, fieldsPage_->firstInputLabel_, fieldsPage_->firstInput_, fieldsPage_->lastInputLabel_, fieldsPage_->lastInput_, fieldsPage_->emailInputLabel_, fieldsPage_->emailInput_}; for (int i = 0; i < 8; i++) { legacySearchWidgets[i]->setVisible(enabled[i]); legacySearchWidgets[i]->setEnabled(enabled[i]); } } fieldsPage_->emitCompletenessCheck(); } +void QtUserSearchWindow::setNameSuggestions(const std::vector<std::string>& suggestions) { + if (detailsPage_) { + detailsPage_->setNameSuggestions(suggestions); + } +} + 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; } void QtUserSearchWindow::setResultsForm(Form::ref results) { QtFormResultItemModel *newModel = new QtFormResultItemModel(this); newModel->setForm(results); resultsPage_->results_->setModel(newModel); resultsPage_->results_->setItemDelegate(new QItemDelegate()); resultsPage_->results_->setHeaderHidden(false); resultsPage_->results_->header()->setResizeMode(QHeaderView::ResizeToContents); delete model_; model_ = newModel; } void QtUserSearchWindow::setSelectedService(const JID& jid) { myServer_ = jid; } void QtUserSearchWindow::clearForm() { fieldsPage_->fetchingThrobber_->show(); fieldsPage_->fetchingThrobber_->movie()->start(); fieldsPage_->fetchingLabel_->show(); QWidget* legacySearchWidgets[8] = {fieldsPage_->nickInputLabel_, fieldsPage_->nickInput_, fieldsPage_->firstInputLabel_, fieldsPage_->firstInput_, fieldsPage_->lastInputLabel_, fieldsPage_->lastInput_, fieldsPage_->emailInputLabel_, fieldsPage_->emailInput_}; for (int i = 0; i < 8; i++) { legacySearchWidgets[i]->hide(); if (QLineEdit* edit = qobject_cast<QLineEdit*>(legacySearchWidgets[i])) { edit->clear(); } diff --git a/Swift/QtUI/UserSearch/QtUserSearchWindow.h b/Swift/QtUI/UserSearch/QtUserSearchWindow.h index 4cfe93f..9173ba9 100644 --- a/Swift/QtUI/UserSearch/QtUserSearchWindow.h +++ b/Swift/QtUI/UserSearch/QtUserSearchWindow.h @@ -6,61 +6,64 @@ #pragma once #include <QWizard> #include <set> #include <Swift/QtUI/UserSearch/ui_QtUserSearchWizard.h> #include <Swift/Controllers/UIInterfaces/UserSearchWindow.h> namespace Swift { class UserSearchModel; class UserSearchDelegate; class UserSearchResult; class UIEventStream; class QtUserSearchFirstPage; class QtUserSearchFieldsPage; class QtUserSearchResultsPage; class QtUserSearchDetailsPage; class QtFormResultItemModel; class QtUserSearchWindow : public QWizard, public UserSearchWindow, private Ui::QtUserSearchWizard { Q_OBJECT public: QtUserSearchWindow(UIEventStream* eventStream, UserSearchWindow::Type type, const std::set<std::string>& groups); virtual ~QtUserSearchWindow(); virtual void addSavedServices(const std::vector<JID>& services); 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 setSearchFields(boost::shared_ptr<SearchPayload> fields); + virtual void setNameSuggestions(const std::vector<std::string>& suggestions); + protected: virtual int nextId() const; private slots: void handleFirstPageRadioChange(); virtual void handleCurrentChanged(int); virtual void handleAccepted(); private: void clearForm(); void setError(const QString& error); JID getServerToSearch(); void handleSearch(); + JID getContactJID() const; private: UIEventStream* eventStream_; UserSearchWindow::Type type_; QAbstractItemModel* model_; UserSearchDelegate* delegate_; QtUserSearchFirstPage* firstPage_; QtUserSearchFieldsPage* fieldsPage_; QtUserSearchResultsPage* resultsPage_; QtUserSearchDetailsPage* detailsPage_; JID myServer_; int lastPage_; }; } |