From 3727dd9632007bc97962156bd131f6c8c977a7ba Mon Sep 17 00:00:00 2001
From: Kevin Smith <git@kismith.co.uk>
Date: Mon, 25 Apr 2011 09:56:21 +0100
Subject: Move available actions logic into Swiften class.

Ready for unit testing, and fixing.

diff --git a/Swift/Controllers/AdHocManager.cpp b/Swift/Controllers/AdHocManager.cpp
index 368771f..0fa63a1 100644
--- a/Swift/Controllers/AdHocManager.cpp
+++ b/Swift/Controllers/AdHocManager.cpp
@@ -11,7 +11,6 @@
 
 #include <Swiften/Base/foreach.h>
 #include <Swiften/Queries/IQRouter.h>
-#include <Swiften/Disco/GetDiscoItemsRequest.h>
 #include <Swiften/AdHoc/OutgoingAdHocCommandSession.h>
 #include <Swift/Controllers/UIInterfaces/MainWindow.h>
 #include <Swift/Controllers/UIInterfaces/AdHocCommandWindowFactory.h>
@@ -30,14 +29,18 @@ AdHocManager::AdHocManager(const JID& jid, AdHocCommandWindowFactory* factory, I
 }
 
 AdHocManager::~AdHocManager() {
-
+	uiEventStream_->onUIEvent.disconnect(boost::bind(&AdHocManager::handleUIEvent, this, _1));
 }
 
 void AdHocManager::setServerDiscoInfo(boost::shared_ptr<DiscoInfo> info) {
 	if (iqRouter_->isAvailable() && info->hasFeature(DiscoInfo::CommandsFeature)) {
-		GetDiscoItemsRequest::ref discoItemsRequest = GetDiscoItemsRequest::create(JID(jid_.getDomain()), DiscoInfo::CommandsFeature, iqRouter_);
-		discoItemsRequest->onResponse.connect(boost::bind(&AdHocManager::handleServerDiscoItemsResponse, this, _1, _2));
-		discoItemsRequest->send();
+		if (discoItemsRequest_) {
+			discoItemsRequest_->onResponse.disconnect(boost::bind(&AdHocManager::handleServerDiscoItemsResponse, this, _1, _2));
+			discoItemsRequest_.reset();
+		}
+		discoItemsRequest_ = GetDiscoItemsRequest::create(JID(jid_.getDomain()), DiscoInfo::CommandsFeature, iqRouter_);
+		discoItemsRequest_->onResponse.connect(boost::bind(&AdHocManager::handleServerDiscoItemsResponse, this, _1, _2));
+		discoItemsRequest_->send();
 	} else {
 		mainWindow_->setAvailableAdHocCommands(std::vector<DiscoItems::Item>());
 	}
diff --git a/Swift/Controllers/AdHocManager.h b/Swift/Controllers/AdHocManager.h
index 9e21bf7..47b03cd 100644
--- a/Swift/Controllers/AdHocManager.h
+++ b/Swift/Controllers/AdHocManager.h
@@ -7,12 +7,14 @@
 #pragma once
 
 #include <boost/shared_ptr.hpp>
+#include <vector>
 
 #include <Swiften/Base/boost_bsignals.h>
 #include <Swiften/JID/JID.h>
 #include <Swiften/Elements/DiscoInfo.h>
 #include <Swiften/Elements/DiscoItems.h>
 #include <Swiften/Elements/ErrorPayload.h>
+#include <Swiften/Disco/GetDiscoItemsRequest.h>
 #include <Swift/Controllers/UIEvents/UIEvent.h>
 
 namespace Swift {
@@ -33,5 +35,6 @@ namespace Swift {
 			UIEventStream* uiEventStream_;
 			MainWindow* mainWindow_;
 			AdHocCommandWindowFactory* factory_;
+			GetDiscoItemsRequest::ref discoItemsRequest_;
 	};
 }
diff --git a/Swift/QtUI/QtAdHocCommandWindow.cpp b/Swift/QtUI/QtAdHocCommandWindow.cpp
index f6b1b5c..a3bb077 100644
--- a/Swift/QtUI/QtAdHocCommandWindow.cpp
+++ b/Swift/QtUI/QtAdHocCommandWindow.cpp
@@ -9,6 +9,7 @@
 #include <boost/bind.hpp>
 #include <QBoxLayout>
 #include <Swift/QtUI/QtFormWidget.h>
+#include <Swiften/Elements/Command.h>
 
 namespace Swift {
 QtAdHocCommandWindow::QtAdHocCommandWindow(boost::shared_ptr<OutgoingAdHocCommandSession> command) : command_(command) {
@@ -47,6 +48,10 @@ QtAdHocCommandWindow::QtAdHocCommandWindow(boost::shared_ptr<OutgoingAdHocComman
 	nextButton_->setEnabled(false);
 	backButton_->setEnabled(false);
 	completeButton_->setEnabled(false);
+	actions_[Command::Next] = nextButton_;
+	actions_[Command::Prev] = backButton_;
+	actions_[Command::Complete] = completeButton_;
+	actions_[Command::Cancel] = cancelButton_;
 	show();
 }
 
@@ -109,21 +114,23 @@ void QtAdHocCommandWindow::setNoForm() {
 	delete formWidget_;
 }
 
-void QtAdHocCommandWindow::setAvailableActions(Command::ref commandResult) {
-	const std::vector<Command::Action> actions = commandResult->getAvailableActions();
-	nextButton_->setEnabled(std::find(actions.begin(), actions.end(), Command::Next) != actions.end());
-	backButton_->setEnabled(std::find(actions.begin(), actions.end(), Command::Prev) != actions.end());
-	completeButton_->setEnabled(std::find(actions.begin(), actions.end(), Command::Complete) != actions.end());
-
-
-	if (command_->getIsMultiStage()) {
-		backButton_->show();
-		nextButton_->show();
-	}
-	else {
-		backButton_->hide();
-		nextButton_->hide();
+typedef std::pair<Command::Action, QPushButton*> ActionButton;
 
+void QtAdHocCommandWindow::setAvailableActions(Command::ref /*commandResult*/) {
+	foreach (ActionButton pair, actions_) {
+		OutgoingAdHocCommandSession::ActionState state = command_->getActionState(pair.first);
+		if (state & OutgoingAdHocCommandSession::Present) {
+			pair.second->show();
+		}
+		else {
+			pair.second->hide();
+		}
+		if (state & OutgoingAdHocCommandSession::Enabled) {
+			pair.second->setEnabled(true);
+		}
+		else {
+			pair.second->setEnabled(false);
+		}
 	}
 }
 
diff --git a/Swift/QtUI/QtAdHocCommandWindow.h b/Swift/QtUI/QtAdHocCommandWindow.h
index f1073bc..adeb3e6 100644
--- a/Swift/QtUI/QtAdHocCommandWindow.h
+++ b/Swift/QtUI/QtAdHocCommandWindow.h
@@ -43,5 +43,6 @@ namespace Swift {
 			QPushButton* nextButton_;
 			QPushButton* completeButton_;
 			QPushButton* cancelButton_;
+			std::map<Command::Action, QPushButton*> actions_;
 	};
 }
diff --git a/Swiften/AdHoc/OutgoingAdHocCommandSession.cpp b/Swiften/AdHoc/OutgoingAdHocCommandSession.cpp
index 40b17e7..edacf94 100644
--- a/Swiften/AdHoc/OutgoingAdHocCommandSession.cpp
+++ b/Swiften/AdHoc/OutgoingAdHocCommandSession.cpp
@@ -19,8 +19,27 @@ void OutgoingAdHocCommandSession::handleResponse(boost::shared_ptr<Command> payl
 	if (error) {
 		onError(error);
 	} else {
-		sessionID_ = payload->getSessionID();
 		const std::vector<Command::Action> actions = payload->getAvailableActions();
+		actionStates_.clear();
+		actionStates_[Command::Cancel] = EnabledAndPresent;
+		actionStates_[Command::Complete] = Present;
+		if (std::find(actions.begin(), actions.end(), Command::Complete) != actions.end()) {
+			actionStates_[Command::Complete] = EnabledAndPresent;
+		}
+
+		if (getIsMultiStage()) {
+			actionStates_[Command::Next] = Present;
+			actionStates_[Command::Prev] = Present;
+		}
+
+		if (std::find(actions.begin(), actions.end(), Command::Next) != actions.end()) {
+			actionStates_[Command::Next] = EnabledAndPresent;
+		}
+		if (std::find(actions.begin(), actions.end(), Command::Prev) != actions.end()) {
+			actionStates_[Command::Prev] = EnabledAndPresent;
+		}
+
+		sessionID_ = payload->getSessionID();
 		if (std::find(actions.begin(), actions.end(), Command::Next) != actions.end()
 				|| std::find(actions.begin(), actions.end(), Command::Prev) != actions.end()) {
 			isMultiStage_ = true;
@@ -74,4 +93,8 @@ void OutgoingAdHocCommandSession::goNext(Form::ref form) {
 	commandRequest->send();
 }
 
+OutgoingAdHocCommandSession::ActionState OutgoingAdHocCommandSession::getActionState(Command::Action action) {
+	return actionStates_[action];
+}
+
 }
diff --git a/Swiften/AdHoc/OutgoingAdHocCommandSession.h b/Swiften/AdHoc/OutgoingAdHocCommandSession.h
index 820dc62..fcc93e7 100644
--- a/Swiften/AdHoc/OutgoingAdHocCommandSession.h
+++ b/Swiften/AdHoc/OutgoingAdHocCommandSession.h
@@ -19,6 +19,16 @@ namespace Swift {
 	class AdHocCommandWindowFactory;
 	class OutgoingAdHocCommandSession {
 		public:
+
+			/**
+			 * Availability of action.
+			 */
+			enum ActionState {
+				Absent /** Action isn't applicable to this command. */ = 0,
+				Present /** Action is applicable to this command */= 1,
+				Enabled /** Action is applicable and currently available */ = 2,
+				EnabledAndPresent = 3};
+
 			OutgoingAdHocCommandSession(const DiscoItems::Item& command, AdHocCommandWindowFactory* factory, IQRouter* iqRouter);
 			/**
 			 * Send initial request to the target.
@@ -57,6 +67,14 @@ namespace Swift {
 			 * Emitted on error.
 			 */
 			boost::signal<void (ErrorPayload::ref)> onError;
+
+			/**
+			 * Get the state of a given action.
+			 * This is useful for a UI to determine which buttons should be visible,
+			 * and which enabled.
+			 * Use for Next, Prev, Cancel and Complete only.
+			 */
+			ActionState getActionState(Command::Action action);
 		private:
 			void handleResponse(boost::shared_ptr<Command> payload, ErrorPayload::ref error);
 		private:
@@ -64,5 +82,6 @@ namespace Swift {
 			IQRouter* iqRouter_;
 			bool isMultiStage_;
 			std::string sessionID_;
+			std::map<Command::Action, ActionState> actionStates_;
 	};
 }
-- 
cgit v0.10.2-6-g49f6