From 6aeb44a905b0c1955ea3afe4ea2025370544e699 Mon Sep 17 00:00:00 2001
From: Kevin Smith <git@kismith.co.uk>
Date: Thu, 31 May 2012 18:27:48 +0100
Subject: Very poor prototype of a MUC invite dialog


diff --git a/Swift/Controllers/Chat/MUCController.cpp b/Swift/Controllers/Chat/MUCController.cpp
index e4209f4..3d04b34 100644
--- a/Swift/Controllers/Chat/MUCController.cpp
+++ b/Swift/Controllers/Chat/MUCController.cpp
@@ -19,6 +19,7 @@
 #include <Swiften/Base/foreach.h>
 #include <Swift/Controllers/XMPPEvents/EventController.h>
 #include <Swift/Controllers/UIInterfaces/ChatWindow.h>
+#include <Swift/Controllers/UIInterfaces/InviteToChatWindow.h>
 #include <Swift/Controllers/UIInterfaces/ChatWindowFactory.h>
 #include <Swift/Controllers/UIEvents/UIEventStream.h>
 #include <Swift/Controllers/UIEvents/RequestChatUIEvent.h>
@@ -64,6 +65,7 @@ MUCController::MUCController (
 	shouldJoinOnReconnect_ = true;
 	doneGettingHistory_ = false;
 	events_ = uiEventStream;
+	inviteWindow_ = NULL;
 	
 	roster_ = new Roster(false, true);
 	completer_ = new TabComplete();
@@ -77,7 +79,7 @@ MUCController::MUCController (
 	chatWindow_->onConfigureRequest.connect(boost::bind(&MUCController::handleConfigureRequest, this, _1));
 	chatWindow_->onConfigurationFormCancelled.connect(boost::bind(&MUCController::handleConfigurationCancelled, this));
 	chatWindow_->onDestroyRequest.connect(boost::bind(&MUCController::handleDestroyRoomRequest, this));
-	chatWindow_->onInvitePersonToThisMUCRequest.connect(boost::bind(&MUCController::handleInvitePersonToThisMUCRequest, this, _1, _2));
+	chatWindow_->onInvitePersonToThisMUCRequest.connect(boost::bind(&MUCController::handleInvitePersonToThisMUCRequest, this));
 	chatWindow_->onGetAffiliationsRequest.connect(boost::bind(&MUCController::handleGetAffiliationsRequest, this));
 	chatWindow_->onChangeAffiliationsRequest.connect(boost::bind(&MUCController::handleChangeAffiliationsRequest, this, _1));
 	muc_->onJoinComplete.connect(boost::bind(&MUCController::handleJoinComplete, this, _1));
@@ -719,8 +721,22 @@ void MUCController::handleDestroyRoomRequest() {
 	muc_->destroyRoom();
 }
 
-void MUCController::handleInvitePersonToThisMUCRequest(const JID& jid, const std::string& reason) {
-	muc_->invitePerson(jid, reason);
+void MUCController::handleInvitePersonToThisMUCRequest() {
+	if (!inviteWindow_) {
+		inviteWindow_ = chatWindow_->createInviteToChatWindow();
+		inviteWindow_->onCompleted.connect(boost::bind(&MUCController::handleInviteToMUCWindowCompleted, this));
+		inviteWindow_->onDismissed.connect(boost::bind(&MUCController::handleInviteToMUCWindowDismissed, this));
+	}
+}
+
+void MUCController::handleInviteToMUCWindowDismissed() {
+	inviteWindow_= NULL;
+}
+
+void MUCController::handleInviteToMUCWindowCompleted() {
+	foreach (const JID& jid, inviteWindow_->getJIDs()) {
+		muc_->invitePerson(jid, inviteWindow_->getReason());
+	}
 }
 
 void MUCController::handleGetAffiliationsRequest() {
diff --git a/Swift/Controllers/Chat/MUCController.h b/Swift/Controllers/Chat/MUCController.h
index 9550ca9..8b43dcf 100644
--- a/Swift/Controllers/Chat/MUCController.h
+++ b/Swift/Controllers/Chat/MUCController.h
@@ -31,6 +31,7 @@ namespace Swift {
 	class UIEventStream;
 	class TimerFactory;
 	class TabComplete;
+	class InviteToChatWindow;
 
 	enum JoinPart {Join, Part, JoinThenPart, PartThenJoin};
 
@@ -95,12 +96,14 @@ namespace Swift {
 			void handleConfigurationFailed(ErrorPayload::ref);
 			void handleConfigurationFormReceived(Form::ref);
 			void handleDestroyRoomRequest();
-			void handleInvitePersonToThisMUCRequest(const JID& jid, const std::string& reason);
+			void handleInvitePersonToThisMUCRequest();
 			void handleConfigurationCancelled();
 			void handleOccupantRoleChangeFailed(ErrorPayload::ref, const JID&, MUCOccupant::Role);
 			void handleGetAffiliationsRequest();
 			void handleAffiliationListReceived(MUCOccupant::Affiliation affiliation, const std::vector<JID>& jids);
 			void handleChangeAffiliationsRequest(const std::vector<std::pair<MUCOccupant::Affiliation, JID> >& changes);
+			void handleInviteToMUCWindowDismissed();
+			void handleInviteToMUCWindowCompleted();
 
 		private:
 			MUC::ref muc_;
@@ -120,6 +123,7 @@ namespace Swift {
 			std::vector<NickJoinPart> joinParts_;
 			boost::posix_time::ptime lastActivity_;
 			boost::optional<std::string> password_;
+			InviteToChatWindow* inviteWindow_;
 	};
 }
 
diff --git a/Swift/Controllers/UIInterfaces/ChatWindow.h b/Swift/Controllers/UIInterfaces/ChatWindow.h
index b5b1604..9188c7f 100644
--- a/Swift/Controllers/UIInterfaces/ChatWindow.h
+++ b/Swift/Controllers/UIInterfaces/ChatWindow.h
@@ -7,7 +7,7 @@
 #pragma once
 
 #include <boost/optional.hpp>
-#include "Swiften/Base/boost_bsignals.h"
+#include <Swiften/Base/boost_bsignals.h>
 #include <boost/shared_ptr.hpp>
 #include <boost/date_time/posix_time/posix_time.hpp>
 #include <vector>
@@ -27,6 +27,7 @@ namespace Swift {
 	class RosterItem;
 	class ContactRosterItem;
 	class FileTransferController;
+	class InviteToChatWindow;
 
 	class ChatWindow {
 		public:
@@ -105,6 +106,8 @@ namespace Swift {
 			 */
 			virtual void showRoomConfigurationForm(Form::ref) = 0;
 
+			virtual InviteToChatWindow* createInviteToChatWindow() = 0;
+
 			boost::signal<void ()> onClosed;
 			boost::signal<void ()> onAllMessagesRead;
 			boost::signal<void (const std::string&, bool isCorrection)> onSendMessageRequest;
@@ -117,7 +120,7 @@ namespace Swift {
 			boost::signal<void (const std::string&)> onChangeSubjectRequest;
 			boost::signal<void (Form::ref)> onConfigureRequest;
 			boost::signal<void ()> onDestroyRequest;
-			boost::signal<void (const JID&, const std::string& /*reason*/)> onInvitePersonToThisMUCRequest;
+			boost::signal<void ()> onInvitePersonToThisMUCRequest;
 			boost::signal<void ()> onConfigurationFormCancelled;
 			boost::signal<void ()> onGetAffiliationsRequest;
 			boost::signal<void (MUCOccupant::Affiliation, const JID&)> onSetAffiliationRequest;
diff --git a/Swift/Controllers/UIInterfaces/InviteToChatWindow.h b/Swift/Controllers/UIInterfaces/InviteToChatWindow.h
new file mode 100644
index 0000000..f34a485
--- /dev/null
+++ b/Swift/Controllers/UIInterfaces/InviteToChatWindow.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2012 Kevin Smith
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#pragma once
+
+#include <vector>
+
+#include <string>
+#include <Swiften/Base/boost_bsignals.h>
+#include <Swiften/JID/JID.h>
+
+namespace Swift {
+	class InviteToChatWindow {
+		public:
+			virtual ~InviteToChatWindow() {};
+
+			virtual std::string getReason() const = 0;
+
+			virtual std::vector<JID> getJIDs() const = 0;
+
+			boost::signal<void ()> onCompleted;
+			boost::signal<void ()> onDismissed;
+	};
+}
+
diff --git a/Swift/Controllers/UnitTest/MockChatWindow.h b/Swift/Controllers/UnitTest/MockChatWindow.h
index e0e18a0..dbfef3e 100644
--- a/Swift/Controllers/UnitTest/MockChatWindow.h
+++ b/Swift/Controllers/UnitTest/MockChatWindow.h
@@ -54,6 +54,7 @@ namespace Swift {
 			virtual void addMUCInvitation(const std::string& /*senderName*/, 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> &) {};
+			virtual InviteToChatWindow* createInviteToChatWindow() {return NULL;}
 
 			std::string name_;
 			std::string lastMessageBody_;
diff --git a/Swift/QtUI/QtChatWindow.cpp b/Swift/QtUI/QtChatWindow.cpp
index 52ce701..137c044 100644
--- a/Swift/QtUI/QtChatWindow.cpp
+++ b/Swift/QtUI/QtChatWindow.cpp
@@ -17,6 +17,7 @@
 #include "QtTextEdit.h"
 #include "QtSettingsProvider.h"
 #include "QtScaledAvatarCache.h"
+#include "QtInviteToChatWindow.h"
 
 #include <Swiften/StringCodecs/Base64.h>
 #include "SwifTools/TabComplete.h"
@@ -843,11 +844,7 @@ void QtChatWindow::handleActionButtonClicked() {
 		}
 	}
 	else if (result == invite) {
-		bool ok;
-		QString jid = QInputDialog::getText(this, tr("Enter person's address"), tr("Address:"), QLineEdit::Normal, "", &ok);
-		if (ok) {
-			onInvitePersonToThisMUCRequest(JID(Q2PSTRING(jid)), "");
-		}
+		onInvitePersonToThisMUCRequest();
 	}
 }
 
@@ -908,4 +905,10 @@ void QtChatWindow::addMUCInvitation(const std::string& senderName, const JID& ji
 	previousMessageKind_ = PreviousMessageWasMUCInvite;
 }
 
+
+InviteToChatWindow* QtChatWindow::createInviteToChatWindow() {
+	return new QtInviteToChatWindow(this);
+}
+
+
 }
diff --git a/Swift/QtUI/QtChatWindow.h b/Swift/QtUI/QtChatWindow.h
index 4b888eb..ff26c9c 100644
--- a/Swift/QtUI/QtChatWindow.h
+++ b/Swift/QtUI/QtChatWindow.h
@@ -91,6 +91,8 @@ namespace Swift {
 			void setAffiliations(MUCOccupant::Affiliation, const std::vector<JID>&);
 			void setAvailableRoomActions(const std::vector<RoomAction> &actions);
 
+			InviteToChatWindow* createInviteToChatWindow();
+
 			static QString buildChatWindowButton(const QString& name, const QString& id, const QString& arg1 = QString(), const QString& arg2 = QString(), const QString& arg3 = QString());
 
 		public slots:
diff --git a/Swift/QtUI/QtInviteToChatWindow.cpp b/Swift/QtUI/QtInviteToChatWindow.cpp
new file mode 100644
index 0000000..d53c493
--- /dev/null
+++ b/Swift/QtUI/QtInviteToChatWindow.cpp
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2012 Kevin Smith
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#include <Swift/QtUI/QtInviteToChatWindow.h>
+
+#include <QHBoxLayout>
+#include <QCompleter>
+#include <QLabel>
+#include <QLineEdit>
+#include <QPushButton>
+#include <QDialogButtonBox>
+
+#include <Swift/QtUI/QtSwiftUtil.h>
+
+namespace Swift {
+
+QtInviteToChatWindow::QtInviteToChatWindow(QWidget* parent) : QDialog(parent) {
+	QBoxLayout *layout = new QBoxLayout(QBoxLayout::TopToBottom, this);
+	layout->setContentsMargins(0,0,0,0);
+	layout->setSpacing(2);
+
+	QLabel* description = new QLabel(tr("Users to invite to this chat (one per line):"));
+	layout->addWidget(description);
+	
+	jidsLayout_ = new QBoxLayout(QBoxLayout::TopToBottom);
+	layout->addLayout(jidsLayout_);
+
+	QLabel* reasonLabel = new QLabel(tr("If you want to provide a reason for the invitation, enter it here"));
+	layout->addWidget(reasonLabel);
+	reason_ = new QLineEdit(this);
+	layout->addWidget(reason_);
+	addJIDLine();
+
+	connect(this, SIGNAL(accepted()), this, SLOT(handleAccepting()));
+	connect(this, SIGNAL(rejected()), this, SLOT(handleRejecting()));
+
+
+	QDialogButtonBox* buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
+
+	connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept()));
+	connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
+
+	layout->addWidget(buttonBox);
+
+	setModal(false);
+	show();
+}
+
+QtInviteToChatWindow::~QtInviteToChatWindow() {
+
+}
+
+void QtInviteToChatWindow::handleAccepting() {
+	onCompleted();
+}
+
+void QtInviteToChatWindow::handleRejecting() {
+	onDismissed();
+}
+
+std::string QtInviteToChatWindow::getReason() const {
+	return Q2PSTRING(reason_->text());
+}
+
+std::vector<JID> QtInviteToChatWindow::getJIDs() const {
+	std::vector<JID> results;
+	foreach (QLineEdit* jidEdit, jids_) {
+		QStringList parts = jidEdit->text().split(" ");
+		if (parts.size() > 0) {
+			JID jid(Q2PSTRING(parts.last()));
+			if (jid.isValid() && !jid.getNode().empty()) {
+				results.push_back(jid);
+			}
+		}
+	}
+	return results;
+}
+
+void QtInviteToChatWindow::addJIDLine() {
+	QLineEdit* jid = new QLineEdit(this);
+	QCompleter* completer = new QCompleter(completions_, this);
+	completer->setCaseSensitivity(Qt::CaseInsensitive);
+	jid->setCompleter(completer);
+	jids_.push_back(jid);
+	jidsLayout_->addWidget(jid);
+	connect(jid, SIGNAL(textChanged(const QString&)), this, SLOT(handleJIDTextChanged()));
+}
+
+void QtInviteToChatWindow::handleJIDTextChanged() {
+	bool gotEmpty = false;
+	foreach(QLineEdit* edit, jids_) {
+		if (edit->text().isEmpty()) {
+			gotEmpty = true;
+		}
+	}
+	if (!gotEmpty) {
+		addJIDLine();
+	}
+}
+
+}
+
+
+
diff --git a/Swift/QtUI/QtInviteToChatWindow.h b/Swift/QtUI/QtInviteToChatWindow.h
new file mode 100644
index 0000000..c009861
--- /dev/null
+++ b/Swift/QtUI/QtInviteToChatWindow.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2012 Kevin Smith
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#pragma once
+
+#include <Swift/Controllers/UIInterfaces/InviteToChatWindow.h>
+
+#include <QDialog>
+#include <QStringList>
+
+class QLineEdit;
+class QBoxLayout;
+
+namespace Swift {
+	class QtInviteToChatWindow : public QDialog, public InviteToChatWindow {
+		Q_OBJECT
+		public:
+			QtInviteToChatWindow(QWidget* parent = NULL);
+			virtual ~QtInviteToChatWindow();
+
+			virtual std::string getReason() const;
+
+			virtual std::vector<JID> getJIDs() const;
+		private:
+			void addJIDLine();
+		private slots:
+			void handleJIDTextChanged();
+			void handleAccepting();
+			void handleRejecting();
+		private:
+			QStringList completions_;
+			QLineEdit* reason_;
+			QBoxLayout* jidsLayout_;
+			std::vector<QLineEdit*> jids_;
+	};
+}
+
+
diff --git a/Swift/QtUI/SConscript b/Swift/QtUI/SConscript
index 4c53313..042e2a0 100644
--- a/Swift/QtUI/SConscript
+++ b/Swift/QtUI/SConscript
@@ -109,6 +109,7 @@ sources = [
     "QtFormResultItemModel.cpp",
     "QtLineEdit.cpp",
     "QtJoinMUCWindow.cpp",
+    "QtInviteToChatWindow.cpp",
     "Roster/RosterModel.cpp",
     "Roster/QtTreeWidget.cpp",
 #    "Roster/QtTreeWidgetItem.cpp",
-- 
cgit v0.10.2-6-g49f6