diff options
Diffstat (limited to 'Swift/Controllers/Chat')
| -rw-r--r-- | Swift/Controllers/Chat/ChatController.cpp | 27 | ||||
| -rw-r--r-- | Swift/Controllers/Chat/ChatControllerBase.cpp | 50 | ||||
| -rw-r--r-- | Swift/Controllers/Chat/MUCController.cpp | 123 | ||||
| -rw-r--r-- | Swift/Controllers/Chat/MUCSearchController.h | 1 | ||||
| -rw-r--r-- | Swift/Controllers/Chat/UnitTest/MUCControllerTest.cpp | 16 | 
5 files changed, 138 insertions, 79 deletions
diff --git a/Swift/Controllers/Chat/ChatController.cpp b/Swift/Controllers/Chat/ChatController.cpp index e4ad9c8..6e7825f 100644 --- a/Swift/Controllers/Chat/ChatController.cpp +++ b/Swift/Controllers/Chat/ChatController.cpp @@ -9,6 +9,8 @@  #include <boost/bind.hpp>  #include <stdio.h> +#include <Swift/Controllers/Intl.h> +#include <Swiften/Base/format.h>  #include "Swiften/Avatars/AvatarManager.h"  #include "Swiften/Chat/ChatStateNotifier.h"  #include "Swiften/Chat/ChatStateTracker.h" @@ -18,6 +20,7 @@  #include "Swift/Controllers/UIInterfaces/ChatWindowFactory.h"  #include "Swiften/Client/NickResolver.h"  #include "Swift/Controllers/XMPPEvents/EventController.h" +#include <Swift/Controllers/StatusUtil.h>  namespace Swift { @@ -37,16 +40,16 @@ ChatController::ChatController(const JID& self, StanzaChannel* stanzaChannel, IQ  	nickResolver_->onNickChanged.connect(boost::bind(&ChatController::handleContactNickChanged, this, _1, _2));  	std::string nick = nickResolver_->jidToNick(toJID_);  	chatWindow_->setName(nick); -	std::string startMessage("Starting chat with " + nick); +	std::string startMessage;  	Presence::ref theirPresence;  	if (isInMUC) { -		startMessage += " in chatroom " + contact.toBare().toString(); +		startMessage = str(format(QT_TRANSLATE_NOOP("", "Starting chat with %1% in chatroom %2%")) % nick % contact.toBare().toString());  		theirPresence = presenceOracle->getLastPresence(contact);  	} else { -		startMessage += " - " + contact.toBare().toString(); +		startMessage = str(format(QT_TRANSLATE_NOOP("", "Starting chat with %1% - %2%")) % nick % contact.toBare().toString());  		theirPresence = contact.isBare() ? presenceOracle->getHighestPriorityPresence(contact.toBare()) : presenceOracle->getLastPresence(contact);  	} -	startMessage += ": " + StatusShow::typeToFriendlyName(theirPresence ? theirPresence->getShow() : StatusShow::None); +	startMessage += ": " + statusShowTypeToFriendlyName(theirPresence ? theirPresence->getShow() : StatusShow::None);  	if (theirPresence && !theirPresence->getStatus().empty()) {  		startMessage += " (" + theirPresence->getStatus() + ")";  	} @@ -109,7 +112,7 @@ void ChatController::preSendMessageRequest(boost::shared_ptr<Message> message) {  }  void ChatController::postSendMessage(const std::string& body, boost::shared_ptr<Stanza> sentStanza) { -	std::string id = addMessage(body, "me", true, labelsEnabled_ ? chatWindow_->getSelectedSecurityLabel() : boost::optional<SecurityLabel>(), std::string(avatarManager_->getAvatarPath(selfJID_).string()), boost::posix_time::microsec_clock::universal_time()); +	std::string id = addMessage(body, QT_TRANSLATE_NOOP("", "me"), true, labelsEnabled_ ? chatWindow_->getSelectedSecurityLabel() : boost::optional<SecurityLabel>(), std::string(avatarManager_->getAvatarPath(selfJID_).string()), boost::posix_time::microsec_clock::universal_time());  	if (stanzaChannel_->getStreamManagementEnabled()) {  		chatWindow_->setAckState(id, ChatWindow::Pending);  		unackedStanzas_[sentStanza] = id; @@ -148,19 +151,23 @@ std::string ChatController::senderDisplayNameFromMessage(const JID& from) {  std::string ChatController::getStatusChangeString(boost::shared_ptr<Presence> presence) {  	std::string nick = senderDisplayNameFromMessage(presence->getFrom()); -	std::string response = nick; +	std::string response;  	if (!presence || presence->getType() == Presence::Unavailable || presence->getType() == Presence::Error) { -		response += " has gone offline"; +		response = QT_TRANSLATE_NOOP("", "%1% has gone offline");  	} else if (presence->getType() == Presence::Available) {  		StatusShow::Type show = presence->getShow();  		if (show == StatusShow::Online || show == StatusShow::FFC) { -			response += " has become available"; +			response = QT_TRANSLATE_NOOP("", "%1% has become available");  		} else if (show == StatusShow::Away || show == StatusShow::XA) { -			response += " has gone away"; +			response = QT_TRANSLATE_NOOP("", "%1% has gone away");  		} else if (show == StatusShow::DND) { -			response += " is now busy"; +			response = QT_TRANSLATE_NOOP("", "%1% is now busy");  		}   	} +	if (!response.empty()) { +		response = str(format(response) % nick); +	} +  	if (!presence->getStatus().empty()) {  		response += " (" + presence->getStatus() + ")";  	} diff --git a/Swift/Controllers/Chat/ChatControllerBase.cpp b/Swift/Controllers/Chat/ChatControllerBase.cpp index f70ec81..a970d88 100644 --- a/Swift/Controllers/Chat/ChatControllerBase.cpp +++ b/Swift/Controllers/Chat/ChatControllerBase.cpp @@ -13,6 +13,8 @@  #include <boost/date_time/posix_time/posix_time.hpp>  #include <boost/algorithm/string.hpp> +#include <Swift/Controllers/Intl.h> +#include <Swiften/Base/format.h>  #include "Swiften/Base/String.h"  #include "Swiften/Client/StanzaChannel.h"  #include "Swiften/Elements/Delay.h" @@ -51,7 +53,7 @@ void ChatControllerBase::createDayChangeTimer() {  void ChatControllerBase::handleDayChangeTick() {  	dateChangeTimer_->stop();  	boost::posix_time::ptime now = boost::posix_time::second_clock::local_time(); -	chatWindow_->addSystemMessage("The day is now " + std::string(boost::posix_time::to_iso_extended_string(now)).substr(0,10)); +	chatWindow_->addSystemMessage(str(format(QT_TRANSLATE_NOOP("", "The day is now %1%")) % std::string(boost::posix_time::to_iso_extended_string(now)).substr(0,10)));  	dayTicked();  	createDayChangeTimer();  } @@ -188,34 +190,34 @@ void ChatControllerBase::handleIncomingMessage(boost::shared_ptr<MessageEvent> m  }  std::string ChatControllerBase::getErrorMessage(boost::shared_ptr<ErrorPayload> error) { -	std::string defaultMessage = "Error sending message"; +	std::string defaultMessage = QT_TRANSLATE_NOOP("", "Error sending message");  	if (!error->getText().empty()) {  		return error->getText();  	}  	else {  		switch (error->getCondition()) { -			case ErrorPayload::BadRequest: return "Bad request"; break; -			case ErrorPayload::Conflict: return "Conflict"; break; -			case ErrorPayload::FeatureNotImplemented: return "This feature is not implemented"; break; -			case ErrorPayload::Forbidden: return "Forbidden"; break; -			case ErrorPayload::Gone: return "Recipient can no longer be contacted"; break; -			case ErrorPayload::InternalServerError: return "Internal server error"; break; -			case ErrorPayload::ItemNotFound: return "Item not found"; break; -			case ErrorPayload::JIDMalformed: return "JID Malformed"; break; -			case ErrorPayload::NotAcceptable: return "Message was rejected"; break; -			case ErrorPayload::NotAllowed: return "Not allowed"; break; -			case ErrorPayload::NotAuthorized: return "Not authorized"; break; -			case ErrorPayload::PaymentRequired: return "Payment is required"; break; -			case ErrorPayload::RecipientUnavailable: return "Recipient is unavailable."; break; -			case ErrorPayload::Redirect: return "Redirect"; break; -			case ErrorPayload::RegistrationRequired: return "Registration required"; break; -			case ErrorPayload::RemoteServerNotFound: return "Recipient's server not found."; break; -			case ErrorPayload::RemoteServerTimeout: return "Remote server timeout"; break; -			case ErrorPayload::ResourceConstraint: return "The server is low on resources"; break; -			case ErrorPayload::ServiceUnavailable: return "The service is unavailable"; break; -			case ErrorPayload::SubscriptionRequired: return "A subscription is required"; break; -			case ErrorPayload::UndefinedCondition: return "Undefined condition"; break; -			case ErrorPayload::UnexpectedRequest: return "Unexpected request"; break; +			case ErrorPayload::BadRequest: return QT_TRANSLATE_NOOP("", "Bad request"); break; +			case ErrorPayload::Conflict: return QT_TRANSLATE_NOOP("", "Conflict"); break; +			case ErrorPayload::FeatureNotImplemented: return QT_TRANSLATE_NOOP("", "This feature is not implemented"); break; +			case ErrorPayload::Forbidden: return QT_TRANSLATE_NOOP("", "Forbidden"); break; +			case ErrorPayload::Gone: return QT_TRANSLATE_NOOP("", "Recipient can no longer be contacted"); break; +			case ErrorPayload::InternalServerError: return QT_TRANSLATE_NOOP("", "Internal server error"); break; +			case ErrorPayload::ItemNotFound: return QT_TRANSLATE_NOOP("", "Item not found"); break; +			case ErrorPayload::JIDMalformed: return QT_TRANSLATE_NOOP("", "JID Malformed"); break; +			case ErrorPayload::NotAcceptable: return QT_TRANSLATE_NOOP("", "Message was rejected"); break; +			case ErrorPayload::NotAllowed: return QT_TRANSLATE_NOOP("", "Not allowed"); break; +			case ErrorPayload::NotAuthorized: return QT_TRANSLATE_NOOP("", "Not authorized"); break; +			case ErrorPayload::PaymentRequired: return QT_TRANSLATE_NOOP("", "Payment is required"); break; +			case ErrorPayload::RecipientUnavailable: return QT_TRANSLATE_NOOP("", "Recipient is unavailable"); break; +			case ErrorPayload::Redirect: return QT_TRANSLATE_NOOP("", "Redirect"); break; +			case ErrorPayload::RegistrationRequired: return QT_TRANSLATE_NOOP("", "Registration required"); break; +			case ErrorPayload::RemoteServerNotFound: return QT_TRANSLATE_NOOP("", "Recipient's server not found"); break; +			case ErrorPayload::RemoteServerTimeout: return QT_TRANSLATE_NOOP("", "Remote server timeout"); break; +			case ErrorPayload::ResourceConstraint: return QT_TRANSLATE_NOOP("", "The server is low on resources"); break; +			case ErrorPayload::ServiceUnavailable: return QT_TRANSLATE_NOOP("", "The service is unavailable"); break; +			case ErrorPayload::SubscriptionRequired: return QT_TRANSLATE_NOOP("", "A subscription is required"); break; +			case ErrorPayload::UndefinedCondition: return QT_TRANSLATE_NOOP("", "Undefined condition"); break; +			case ErrorPayload::UnexpectedRequest: return QT_TRANSLATE_NOOP("", "Unexpected request"); break;  		}  	}  	return defaultMessage; diff --git a/Swift/Controllers/Chat/MUCController.cpp b/Swift/Controllers/Chat/MUCController.cpp index 765c49d..ce8c946 100644 --- a/Swift/Controllers/Chat/MUCController.cpp +++ b/Swift/Controllers/Chat/MUCController.cpp @@ -10,6 +10,8 @@  #include <boost/regex.hpp>  #include <boost/algorithm/string.hpp> +#include <Swift/Controllers/Intl.h> +#include <Swiften/Base/format.h>  #include "Swiften/Network/Timer.h"  #include "Swiften/Network/TimerFactory.h"  #include "Swiften/Base/foreach.h" @@ -109,7 +111,7 @@ void MUCController::rejoin() {  void MUCController::handleJoinTimeoutTick() {  	receivedActivity(); -	chatWindow_->addSystemMessage("Room " + toJID_.toString() + " is not responding. This operation may never complete"); +	chatWindow_->addSystemMessage(str(format(QT_TRANSLATE_NOOP("", "Room %1% is not responding. This operation may never complete.")) % toJID_.toString()));  }  void MUCController::receivedActivity() { @@ -120,17 +122,38 @@ void MUCController::receivedActivity() {  void MUCController::handleJoinFailed(boost::shared_ptr<ErrorPayload> error) {  	receivedActivity(); -	std::string errorMessage = "Unable to join this room"; +	std::string errorMessage = QT_TRANSLATE_NOOP("", "Unable to join this room");  	std::string rejoinNick;  	if (error) {  		switch (error->getCondition()) { -		case ErrorPayload::Conflict: rejoinNick = nick_ + "_"; errorMessage += " as " + nick_ + ", retrying as " + rejoinNick; break; -		case ErrorPayload::JIDMalformed: errorMessage += ", no nickname specified";break; -		case ErrorPayload::NotAuthorized: errorMessage += ", a password needed";break; -		case ErrorPayload::RegistrationRequired: errorMessage += ", only members may join"; break; -		case ErrorPayload::Forbidden: errorMessage += ", you are banned from the room"; break; -		case ErrorPayload::ServiceUnavailable: errorMessage += ", the room is full";break; -		case ErrorPayload::ItemNotFound: errorMessage += ", the room does not exist";break; +		case ErrorPayload::Conflict: +			rejoinNick = nick_ + "_"; +			errorMessage = str(format(QT_TRANSLATE_NOOP("", "Unable to join this room as %1%, retrying as %2%")) % nick_ % rejoinNick); +			break; +		case ErrorPayload::JIDMalformed:  +			errorMessage += ": "; +			errorMessage += QT_TRANSLATE_NOOP("", "No nickname specified"); +			break; +		case ErrorPayload::NotAuthorized:  +			errorMessage += ": "; +			errorMessage += QT_TRANSLATE_NOOP("", "A password needed"); +			break; +		case ErrorPayload::RegistrationRequired:  +			errorMessage += ": "; +			errorMessage += QT_TRANSLATE_NOOP("", "Only members may join");  +			break; +		case ErrorPayload::Forbidden:  +			errorMessage += ": "; +			errorMessage += QT_TRANSLATE_NOOP("", "You are banned from the room");  +			break; +		case ErrorPayload::ServiceUnavailable:  +			errorMessage += ": "; +			errorMessage += QT_TRANSLATE_NOOP("", "The room is full"); +			break; +		case ErrorPayload::ItemNotFound:  +			errorMessage += ": "; +			errorMessage += QT_TRANSLATE_NOOP("", "The room does not exist"); +			break;  		default: break;  		} @@ -147,7 +170,7 @@ void MUCController::handleJoinFailed(boost::shared_ptr<ErrorPayload> error) {  void MUCController::handleJoinComplete(const std::string& nick) {  	receivedActivity();  	joined_ = true; -	std::string joinMessage = "You have joined room " + toJID_.toString() + " as " + nick; +	std::string joinMessage = str(format(QT_TRANSLATE_NOOP("", "You have joined room %1% as %2%")) % toJID_.toString() % nick);  	nick_ = nick;  	chatWindow_->addSystemMessage(joinMessage);  	clearPresenceQueue(); @@ -185,13 +208,14 @@ void MUCController::handleOccupantJoined(const MUCOccupant& occupant) {  	appendToJoinParts(joinParts_, event);  	roster_->addContact(jid, realJID, occupant.getNick(), roleToGroupName(occupant.getRole()), avatarManager_->getAvatarPath(jid).string());  	if (joined_) { -		std::string joinString = occupant.getNick() + " has joined the room"; +		std::string joinString;  		MUCOccupant::Role role = occupant.getRole();  		if (role != MUCOccupant::NoRole && role != MUCOccupant::Participant) { -			joinString += " as a " + roleToFriendlyName(role); - +			joinString = str(format(QT_TRANSLATE_NOOP("", "%1% has joined the room as a %2%.")) % occupant.getNick() % roleToFriendlyName(role)); +		} +		else { +			joinString = str(format(QT_TRANSLATE_NOOP("", "%1% has joined the room.")) % occupant.getNick());  		} -		joinString += ".";  		if (shouldUpdateJoinParts()) {  			updateJoinParts();  		} else { @@ -216,9 +240,9 @@ void MUCController::clearPresenceQueue() {  std::string MUCController::roleToFriendlyName(MUCOccupant::Role role) {  	switch (role) { -	case MUCOccupant::Moderator: return "moderator"; -	case MUCOccupant::Participant: return "participant"; -	case MUCOccupant::Visitor: return "visitor"; +	case MUCOccupant::Moderator: return QT_TRANSLATE_NOOP("", "moderator"); +	case MUCOccupant::Participant: return QT_TRANSLATE_NOOP("", "participant"); +	case MUCOccupant::Visitor: return QT_TRANSLATE_NOOP("", "visitor");  	case MUCOccupant::NoRole: return "";  	}  	return ""; @@ -257,7 +281,7 @@ void MUCController::preHandleIncomingMessage(boost::shared_ptr<MessageEvent> mes  	joined_ = true;  	if (!message->getSubject().empty() && message->getBody().empty()) { -		chatWindow_->addSystemMessage("The room subject is now: " + message->getSubject()); +		chatWindow_->addSystemMessage(str(format(QT_TRANSLATE_NOOP("", "The room subject is now: %1%")) % message->getSubject()));;  		doneGettingHistory_ = true;  	} @@ -280,16 +304,16 @@ void MUCController::handleOccupantRoleChanged(const std::string& nick, const MUC  		realJID = occupant.getRealJID().get();  	}  	roster_->addContact(jid, realJID, nick, roleToGroupName(occupant.getRole()), avatarManager_->getAvatarPath(jid).string()); -	chatWindow_->addSystemMessage(nick + " is now a " + roleToFriendlyName(occupant.getRole())); +	chatWindow_->addSystemMessage(str(format(QT_TRANSLATE_NOOP("", "%1% is now a %2%")) % nick % roleToFriendlyName(occupant.getRole())));  }  std::string MUCController::roleToGroupName(MUCOccupant::Role role) {  	std::string result;  	switch (role) { -	case MUCOccupant::Moderator: result = "Moderators"; break; -	case MUCOccupant::Participant: result = "Participants"; break; -	case MUCOccupant::Visitor: result = "Visitors"; break; -	case MUCOccupant::NoRole: result = "Occupants"; break; +	case MUCOccupant::Moderator: result = QT_TRANSLATE_NOOP("", "Moderators"); break; +	case MUCOccupant::Participant: result = QT_TRANSLATE_NOOP("", "Participants"); break; +	case MUCOccupant::Visitor: result = QT_TRANSLATE_NOOP("", "Visitors"); break; +	case MUCOccupant::NoRole: result = QT_TRANSLATE_NOOP("", "Occupants"); break;  	default: assert(false);  	}  	return result; @@ -303,7 +327,7 @@ void MUCController::setOnline(bool online) {  		processUserPart();  	} else {  		if (shouldJoinOnReconnect_) { -			chatWindow_->addSystemMessage("Trying to join room " + toJID_.toString()); +			chatWindow_->addSystemMessage(str(format(QT_TRANSLATE_NOOP("", "Trying to join room %1%")) % toJID_.toString()));  			if (loginCheckTimer_) {  				loginCheckTimer_->start();  			} @@ -332,7 +356,7 @@ void MUCController::handleOccupantLeft(const MUCOccupant& occupant, MUC::Leaving  	appendToJoinParts(joinParts_, event);  	currentOccupants_.erase(occupant.getNick());  	completer_->removeWord(occupant.getNick()); -	std::string partMessage = (occupant.getNick() != nick_) ? occupant.getNick() + " has left the room" : "You have left the room"; +	std::string partMessage = (occupant.getNick() != nick_) ? str(format(QT_TRANSLATE_NOOP("", "%1% has left the room")) % occupant.getNick()) : QT_TRANSLATE_NOOP("", "You have left the room");  	if (!reason.empty()) {  		partMessage += " (" + reason + ")";  	} @@ -406,7 +430,7 @@ std::string MUCController::concatenateListOfNames(const std::vector<NickJoinPart  			if (i < joinParts.size() - 1) {  				result += ", ";  			} else { -				result += " and "; +				result += QT_TRANSLATE_NOOP("", " and ");  			}  		}  		NickJoinPart event = joinParts[i]; @@ -424,17 +448,45 @@ std::string MUCController::generateJoinPartString(const std::vector<NickJoinPart  	std::string result;  	std::vector<JoinPart> populatedEvents;  	for (size_t i = 0; i < 4; i++) { -		std::string eventString = concatenateListOfNames(sorted[i]); -		if (!eventString.empty()) { -			std::string haveHas = sorted[i].size() > 1 ? " have" : " has"; +		std::string names = concatenateListOfNames(sorted[i]); +		if (!names.empty()) { +			std::string eventString;  			switch (i) { -				case Join: eventString += haveHas + " joined";break; -				case Part: eventString += haveHas + " left";break; -				case JoinThenPart: eventString += " joined then left";break; -				case PartThenJoin: eventString += " left then rejoined";break; +				case Join:  +					if (sorted[i].size() > 1) { +						eventString = QT_TRANSLATE_NOOP("", "%1% have joined the room"); +					} +					else { +						eventString = QT_TRANSLATE_NOOP("", "%1% has joined the room"); +					} +					break; +				case Part:  +					if (sorted[i].size() > 1) { +						eventString = QT_TRANSLATE_NOOP("", "%1% have left the room"); +					} +					else { +						eventString = QT_TRANSLATE_NOOP("", "%1% has left the room"); +					} +					break; +				case JoinThenPart:  +					if (sorted[i].size() > 1) { +						eventString = QT_TRANSLATE_NOOP("", "%1% have joined then left the room"); +					} +					else { +						eventString = QT_TRANSLATE_NOOP("", "%1% has joined then left the room"); +					} +					break; +				case PartThenJoin:  +					if (sorted[i].size() > 1) { +						eventString = QT_TRANSLATE_NOOP("", "%1% have left then rejoined the room"); +					} +					else { +						eventString = QT_TRANSLATE_NOOP("", "%1% has left then rejoined the room"); +					} +					break;  			}  			populatedEvents.push_back(static_cast<JoinPart>(i)); -			eventStrings[i] = eventString; +			eventStrings[i] = str(boost::format(eventString) % names);  		}  	}  	for (size_t i = 0; i < populatedEvents.size(); i++) { @@ -442,12 +494,11 @@ std::string MUCController::generateJoinPartString(const std::vector<NickJoinPart  			if (i < populatedEvents.size() - 1) {  				result += ", ";  			} else { -				result += " and "; +				result += QT_TRANSLATE_NOOP("", " and ");  			}  		}  		result += eventStrings[populatedEvents[i]];  	} -	result += " the room.";  	return result;  } diff --git a/Swift/Controllers/Chat/MUCSearchController.h b/Swift/Controllers/Chat/MUCSearchController.h index b348886..c8040ed 100644 --- a/Swift/Controllers/Chat/MUCSearchController.h +++ b/Swift/Controllers/Chat/MUCSearchController.h @@ -16,7 +16,6 @@  #include "Swiften/JID/JID.h"  #include "Swift/Controllers/UIEvents/UIEvent.h" -#include "Swift/Controllers/Chat/MUCSearchController.h"  #include "Swift/Controllers/Settings/SettingsProvider.h"  #include "Swiften/Elements/DiscoInfo.h"  #include "Swiften/Elements/DiscoItems.h" diff --git a/Swift/Controllers/Chat/UnitTest/MUCControllerTest.cpp b/Swift/Controllers/Chat/UnitTest/MUCControllerTest.cpp index 7c7a8b9..e66fa9e 100644 --- a/Swift/Controllers/Chat/UnitTest/MUCControllerTest.cpp +++ b/Swift/Controllers/Chat/UnitTest/MUCControllerTest.cpp @@ -200,25 +200,25 @@ public:  	void testJoinPartStringContructionSimple() {  		std::vector<NickJoinPart> list;  		list.push_back(NickJoinPart("Kev", Join)); -		CPPUNIT_ASSERT_EQUAL(std::string("Kev has joined the room."), MUCController::generateJoinPartString(list)); +		CPPUNIT_ASSERT_EQUAL(std::string("Kev has joined the room"), MUCController::generateJoinPartString(list));  		list.push_back(NickJoinPart("Remko", Part)); -		CPPUNIT_ASSERT_EQUAL(std::string("Kev has joined and Remko has left the room."), MUCController::generateJoinPartString(list)); +		CPPUNIT_ASSERT_EQUAL(std::string("Kev has joined the room and Remko has left the room"), MUCController::generateJoinPartString(list));  		list.push_back(NickJoinPart("Bert", Join)); -		CPPUNIT_ASSERT_EQUAL(std::string("Kev and Bert have joined and Remko has left the room."), MUCController::generateJoinPartString(list)); +		CPPUNIT_ASSERT_EQUAL(std::string("Kev and Bert have joined the room and Remko has left the room"), MUCController::generateJoinPartString(list));  		list.push_back(NickJoinPart("Ernie", Join)); -		CPPUNIT_ASSERT_EQUAL(std::string("Kev, Bert and Ernie have joined and Remko has left the room."), MUCController::generateJoinPartString(list)); +		CPPUNIT_ASSERT_EQUAL(std::string("Kev, Bert and Ernie have joined the room and Remko has left the room"), MUCController::generateJoinPartString(list));  	}  	void testJoinPartStringContructionMixed() {  		std::vector<NickJoinPart> list;  		list.push_back(NickJoinPart("Kev", JoinThenPart)); -		CPPUNIT_ASSERT_EQUAL(std::string("Kev joined then left the room."), MUCController::generateJoinPartString(list)); +		CPPUNIT_ASSERT_EQUAL(std::string("Kev has joined then left the room"), MUCController::generateJoinPartString(list));  		list.push_back(NickJoinPart("Remko", Part)); -		CPPUNIT_ASSERT_EQUAL(std::string("Remko has left and Kev joined then left the room."), MUCController::generateJoinPartString(list)); +		CPPUNIT_ASSERT_EQUAL(std::string("Remko has left the room and Kev has joined then left the room"), MUCController::generateJoinPartString(list));  		list.push_back(NickJoinPart("Bert", PartThenJoin)); -		CPPUNIT_ASSERT_EQUAL(std::string("Remko has left, Kev joined then left and Bert left then rejoined the room."), MUCController::generateJoinPartString(list)); +		CPPUNIT_ASSERT_EQUAL(std::string("Remko has left the room, Kev has joined then left the room and Bert has left then rejoined the room"), MUCController::generateJoinPartString(list));  		list.push_back(NickJoinPart("Ernie", JoinThenPart)); -		CPPUNIT_ASSERT_EQUAL(std::string("Remko has left, Kev and Ernie joined then left and Bert left then rejoined the room."), MUCController::generateJoinPartString(list)); +		CPPUNIT_ASSERT_EQUAL(std::string("Remko has left the room, Kev and Ernie have joined then left the room and Bert has left then rejoined the room"), MUCController::generateJoinPartString(list));  	}  private:  | 
 Swift