summaryrefslogtreecommitdiffstats
path: root/Swift
diff options
context:
space:
mode:
authorRichard Maudsley <richard.maudsley@isode.com>2013-12-16 09:45:40 (GMT)
committerRichard Maudsley <richard.maudsley@isode.com>2013-12-18 14:48:12 (GMT)
commit26994474c1ebfe874c2cd62ededf9a82b0496136 (patch)
tree20feb19c35f438b7789fe0c5113412c87b27b235 /Swift
parent503a8077c8811c2e9f65a619c33690a36eb5c153 (diff)
downloadswift-26994474c1ebfe874c2cd62ededf9a82b0496136.zip
swift-26994474c1ebfe874c2cd62ededf9a82b0496136.tar.bz2
Add affiliations to tooltips for MUC occupant lists.
Also extracts MUC into an interface and MUCImpl the existing implementation, adds a MockMUC for using in unit tests, and adds unit tests for the MUCController changes. Change-Id: I25034384f59d3c274c46ffc37b2d1ae60ec660f4
Diffstat (limited to 'Swift')
-rw-r--r--Swift/Controllers/Chat/MUCController.cpp6
-rw-r--r--Swift/Controllers/Chat/UnitTest/MUCControllerTest.cpp72
-rw-r--r--Swift/Controllers/Roster/ContactRosterItem.cpp40
-rw-r--r--Swift/Controllers/Roster/ContactRosterItem.h11
-rw-r--r--Swift/Controllers/Roster/ItemOperations/SetMUC.h39
-rw-r--r--Swift/Controllers/UnitTest/MockChatWindow.h4
-rw-r--r--Swift/QtUI/Roster/RosterTooltip.cpp9
7 files changed, 174 insertions, 7 deletions
diff --git a/Swift/Controllers/Chat/MUCController.cpp b/Swift/Controllers/Chat/MUCController.cpp
index afcb782..14d1767 100644
--- a/Swift/Controllers/Chat/MUCController.cpp
+++ b/Swift/Controllers/Chat/MUCController.cpp
@@ -32,6 +32,7 @@
#include <Swift/Controllers/Roster/GroupRosterItem.h>
#include <Swift/Controllers/Roster/ItemOperations/SetAvatar.h>
#include <Swift/Controllers/Roster/ItemOperations/SetPresence.h>
+#include <Swift/Controllers/Roster/ItemOperations/SetMUC.h>
#include <Swift/Controllers/Roster/Roster.h>
#include <Swift/Controllers/Roster/RosterVCardProvider.h>
#include <Swift/Controllers/UIEvents/InviteToMUCUIEvent.h>
@@ -385,6 +386,7 @@ void MUCController::handleOccupantJoined(const MUCOccupant& occupant) {
appendToJoinParts(joinParts_, event);
std::string groupName(roleToGroupName(occupant.getRole()));
roster_->addContact(jid, realJID, occupant.getNick(), groupName, avatarManager_->getAvatarPath(jid));
+ roster_->applyOnItems(SetMUC(jid, occupant.getRole(), occupant.getAffiliation()));
roster_->getGroup(groupName)->setManualSort(roleToSortName(occupant.getRole()));
if (joined_) {
std::string joinString;
@@ -537,6 +539,7 @@ void MUCController::handleOccupantRoleChanged(const std::string& nick, const MUC
std::string group(roleToGroupName(occupant.getRole()));
roster_->addContact(jid, realJID, nick, group, avatarManager_->getAvatarPath(jid));
roster_->getGroup(group)->setManualSort(roleToSortName(occupant.getRole()));
+ roster_->applyOnItems(SetMUC(jid, occupant.getRole(), occupant.getAffiliation()));
chatWindow_->addSystemMessage(chatMessageParser_->parseMessageBody(str(format(QT_TRANSLATE_NOOP("", "%1% is now a %2%")) % nick % roleToFriendlyName(occupant.getRole()))), ChatWindow::DefaultDirection);
if (nick == nick_) {
setAvailableRoomActions(occupant.getAffiliation(), occupant.getRole());
@@ -548,6 +551,9 @@ void MUCController::handleOccupantAffiliationChanged(const std::string& nick, co
if (nick == nick_) {
setAvailableRoomActions(affiliation, muc_->getOccupant(nick_).getRole());
}
+ JID jid(nickToJID(nick));
+ MUCOccupant occupant = muc_->getOccupant(nick);
+ roster_->applyOnItems(SetMUC(jid, occupant.getRole(), affiliation));
}
std::string MUCController::roleToGroupName(MUCOccupant::Role role) {
diff --git a/Swift/Controllers/Chat/UnitTest/MUCControllerTest.cpp b/Swift/Controllers/Chat/UnitTest/MUCControllerTest.cpp
index 291fb22..3652e86 100644
--- a/Swift/Controllers/Chat/UnitTest/MUCControllerTest.cpp
+++ b/Swift/Controllers/Chat/UnitTest/MUCControllerTest.cpp
@@ -9,6 +9,7 @@
#include <boost/algorithm/string.hpp>
#include <hippomocks.h>
+#include "Swiften/Base/foreach.h"
#include "Swift/Controllers/XMPPEvents/EventController.h"
#include "Swiften/Presence/DirectedPresenceSender.h"
#include "Swiften/Presence/StanzaChannelPresenceSender.h"
@@ -20,6 +21,7 @@
#include "Swiften/Roster/XMPPRoster.h"
#include "Swift/Controllers/UIEvents/UIEventStream.h"
#include "Swift/Controllers/UnitTest/MockChatWindow.h"
+#include "Swiften/MUC/UnitTest/MockMUC.h"
#include "Swiften/Client/DummyStanzaChannel.h"
#include "Swiften/Queries/DummyIQChannel.h"
#include "Swiften/Presence/PresenceOracle.h"
@@ -33,6 +35,8 @@
#include <Swift/Controllers/Chat/ChatMessageParser.h>
#include <Swift/Controllers/Chat/UserSearchController.h>
#include <Swift/Controllers/UIInterfaces/UserSearchWindowFactory.h>
+#include <Swift/Controllers/Roster/Roster.h>
+#include <Swift/Controllers/Roster/GroupRosterItem.h>
#include <Swiften/Crypto/CryptoProvider.h>
using namespace Swift;
@@ -48,6 +52,7 @@ class MUCControllerTest : public CppUnit::TestFixture {
CPPUNIT_TEST(testMessageWithEmptyLabelItem);
CPPUNIT_TEST(testMessageWithLabelItem);
CPPUNIT_TEST(testCorrectMessageWithLabelItem);
+ CPPUNIT_TEST(testRoleAffiliationStates);
CPPUNIT_TEST_SUITE_END();
public:
@@ -74,7 +79,7 @@ public:
entityCapsProvider_ = new DummyEntityCapsProvider();
settings_ = new DummySettingsProvider();
highlightManager_ = new HighlightManager(settings_);
- muc_ = boost::make_shared<MUC>(stanzaChannel_, iqRouter_, directedPresenceSender_, mucJID_, mucRegistry_);
+ muc_ = boost::make_shared<MockMUC>(mucJID_);
mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With(muc_->getJID(), uiEventStream_).Return(window_);
chatMessageParser_ = new ChatMessageParser(std::map<std::string, std::string>());
vcardStorage_ = new VCardMemoryStorage(crypto_.get());
@@ -337,10 +342,73 @@ public:
CPPUNIT_ASSERT_EQUAL(std::string("Remko has left the room, Kev and Ernie have entered then left the room and Bert has left then returned to the room"), MUCController::generateJoinPartString(list, false));
}
+ JID jidFromOccupant(const MUCOccupant& occupant) {
+ return JID(mucJID_.toString()+"/"+occupant.getNick());
+ }
+
+ void testRoleAffiliationStates() {
+
+ typedef std::map<std::string, MUCOccupant> occupant_map;
+ occupant_map occupants;
+ occupants.insert(occupant_map::value_type("Kev", MUCOccupant("Kev", MUCOccupant::Participant, MUCOccupant::Owner)));
+ occupants.insert(occupant_map::value_type("Remko", MUCOccupant("Remko", MUCOccupant::Participant, MUCOccupant::Owner)));
+ occupants.insert(occupant_map::value_type("Bert", MUCOccupant("Bert", MUCOccupant::Participant, MUCOccupant::Owner)));
+ occupants.insert(occupant_map::value_type("Ernie", MUCOccupant("Ernie", MUCOccupant::Participant, MUCOccupant::Owner)));
+
+ /* populate the MUC with fake users */
+ typedef const std::pair<std::string,MUCOccupant> occupantIterator;
+ foreach(occupantIterator &occupant, occupants) {
+ muc_->insertOccupant(occupant.second);
+ }
+
+ std::vector<MUCOccupant> alterations;
+ alterations.push_back(MUCOccupant("Kev", MUCOccupant::Visitor, MUCOccupant::Admin));
+ alterations.push_back(MUCOccupant("Remko", MUCOccupant::Moderator, MUCOccupant::Member));
+ alterations.push_back(MUCOccupant("Bert", MUCOccupant::Visitor, MUCOccupant::Outcast));
+ alterations.push_back(MUCOccupant("Ernie", MUCOccupant::NoRole, MUCOccupant::Member));
+ alterations.push_back(MUCOccupant("Bert", MUCOccupant::Moderator, MUCOccupant::Owner));
+ alterations.push_back(MUCOccupant("Kev", MUCOccupant::Participant, MUCOccupant::Outcast));
+ alterations.push_back(MUCOccupant("Bert", MUCOccupant::Visitor, MUCOccupant::NoAffiliation));
+ alterations.push_back(MUCOccupant("Remko", MUCOccupant::NoRole, MUCOccupant::NoAffiliation));
+ alterations.push_back(MUCOccupant("Ernie", MUCOccupant::Visitor, MUCOccupant::Outcast));
+
+ foreach(const MUCOccupant& alteration, alterations) {
+ /* perform an alteration to a user's role and affiliation */
+ occupant_map::iterator occupant = occupants.find(alteration.getNick());
+ CPPUNIT_ASSERT(occupant != occupants.end());
+ const JID jid = jidFromOccupant(occupant->second);
+ /* change the affiliation, leave the role in place */
+ muc_->changeAffiliation(jid, alteration.getAffiliation());
+ occupant->second = MUCOccupant(occupant->first, occupant->second.getRole(), alteration.getAffiliation());
+ testRoleAffiliationStatesVerify(occupants);
+ /* change the role, leave the affiliation in place */
+ muc_->changeOccupantRole(jid, alteration.getRole());
+ occupant->second = MUCOccupant(occupant->first, alteration.getRole(), occupant->second.getAffiliation());
+ testRoleAffiliationStatesVerify(occupants);
+ }
+ }
+
+ void testRoleAffiliationStatesVerify(const std::map<std::string, MUCOccupant> &occupants) {
+ /* verify that the roster is in sync */
+ GroupRosterItem* group = window_->getRosterModel()->getRoot();
+ foreach(RosterItem* rosterItem, group->getChildren()) {
+ GroupRosterItem* child = dynamic_cast<GroupRosterItem*>(rosterItem);
+ CPPUNIT_ASSERT(child);
+ foreach(RosterItem* childItem, child->getChildren()) {
+ ContactRosterItem* item = dynamic_cast<ContactRosterItem*>(childItem);
+ CPPUNIT_ASSERT(item);
+ std::map<std::string, MUCOccupant>::const_iterator occupant = occupants.find(item->getJID().getResource());
+ CPPUNIT_ASSERT(occupant != occupants.end());
+ CPPUNIT_ASSERT(item->getMUCRole() == occupant->second.getRole());
+ CPPUNIT_ASSERT(item->getMUCAffiliation() == occupant->second.getAffiliation());
+ }
+ }
+ }
+
private:
JID self_;
JID mucJID_;
- MUC::ref muc_;
+ MockMUC::ref muc_;
std::string nick_;
DummyStanzaChannel* stanzaChannel_;
DummyIQChannel* iqChannel_;
diff --git a/Swift/Controllers/Roster/ContactRosterItem.cpp b/Swift/Controllers/Roster/ContactRosterItem.cpp
index 622b6ae..fde4c97 100644
--- a/Swift/Controllers/Roster/ContactRosterItem.cpp
+++ b/Swift/Controllers/Roster/ContactRosterItem.cpp
@@ -11,13 +11,15 @@
#include <Swiften/Base/foreach.h>
#include <Swiften/Base/DateTime.h>
#include <Swiften/Elements/Idle.h>
-
+#include <Swift/Controllers/Intl.h>
#include <Swift/Controllers/Roster/GroupRosterItem.h>
namespace Swift {
-ContactRosterItem::ContactRosterItem(const JID& jid, const JID& displayJID, const std::string& name, GroupRosterItem* parent) : RosterItem(name, parent), jid_(jid), displayJID_(displayJID), blockState_(BlockingNotSupported) {
+ContactRosterItem::ContactRosterItem(const JID& jid, const JID& displayJID, const std::string& name, GroupRosterItem* parent)
+: RosterItem(name, parent), jid_(jid), displayJID_(displayJID), mucRole_(MUCOccupant::NoRole), mucAffiliation_(MUCOccupant::NoAffiliation), blockState_(BlockingNotSupported)
+{
}
ContactRosterItem::~ContactRosterItem() {
@@ -137,6 +139,40 @@ void ContactRosterItem::removeGroup(const std::string& group) {
groups_.erase(std::remove(groups_.begin(), groups_.end(), group), groups_.end());
}
+MUCOccupant::Role ContactRosterItem::getMUCRole() const
+{
+ return mucRole_;
+}
+
+void ContactRosterItem::setMUCRole(const MUCOccupant::Role& role)
+{
+ mucRole_ = role;
+}
+
+MUCOccupant::Affiliation ContactRosterItem::getMUCAffiliation() const
+{
+ return mucAffiliation_;
+}
+
+void ContactRosterItem::setMUCAffiliation(const MUCOccupant::Affiliation& affiliation)
+{
+ mucAffiliation_ = affiliation;
+}
+
+std::string ContactRosterItem::getMUCAffiliationText() const
+{
+ std::string affiliationString;
+ switch (mucAffiliation_) {
+ case MUCOccupant::Owner: affiliationString = QT_TRANSLATE_NOOP("", "Owner"); break;
+ case MUCOccupant::Admin: affiliationString = QT_TRANSLATE_NOOP("", "Admin"); break;
+ case MUCOccupant::Member: affiliationString = QT_TRANSLATE_NOOP("", "Member"); break;
+ case MUCOccupant::Outcast: affiliationString = QT_TRANSLATE_NOOP("", "Outcast"); break;
+ case MUCOccupant::NoAffiliation: affiliationString = ""; break;
+ }
+
+ return affiliationString;
+}
+
void ContactRosterItem::setSupportedFeatures(const std::set<Feature>& features) {
features_ = features;
onDataChanged();
diff --git a/Swift/Controllers/Roster/ContactRosterItem.h b/Swift/Controllers/Roster/ContactRosterItem.h
index 6de7909..ab10c66 100644
--- a/Swift/Controllers/Roster/ContactRosterItem.h
+++ b/Swift/Controllers/Roster/ContactRosterItem.h
@@ -18,6 +18,7 @@
#include <Swiften/Base/boost_bsignals.h>
#include <Swiften/Elements/Presence.h>
#include <Swiften/Elements/StatusShow.h>
+#include <Swiften/Elements/MUCOccupant.h>
#include <Swiften/Elements/VCard.h>
#include <Swiften/JID/JID.h>
@@ -61,7 +62,13 @@ class ContactRosterItem : public RosterItem {
/** Only used so a contact can know about the groups it's in*/
void addGroup(const std::string& group);
void removeGroup(const std::string& group);
-
+
+ MUCOccupant::Role getMUCRole() const;
+ void setMUCRole(const MUCOccupant::Role& role);
+ MUCOccupant::Affiliation getMUCAffiliation() const;
+ void setMUCAffiliation(const MUCOccupant::Affiliation& affiliation);
+ std::string getMUCAffiliationText() const;
+
void setSupportedFeatures(const std::set<Feature>& features);
bool supportsFeature(Feature feature) const;
@@ -82,6 +89,8 @@ class ContactRosterItem : public RosterItem {
boost::shared_ptr<Presence> offlinePresence_;
boost::shared_ptr<Presence> shownPresence_;
std::vector<std::string> groups_;
+ MUCOccupant::Role mucRole_;
+ MUCOccupant::Affiliation mucAffiliation_;
std::set<Feature> features_;
BlockState blockState_;
VCard::ref vcard_;
diff --git a/Swift/Controllers/Roster/ItemOperations/SetMUC.h b/Swift/Controllers/Roster/ItemOperations/SetMUC.h
new file mode 100644
index 0000000..de40e04
--- /dev/null
+++ b/Swift/Controllers/Roster/ItemOperations/SetMUC.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2013 Kevin Smith and Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#pragma once
+
+#include <Swiften/JID/JID.h>
+
+#include <Swift/Controllers/Roster/ItemOperations/RosterItemOperation.h>
+#include <Swift/Controllers/Roster/ContactRosterItem.h>
+
+namespace Swift {
+
+class RosterItem;
+
+class SetMUC : public RosterItemOperation {
+ public:
+ SetMUC(const JID& jid, const MUCOccupant::Role& role, const MUCOccupant::Affiliation& affiliation)
+ : RosterItemOperation(true, jid), jid_(jid), mucRole_(role), mucAffiliation_(affiliation) {
+ }
+
+ virtual void operator() (RosterItem* item) const {
+ ContactRosterItem* contact = dynamic_cast<ContactRosterItem*>(item);
+ if (contact && contact->getJID().equals(jid_, JID::WithResource)) {
+ contact->setMUCRole(mucRole_);
+ contact->setMUCAffiliation(mucAffiliation_);
+ }
+ }
+
+ private:
+ JID jid_;
+ bool mucParticipant_;
+ MUCOccupant::Role mucRole_;
+ MUCOccupant::Affiliation mucAffiliation_;
+};
+
+}
diff --git a/Swift/Controllers/UnitTest/MockChatWindow.h b/Swift/Controllers/UnitTest/MockChatWindow.h
index 43779c5..59ed0f1 100644
--- a/Swift/Controllers/UnitTest/MockChatWindow.h
+++ b/Swift/Controllers/UnitTest/MockChatWindow.h
@@ -49,7 +49,8 @@ namespace Swift {
virtual void setSecurityLabelsError() {}
virtual SecurityLabelsCatalog::Item getSelectedSecurityLabel() {return label_;}
virtual void setInputEnabled(bool /*enabled*/) {}
- virtual void setRosterModel(Roster* /*roster*/) {}
+ virtual void setRosterModel(Roster* roster) { roster_ = roster; }
+ Roster* getRosterModel() { return roster_; }
virtual void setTabComplete(TabComplete*) {}
void setAckState(const std::string& /*id*/, AckState /*state*/) {}
@@ -86,6 +87,7 @@ namespace Swift {
std::vector<SecurityLabelsCatalog::Item> labels_;
bool labelsEnabled_;
SecurityLabelsCatalog::Item label_;
+ Roster* roster_;
};
}
diff --git a/Swift/QtUI/Roster/RosterTooltip.cpp b/Swift/QtUI/Roster/RosterTooltip.cpp
index edf9c99..045a955 100644
--- a/Swift/QtUI/Roster/RosterTooltip.cpp
+++ b/Swift/QtUI/Roster/RosterTooltip.cpp
@@ -39,6 +39,7 @@ QString RosterTooltip::buildDetailedTooltip(ContactRosterItem* contact, QtScaled
"%6"
"%7"
"%8"
+ "%9"
"</td>"
"</tr>"
"</table>");
@@ -55,6 +56,7 @@ QString RosterTooltip::buildDetailedTooltip(ContactRosterItem* contact, QtScaled
"%6"
"%7"
"%8"
+ "%9"
"</td>"
"</tr>"
"</table>");
@@ -97,7 +99,12 @@ QString RosterTooltip::buildDetailedTooltip(ContactRosterItem* contact, QtScaled
lastSeen = htmlEscape(lastSeen) + "<br/>";
}
- return tooltipTemplate.arg(scaledAvatarPath, htmlEscape(fullName), htmlEscape(bareJID), presenceIconTag, htmlEscape(statusMessage), idleString, lastSeen, vCardSummary);
+ QString mucOccupant= P2QSTRING(contact->getMUCAffiliationText());
+ if (!mucOccupant.isEmpty()) {
+ mucOccupant = htmlEscape(mucOccupant) + "<br/>";
+ }
+
+ return tooltipTemplate.arg(scaledAvatarPath, htmlEscape(fullName), htmlEscape(bareJID), presenceIconTag, htmlEscape(statusMessage), mucOccupant, idleString, lastSeen, vCardSummary);
}
QString RosterTooltip::buildVCardSummary(VCard::ref vcard) {