From c9275affd040ee1ca7c1d599b28df3b363bef888 Mon Sep 17 00:00:00 2001
From: Richard Maudsley <richard.maudsley@isode.com>
Date: Fri, 14 Mar 2014 14:15:34 +0000
Subject: Make the impromptu MUCs behave more like a regular chat.

This hides occupant types in the participant list and initiates a
direct 1-to-1 on occupant double-click instead of MUC-proxied 1-to-1.

Change-Id: I76c57fe52beb3e4236524c1d8cfbd583d3dc3f62

diff --git a/Swift/Controllers/Chat/MUCController.cpp b/Swift/Controllers/Chat/MUCController.cpp
index 14d1767..f83a772 100644
--- a/Swift/Controllers/Chat/MUCController.cpp
+++ b/Swift/Controllers/Chat/MUCController.cpp
@@ -104,8 +104,6 @@ MUCController::MUCController (
 	muc_->onOccupantJoined.connect(boost::bind(&MUCController::handleOccupantJoined, this, _1));
 	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_->onRoleChangeFailed.connect(boost::bind(&MUCController::handleOccupantRoleChangeFailed, this, _1, _2, _3));
 	muc_->onAffiliationListReceived.connect(boost::bind(&MUCController::handleAffiliationListReceived, this, _1, _2));
 	muc_->onConfigurationFailed.connect(boost::bind(&MUCController::handleConfigurationFailed, this, _1));
@@ -119,9 +117,11 @@ MUCController::MUCController (
 	}
 	if (isImpromptu) {
 		muc_->onUnlocked.connect(boost::bind(&MUCController::handleRoomUnlocked, this));
-		chatWindow_->convertToMUC(true);
+		chatWindow_->convertToMUC(ChatWindow::ImpromptuMUC);
 	} else {
-		chatWindow_->convertToMUC();
+		muc_->onOccupantRoleChanged.connect(boost::bind(&MUCController::handleOccupantRoleChanged, this, _1, _2, _3));
+		muc_->onOccupantAffiliationChanged.connect(boost::bind(&MUCController::handleOccupantAffiliationChanged, this, _1, _2, _3));
+		chatWindow_->convertToMUC(ChatWindow::StandardMUC);
 		chatWindow_->setName(muc->getJID().getNode());
 	}
 	setOnline(true);
@@ -154,7 +154,7 @@ void MUCController::handleWindowOccupantSelectionChanged(ContactRosterItem* item
 	if (item) {
 		MUCOccupant::Affiliation affiliation = muc_->getOccupant(getNick()).getAffiliation();
 		MUCOccupant::Role role = muc_->getOccupant(getNick()).getRole();
-		if (role == MUCOccupant::Moderator)
+		if (role == MUCOccupant::Moderator && !isImpromptu_)
 		{
 			if (affiliation == MUCOccupant::Admin || affiliation == MUCOccupant::Owner) {
 				actions.push_back(ChatWindow::Ban);
@@ -348,8 +348,12 @@ void MUCController::handleJoinComplete(const std::string& nick) {
 	clearPresenceQueue();
 	shouldJoinOnReconnect_ = true;
 	setEnabled(true);
-	MUCOccupant occupant = muc_->getOccupant(nick);
-	setAvailableRoomActions(occupant.getAffiliation(), occupant.getRole());
+	if (isImpromptu_) {
+		setAvailableRoomActions(MUCOccupant::NoAffiliation, MUCOccupant::Participant);
+	} else {
+		MUCOccupant occupant = muc_->getOccupant(nick);
+		setAvailableRoomActions(occupant.getAffiliation(), occupant.getRole());
+	}
 	onUserJoined();
 
 	if (isImpromptu_) {
@@ -384,13 +388,18 @@ void MUCController::handleOccupantJoined(const MUCOccupant& occupant) {
 	currentOccupants_.insert(occupant.getNick());
 	NickJoinPart event(occupant.getNick(), Join);
 	appendToJoinParts(joinParts_, event);
-	std::string groupName(roleToGroupName(occupant.getRole()));
+	MUCOccupant::Role role = MUCOccupant::Participant;
+	MUCOccupant::Affiliation affiliation = MUCOccupant::NoAffiliation;
+	if (!isImpromptu_) {
+		role = occupant.getRole();
+		affiliation = occupant.getAffiliation();
+	}
+	std::string groupName(roleToGroupName(role));
 	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()));
+	roster_->applyOnItems(SetMUC(jid, role, affiliation));
+	roster_->getGroup(groupName)->setManualSort(roleToSortName(role));
 	if (joined_) {
 		std::string joinString;
-		MUCOccupant::Role role = occupant.getRole();
 		if (role != MUCOccupant::NoRole && role != MUCOccupant::Participant) {
 			joinString = str(format(QT_TRANSLATE_NOOP("", "%1% has entered the %3% as a %2%.")) % occupant.getNick() % roleToFriendlyName(role) % (isImpromptu_ ? QT_TRANSLATE_NOOP("", "chat") : QT_TRANSLATE_NOOP("", "room")));
 		}
diff --git a/Swift/Controllers/UIInterfaces/ChatWindow.h b/Swift/Controllers/UIInterfaces/ChatWindow.h
index 0f0062d..771872a 100644
--- a/Swift/Controllers/UIInterfaces/ChatWindow.h
+++ b/Swift/Controllers/UIInterfaces/ChatWindow.h
@@ -92,6 +92,7 @@ namespace Swift {
 			enum WhiteboardSessionState {WhiteboardAccepted, WhiteboardTerminated, WhiteboardRejected};
 			enum BlockingState {BlockingUnsupported, IsBlocked, IsUnblocked};
 			enum Direction { UnknownDirection, DefaultDirection };
+			enum MUCType { StandardMUC, ImpromptuMUC };
 
 			ChatWindow() {}
 			virtual ~ChatWindow() {}
@@ -132,7 +133,7 @@ namespace Swift {
 			virtual void setSecurityLabelsEnabled(bool enabled) = 0;
 			virtual void setCorrectionEnabled(Tristate enabled) = 0;
 			virtual void setUnreadMessageCount(int count) = 0;
-			virtual void convertToMUC(bool impromptuMUC = false) = 0;
+			virtual void convertToMUC(MUCType mucType) = 0;
 //			virtual TreeWidget *getTreeWidget() = 0;
 			virtual void setSecurityLabelsError() = 0;
 			virtual SecurityLabelsCatalog::Item getSelectedSecurityLabel() = 0;
diff --git a/Swift/Controllers/UnitTest/MockChatWindow.h b/Swift/Controllers/UnitTest/MockChatWindow.h
index 59ed0f1..8aa645d 100644
--- a/Swift/Controllers/UnitTest/MockChatWindow.h
+++ b/Swift/Controllers/UnitTest/MockChatWindow.h
@@ -45,7 +45,7 @@ namespace Swift {
 			virtual void setAvailableSecurityLabels(const std::vector<SecurityLabelsCatalog::Item>& labels) {labels_ = labels;}
 			virtual void setSecurityLabelsEnabled(bool enabled) {labelsEnabled_ = enabled;}
 			virtual void setUnreadMessageCount(int /*count*/) {}
-			virtual void convertToMUC(bool /*impromptuMUC*/) {}
+			virtual void convertToMUC(MUCType /*mucType*/) {}
 			virtual void setSecurityLabelsError() {}
 			virtual SecurityLabelsCatalog::Item getSelectedSecurityLabel() {return label_;}
 			virtual void setInputEnabled(bool /*enabled*/) {}
diff --git a/Swift/QtUI/QtChatWindow.cpp b/Swift/QtUI/QtChatWindow.cpp
index 826ec9e..bd7c817 100644
--- a/Swift/QtUI/QtChatWindow.cpp
+++ b/Swift/QtUI/QtChatWindow.cpp
@@ -116,7 +116,7 @@ QtChatWindow::QtChatWindow(const QString &contact, QtChatTheme* theme, UIEventSt
 	}
 	logRosterSplitter_->addWidget(messageLog_);
 
-	treeWidget_ = new QtOccupantListWidget(eventStream_, settings_, this);
+	treeWidget_ = new QtOccupantListWidget(eventStream_, settings_, QtTreeWidget::MessageDefaultJID, this);
 	treeWidget_->hide();
 	logRosterSplitter_->addWidget(treeWidget_);
 	logRosterSplitter_->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
@@ -396,8 +396,9 @@ void QtChatWindow::closeEvent(QCloseEvent* event) {
 	onClosed();
 }
 
-void QtChatWindow::convertToMUC(bool impromptuMUC) {
-	impromptu_ = impromptuMUC;
+void QtChatWindow::convertToMUC(MUCType mucType) {
+	impromptu_ = (mucType == ImpromptuMUC);
+	treeWidget_->setMessageTarget(impromptu_ ? QtTreeWidget::MessageDisplayJID : QtTreeWidget::MessageDefaultJID);
 	isMUC_ = true;
 	treeWidget_->show();
 	subject_->setVisible(!impromptu_);
diff --git a/Swift/QtUI/QtChatWindow.h b/Swift/QtUI/QtChatWindow.h
index eeb8093..5a4fe95 100644
--- a/Swift/QtUI/QtChatWindow.h
+++ b/Swift/QtUI/QtChatWindow.h
@@ -99,7 +99,7 @@ namespace Swift {
 			void show();
 			void activate();
 			void setUnreadMessageCount(int count);
-			void convertToMUC(bool impromptuMUC = false);
+			void convertToMUC(MUCType mucType);
 //			TreeWidget *getTreeWidget();
 			void setAvailableSecurityLabels(const std::vector<SecurityLabelsCatalog::Item>& labels);
 			void setSecurityLabelsEnabled(bool enabled);
diff --git a/Swift/QtUI/QtHistoryWindow.cpp b/Swift/QtUI/QtHistoryWindow.cpp
index 9f88258..75eeaad 100644
--- a/Swift/QtUI/QtHistoryWindow.cpp
+++ b/Swift/QtUI/QtHistoryWindow.cpp
@@ -60,7 +60,7 @@ QtHistoryWindow::QtHistoryWindow(SettingsProvider* settings, UIEventStream* even
 	ui_.bottomLayout_->addWidget(conversation_);
 
 	delete ui_.conversationRoster_;
-	conversationRoster_ = new QtTreeWidget(eventStream, settings, this);
+	conversationRoster_ = new QtTreeWidget(eventStream, settings, QtTreeWidget::MessageDefaultJID, this);
 	QSizePolicy sizePolicy2(QSizePolicy::Preferred, QSizePolicy::Expanding);
 	sizePolicy2.setVerticalStretch(80);
 	conversationRoster_->setSizePolicy(sizePolicy2);
diff --git a/Swift/QtUI/Roster/QtOccupantListWidget.cpp b/Swift/QtUI/Roster/QtOccupantListWidget.cpp
index 12dc1e4..4f1baf3 100644
--- a/Swift/QtUI/Roster/QtOccupantListWidget.cpp
+++ b/Swift/QtUI/Roster/QtOccupantListWidget.cpp
@@ -1,25 +1,26 @@
 /*
- * Copyright (c) 2011-2012 Kevin Smith
+ * Copyright (c) 2011-2014 Kevin Smith
  * Licensed under the GNU General Public License v3.
  * See Documentation/Licenses/GPLv3.txt for more information.
  */
 
 
-#include "Roster/QtOccupantListWidget.h"
+#include <Swift/QtUI/Roster/QtOccupantListWidget.h>
 
 #include <QContextMenuEvent>
 #include <QMenu>
 #include <QAction>
 #include <QInputDialog>
 
-#include "Swift/Controllers/Roster/ContactRosterItem.h"
-#include "Swift/Controllers/Roster/GroupRosterItem.h"
-#include "Swift/Controllers/UIEvents/UIEventStream.h"
-#include "QtSwiftUtil.h"
+#include <Swift/Controllers/Roster/ContactRosterItem.h>
+#include <Swift/Controllers/Roster/GroupRosterItem.h>
+#include <Swift/Controllers/UIEvents/UIEventStream.h>
+
+#include <Swift/QtUI/QtSwiftUtil.h>
 
 namespace Swift {
 
-QtOccupantListWidget::QtOccupantListWidget(UIEventStream* eventStream, SettingsProvider* settings, QWidget* parent) : QtTreeWidget(eventStream, settings, parent) {
+QtOccupantListWidget::QtOccupantListWidget(UIEventStream* eventStream, SettingsProvider* settings, MessageTarget privateMessageTarget, QWidget* parent) : QtTreeWidget(eventStream, settings, privateMessageTarget, parent) {
 
 }
 
diff --git a/Swift/QtUI/Roster/QtOccupantListWidget.h b/Swift/QtUI/Roster/QtOccupantListWidget.h
index 729115a..c944658 100644
--- a/Swift/QtUI/Roster/QtOccupantListWidget.h
+++ b/Swift/QtUI/Roster/QtOccupantListWidget.h
@@ -1,15 +1,16 @@
 /*
- * Copyright (c) 2011-2012 Kevin Smith
+ * Copyright (c) 2011-2014 Kevin Smith
  * Licensed under the GNU General Public License v3.
  * See Documentation/Licenses/GPLv3.txt for more information.
  */
 
 #pragma once
 
-#include "Swift/QtUI/Roster/QtTreeWidget.h"
+#include <Swift/QtUI/Roster/QtTreeWidget.h>
 
-#include "Swiften/Base/boost_bsignals.h"
-#include "Swift/Controllers/UIInterfaces/ChatWindow.h"
+#include <Swiften/Base/boost_bsignals.h>
+
+#include <Swift/Controllers/UIInterfaces/ChatWindow.h>
 
 namespace Swift {
 class SettingsProvider;
@@ -17,7 +18,7 @@ class SettingsProvider;
 class QtOccupantListWidget : public QtTreeWidget {
 	Q_OBJECT
 	public:
-		QtOccupantListWidget(UIEventStream* eventStream, SettingsProvider* settings, QWidget* parent = 0);
+		QtOccupantListWidget(UIEventStream* eventStream, SettingsProvider* settings, MessageTarget privateMessageTarget, QWidget* parent = NULL);
 		virtual ~QtOccupantListWidget();
 		void setAvailableOccupantActions(const std::vector<ChatWindow::OccupantAction>& actions);
 		boost::signal<void (ChatWindow::OccupantAction, ContactRosterItem*)> onOccupantActionSelected;
diff --git a/Swift/QtUI/Roster/QtRosterWidget.cpp b/Swift/QtUI/Roster/QtRosterWidget.cpp
index 1436c7c..fff0ccd 100644
--- a/Swift/QtUI/Roster/QtRosterWidget.cpp
+++ b/Swift/QtUI/Roster/QtRosterWidget.cpp
@@ -28,7 +28,7 @@
 
 namespace Swift {
 
-QtRosterWidget::QtRosterWidget(UIEventStream* eventStream, SettingsProvider* settings, QWidget* parent) : QtTreeWidget(eventStream, settings, parent) {
+QtRosterWidget::QtRosterWidget(UIEventStream* eventStream, SettingsProvider* settings, QWidget* parent) : QtTreeWidget(eventStream, settings, MessageDefaultJID, parent) {
 
 }
 
diff --git a/Swift/QtUI/Roster/QtTreeWidget.cpp b/Swift/QtUI/Roster/QtTreeWidget.cpp
index 91e9a33..ed76a6f 100644
--- a/Swift/QtUI/Roster/QtTreeWidget.cpp
+++ b/Swift/QtUI/Roster/QtTreeWidget.cpp
@@ -26,12 +26,12 @@
 #include <Swift/Controllers/Settings/SettingsProvider.h>
  
 #include <Swift/QtUI/QtUISettingConstants.h>
-
+#include <Swift/QtUI/Roster/RosterModel.h>
 #include <QtSwiftUtil.h>
 
 namespace Swift {
 
-QtTreeWidget::QtTreeWidget(UIEventStream* eventStream, SettingsProvider* settings, QWidget* parent) : QTreeView(parent), tooltipShown_(false) {
+QtTreeWidget::QtTreeWidget(UIEventStream* eventStream, SettingsProvider* settings, MessageTarget messageTarget, QWidget* parent) : QTreeView(parent), messageTarget_(messageTarget), tooltipShown_(false) {
 	eventStream_ = eventStream;
 	settings_ = settings;
 	model_ = new RosterModel(this, settings_->getSetting(QtUISettingConstants::USE_SCREENREADER));
@@ -137,12 +137,24 @@ void QtTreeWidget::currentChanged(const QModelIndex& current, const QModelIndex&
 	QTreeView::currentChanged(current, previous);
 }
 
-
 void QtTreeWidget::handleItemActivated(const QModelIndex& index) {
-	RosterItem* item = static_cast<RosterItem*>(index.internalPointer());
-	ContactRosterItem* contact = dynamic_cast<ContactRosterItem*>(item);
-	if (contact) {
-		eventStream_->send(boost::shared_ptr<UIEvent>(new RequestChatUIEvent(contact->getJID())));
+	switch (messageTarget_) {
+	case MessageDisplayJID: {
+		QString indexJID = index.data(DisplayJIDRole).toString();
+		if (!indexJID.isEmpty()) {
+			JID target = JID(Q2PSTRING(indexJID)).toBare();
+			eventStream_->send(boost::shared_ptr<UIEvent>(new RequestChatUIEvent(target)));
+			break;
+		}
+	}
+	case MessageDefaultJID: {
+		QString indexJID = index.data(JIDRole).toString();
+		if (!indexJID.isEmpty()) {
+			JID target = JID(Q2PSTRING(indexJID));
+			eventStream_->send(boost::shared_ptr<UIEvent>(new RequestChatUIEvent(target)));
+		}
+		break;
+	}
 	}
 }
 
@@ -230,4 +242,8 @@ void QtTreeWidget::show() {
 	QWidget::show();
 }
 
+void QtTreeWidget::setMessageTarget(MessageTarget messageTarget) {
+	messageTarget_ = messageTarget;
+}
+
 }
diff --git a/Swift/QtUI/Roster/QtTreeWidget.h b/Swift/QtUI/Roster/QtTreeWidget.h
index 8884a40..29e985d 100644
--- a/Swift/QtUI/Roster/QtTreeWidget.h
+++ b/Swift/QtUI/Roster/QtTreeWidget.h
@@ -1,34 +1,40 @@
 /*
- * Copyright (c) 2010-2012 Kevin Smith
+ * Copyright (c) 2010-2014 Kevin Smith
  * Licensed under the GNU General Public License v3.
  * See Documentation/Licenses/GPLv3.txt for more information.
  */
 
 #pragma once
 
-#include <QTreeView>
-#include <QModelIndex>
 #include <QDragEnterEvent>
 #include <QDropEvent>
 #include <QDragMoveEvent>
+#include <QModelIndex>
+#include <QTreeView>
  
-#include <Swift/QtUI/Roster/RosterModel.h>
 #include <Swift/QtUI/Roster/RosterDelegate.h>
+#include <Swift/QtUI/Roster/RosterModel.h>
+
+#include <Swift/Controllers/UIInterfaces/ChatWindow.h>
 
 namespace Swift {
 class UIEventStream;
 class SettingsProvider;
 
-class QtTreeWidget : public QTreeView{
+class QtTreeWidget : public QTreeView {
 	Q_OBJECT
 	public:
-		QtTreeWidget(UIEventStream* eventStream, SettingsProvider* settings, QWidget* parent = 0);
+		enum MessageTarget {MessageDefaultJID, MessageDisplayJID};
+
+		QtTreeWidget(UIEventStream* eventStream, SettingsProvider* settings, MessageTarget messageTarget, QWidget* parent = 0);
 		~QtTreeWidget();
 		void show();
 		QtTreeWidgetItem* getRoot();
 		void setRosterModel(Roster* roster);
 		Roster* getRoster() {return roster_;}
 		void refreshTooltip();
+		void setMessageTarget(MessageTarget messageTarget);
+	public:
 		boost::signal<void (RosterItem*)> onSomethingSelectedChanged;
 
 	private slots:
@@ -45,9 +51,8 @@ class QtTreeWidget : public QTreeView{
 		void dropEvent(QDropEvent* event);
 		void dragMoveEvent(QDragMoveEvent* event);
 		bool event(QEvent* event);
-
-	protected:
 		QModelIndexList getSelectedIndexes() const;
+
 	private:
 		void drawBranches(QPainter*, const QRect&, const QModelIndex&) const;
 
@@ -63,6 +68,7 @@ class QtTreeWidget : public QTreeView{
 		QtTreeWidgetItem* treeRoot_;
 		SettingsProvider* settings_;
 		bool tooltipShown_;
+		MessageTarget messageTarget_;
 };
 
 }
diff --git a/Swift/QtUI/Roster/RosterModel.cpp b/Swift/QtUI/Roster/RosterModel.cpp
index fa8c393..2bd0d09 100644
--- a/Swift/QtUI/Roster/RosterModel.cpp
+++ b/Swift/QtUI/Roster/RosterModel.cpp
@@ -102,6 +102,8 @@ QVariant RosterModel::data(const QModelIndex& index, int role) const {
 		case PresenceIconRole: return getPresenceIcon(item);
 		case ChildCountRole: return getChildCount(item);
 		case IdleRole: return getIsIdle(item);
+		case JIDRole: return getJID(item);
+		case DisplayJIDRole: return getDisplayJID(item);
 		default: return QVariant();
 	}
 }
@@ -181,6 +183,16 @@ QString RosterModel::getStatusText(RosterItem* item) const {
 	return P2QSTRING(contact->getStatusText());
 }
 
+QString RosterModel::getJID(RosterItem* item) const {
+	ContactRosterItem* contact = dynamic_cast<ContactRosterItem*>(item);
+	return contact ? P2QSTRING(contact->getJID().toString()) : QString();
+}
+
+QString RosterModel::getDisplayJID(RosterItem* item) const {
+	ContactRosterItem* contact = dynamic_cast<ContactRosterItem*>(item);
+	return contact ? P2QSTRING(contact->getDisplayJID().toString()) : QString();
+}
+
 QIcon RosterModel::getPresenceIcon(RosterItem* item) const {
 	ContactRosterItem* contact = dynamic_cast<ContactRosterItem*>(item);
 	if (!contact) return QIcon();
diff --git a/Swift/QtUI/Roster/RosterModel.h b/Swift/QtUI/Roster/RosterModel.h
index 7f6cdd2..2b05044 100644
--- a/Swift/QtUI/Roster/RosterModel.h
+++ b/Swift/QtUI/Roster/RosterModel.h
@@ -20,7 +20,9 @@ namespace Swift {
 		PresenceIconRole = Qt::UserRole + 2,
 		StatusShowTypeRole = Qt::UserRole + 3,
 		ChildCountRole = Qt::UserRole + 4,
-		IdleRole = Qt::UserRole + 5
+		IdleRole = Qt::UserRole + 5,
+		JIDRole = Qt::UserRole + 6,
+		DisplayJIDRole = Qt::UserRole + 7
 	};
 
 	class QtTreeWidget;
@@ -52,6 +54,8 @@ namespace Swift {
 			QString getToolTip(RosterItem* item) const;
 			QString getAvatar(RosterItem* item) const;
 			QString getStatusText(RosterItem* item) const;
+			QString getJID(RosterItem* item) const;
+			QString getDisplayJID(RosterItem* item) const;
 			QIcon getPresenceIcon(RosterItem* item) const;
 			int getChildCount(RosterItem* item) const;
 			bool getIsIdle(RosterItem* item) const;
-- 
cgit v0.10.2-6-g49f6