From 1e61cace31a3395f5470a03c3bcf2b7f32d79d03 Mon Sep 17 00:00:00 2001
From: Mateusz Piekos <mateuszpiekos@gmail.com>
Date: Sat, 31 Mar 2012 18:34:53 +0200
Subject: Made MUC context options role-aware

License: This patch is BSD-licensed, see Documentation/Licenses/BSD-simplified.txt for details.

diff --git a/Swift/Controllers/Chat/MUCController.cpp b/Swift/Controllers/Chat/MUCController.cpp
index fd37d27..52cd262 100644
--- a/Swift/Controllers/Chat/MUCController.cpp
+++ b/Swift/Controllers/Chat/MUCController.cpp
@@ -86,6 +86,7 @@ MUCController::MUCController (
 	muc_->onOccupantPresenceChange.connect(boost::bind(&MUCController::handleOccupantPresenceChange, this, _1));
 	muc_->onOccupantLeft.connect(boost::bind(&MUCController::handleOccupantLeft, this, _1, _2, _3));
 	muc_->onOccupantRoleChanged.connect(boost::bind(&MUCController::handleOccupantRoleChanged, this, _1, _2, _3));
+	muc_->onOccupantAffiliationChanged.connect(boost::bind(&MUCController::handleOccupantAffiliationChanged, this, _1, _2, _3));
 	muc_->onConfigurationFailed.connect(boost::bind(&MUCController::handleConfigurationFailed, this, _1));
 	muc_->onConfigurationFormReceived.connect(boost::bind(&MUCController::handleConfigurationFormReceived, this, _1));
 	muc_->onRoleChangeFailed.connect(boost::bind(&MUCController::handleOccupantRoleChangeFailed, this, _1, _2, _3));
@@ -115,14 +116,21 @@ 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);
+		MUCOccupant::Affiliation affiliation = muc_->getOccupant(getNick()).getAffiliation();
+		MUCOccupant::Role role = muc_->getOccupant(getNick()).getRole();
+		if (role == MUCOccupant::Moderator)
+		{
+			if (affiliation == MUCOccupant::Admin || affiliation == MUCOccupant::Owner) {
+				actions.push_back(ChatWindow::Ban);
+			}
 
+			actions.push_back(ChatWindow::Kick);
+			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);
@@ -259,6 +267,8 @@ void MUCController::handleJoinComplete(const std::string& nick) {
 	clearPresenceQueue();
 	shouldJoinOnReconnect_ = true;
 	setEnabled(true);
+	MUCOccupant occupant = muc_->getOccupant(nick);
+	setAvailableRoomActions(occupant.getAffiliation(), occupant.getRole());
 	onUserJoined();
 }
 
@@ -319,6 +329,29 @@ void MUCController::addPresenceMessage(const std::string& message) {
 	chatWindow_->addPresenceMessage(message);
 }
 
+
+void MUCController::setAvailableRoomActions(const MUCOccupant::Affiliation& affiliation, const MUCOccupant::Role& role)
+{
+	std::vector<ChatWindow::RoomAction> actions;
+
+	if (role <= MUCOccupant::Participant) {
+		actions.push_back(ChatWindow::ChangeSubject);
+	}
+	if (affiliation == MUCOccupant::Owner) {
+		actions.push_back(ChatWindow::Configure);
+	}
+	if (affiliation <= MUCOccupant::Admin) {
+		actions.push_back(ChatWindow::Affiliations);
+	}
+	if (affiliation == MUCOccupant::Owner) {
+		actions.push_back(ChatWindow::Destroy);
+	}
+	if (role <= MUCOccupant::Visitor) {
+		actions.push_back(ChatWindow::Invite);
+	}
+	chatWindow_->setAvailableRoomActions(actions);
+}
+
 void MUCController::clearPresenceQueue() {
 	lastWasPresence_ = false;
 	joinParts_.clear();
@@ -410,6 +443,16 @@ void MUCController::handleOccupantRoleChanged(const std::string& nick, const MUC
 	roster_->addContact(jid, realJID, nick, group, avatarManager_->getAvatarPath(jid).string());
 	roster_->getGroup(group)->setManualSort(roleToSortName(occupant.getRole()));
 	chatWindow_->addSystemMessage(str(format(QT_TRANSLATE_NOOP("", "%1% is now a %2%")) % nick % roleToFriendlyName(occupant.getRole())));
+	if (nick == nick_) {
+		setAvailableRoomActions(occupant.getAffiliation(), occupant.getRole());
+	}
+}
+
+void MUCController::handleOccupantAffiliationChanged(const std::string& nick, const MUCOccupant::Affiliation& affiliation, const MUCOccupant::Affiliation& oldAffiliation)
+{
+	if (nick == nick_) {
+		setAvailableRoomActions(affiliation, muc_->getOccupant(nick_).getRole());
+	}
 }
 
 std::string MUCController::roleToGroupName(MUCOccupant::Role role) {
diff --git a/Swift/Controllers/Chat/MUCController.h b/Swift/Controllers/Chat/MUCController.h
index 16dcb99..6906f81 100644
--- a/Swift/Controllers/Chat/MUCController.h
+++ b/Swift/Controllers/Chat/MUCController.h
@@ -63,6 +63,7 @@ namespace Swift {
 			void postHandleIncomingMessage(boost::shared_ptr<MessageEvent>);
 
 		private:
+			void setAvailableRoomActions(const MUCOccupant::Affiliation& affiliation, const MUCOccupant::Role& role);
 			void clearPresenceQueue();
 			void addPresenceMessage(const std::string& message);
 			void handleWindowOccupantSelectionChanged(ContactRosterItem* item);
@@ -73,6 +74,7 @@ namespace Swift {
 			void handleOccupantLeft(const MUCOccupant& occupant, MUC::LeavingType type, const std::string& reason);
 			void handleOccupantPresenceChange(boost::shared_ptr<Presence> presence);
 			void handleOccupantRoleChanged(const std::string& nick, const MUCOccupant& occupant,const MUCOccupant::Role& oldRole);
+			void handleOccupantAffiliationChanged(const std::string& nick, const MUCOccupant::Affiliation& affiliation,const MUCOccupant::Affiliation& oldAffiliation);
 			void handleJoinComplete(const std::string& nick);
 			void handleJoinFailed(boost::shared_ptr<ErrorPayload> error);
 			void handleJoinTimeoutTick();
diff --git a/Swift/Controllers/UIInterfaces/ChatWindow.h b/Swift/Controllers/UIInterfaces/ChatWindow.h
index acf2381..e7246c6 100644
--- a/Swift/Controllers/UIInterfaces/ChatWindow.h
+++ b/Swift/Controllers/UIInterfaces/ChatWindow.h
@@ -35,6 +35,7 @@ namespace Swift {
 			enum ReceiptState {ReceiptRequested, ReceiptReceived};
 			enum Tristate {Yes, No, Maybe};
 			enum OccupantAction {Kick, Ban, MakeModerator, MakeParticipant, MakeVisitor, AddContact};
+			enum RoomAction {ChangeSubject, Configure, Affiliations, Destroy, Invite};
 			enum FileTransferState {WaitingForAccept, Negotiating, Transferring, Canceled, Finished, FTFailed};
 			ChatWindow() {}
 			virtual ~ChatWindow() {};
@@ -81,7 +82,7 @@ namespace Swift {
 			virtual void flash() = 0;
 			virtual void setSubject(const std::string& subject) = 0;
 			virtual void setAffiliations(MUCOccupant::Affiliation, const std::vector<JID>&) = 0;
-
+			virtual void setAvailableRoomActions(const std::vector<RoomAction> &actions) = 0;
 			/**
 			 * Set an alert on the window.
 			 * @param alertText Description of alert (required).
diff --git a/Swift/Controllers/UnitTest/MockChatWindow.h b/Swift/Controllers/UnitTest/MockChatWindow.h
index ce012c6..dab1e90 100644
--- a/Swift/Controllers/UnitTest/MockChatWindow.h
+++ b/Swift/Controllers/UnitTest/MockChatWindow.h
@@ -52,6 +52,7 @@ namespace Swift {
 			virtual void showRoomConfigurationForm(Form::ref) {}
 			virtual void addMUCInvitation(const JID& /*jid*/, const std::string& /*reason*/, const std::string& /*password*/, bool = true) {};
 			virtual void setAffiliations(MUCOccupant::Affiliation, const std::vector<JID>&) {}
+			virtual void setAvailableRoomActions(const std::vector<RoomAction> &) {};
 
 			std::string name_;
 			std::string lastMessageBody_;
diff --git a/Swift/QtUI/QtChatWindow.cpp b/Swift/QtUI/QtChatWindow.cpp
index dc89c21..c6519ba 100644
--- a/Swift/QtUI/QtChatWindow.cpp
+++ b/Swift/QtUI/QtChatWindow.cpp
@@ -732,11 +732,24 @@ void QtChatWindow::setSubject(const std::string& subject) {
 
 void QtChatWindow::handleActionButtonClicked() {
 	QMenu contextMenu;
-	QAction* changeSubject = contextMenu.addAction(tr("Change subject"));
-	QAction* configure = contextMenu.addAction(tr("Configure room"));
-	QAction* affiliations = contextMenu.addAction(tr("Edit affiliations"));
-	QAction* destroy = contextMenu.addAction(tr("Destroy room"));
-	QAction* invite = contextMenu.addAction(tr("Invite person to this room"));
+	QAction* changeSubject = NULL;
+	QAction* configure = NULL;
+	QAction* affiliations = NULL;
+	QAction* destroy = NULL;
+	QAction* invite = NULL;
+
+	foreach(ChatWindow::RoomAction availableAction, availableRoomActions_)
+	{
+		switch(availableAction)
+		{
+			case ChatWindow::ChangeSubject: changeSubject = contextMenu.addAction(tr("Change subject")); break;
+			case ChatWindow::Configure: configure = contextMenu.addAction(tr("Configure room")); break;
+			case ChatWindow::Affiliations: affiliations = contextMenu.addAction(tr("Edit affiliations")); break;
+			case ChatWindow::Destroy: destroy = contextMenu.addAction(tr("Destroy room")); break;
+			case ChatWindow::Invite: invite = contextMenu.addAction(tr("Invite person to this room")); break;
+		}
+	}
+
 	QAction* result = contextMenu.exec(QCursor::pos());
 	if (result == changeSubject) {
 		bool ok;
@@ -785,6 +798,11 @@ void QtChatWindow::setAffiliations(MUCOccupant::Affiliation affiliation, const s
 	affiliationEditor_->setAffiliations(affiliation, jids);
 }
 
+void QtChatWindow::setAvailableRoomActions(const std::vector<RoomAction> &actions)
+{
+	availableRoomActions_ = actions;
+}
+
 void QtChatWindow::showRoomConfigurationForm(Form::ref form) {
 	if (mucConfigurationWindow_) {
 		delete mucConfigurationWindow_.data();
diff --git a/Swift/QtUI/QtChatWindow.h b/Swift/QtUI/QtChatWindow.h
index 9203068..189a12a 100644
--- a/Swift/QtUI/QtChatWindow.h
+++ b/Swift/QtUI/QtChatWindow.h
@@ -79,6 +79,7 @@ namespace Swift {
 			void showRoomConfigurationForm(Form::ref);
 			void addMUCInvitation(const JID& jid, const std::string& reason, const std::string& password, bool direct = true);
 			void setAffiliations(MUCOccupant::Affiliation, const std::vector<JID>&);
+			void setAvailableRoomActions(const std::vector<RoomAction> &actions);
 
 		public slots:
 			void handleChangeSplitterState(QByteArray state);
@@ -163,5 +164,6 @@ namespace Swift {
 			QPointer<QtAffiliationEditor> affiliationEditor_;
 			int idCounter_;
 			SettingsProvider* settings_;
+			std::vector<ChatWindow::RoomAction> availableRoomActions_;
 	};
 }
-- 
cgit v0.10.2-6-g49f6