From 4315ccbd51f63e408d69d944f162d0ead4f9addd Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Remko=20Tron=C3=A7on?= <git@el-tramo.be>
Date: Sun, 12 Dec 2010 13:29:20 +0100
Subject: Refactored own nickname handling.


diff --git a/Swift/Controllers/MainController.cpp b/Swift/Controllers/MainController.cpp
index c1d8682..f215dc6 100644
--- a/Swift/Controllers/MainController.cpp
+++ b/Swift/Controllers/MainController.cpp
@@ -230,7 +230,7 @@ void MainController::handleConnected() {
 	bool freshLogin = rosterController_ == NULL;
 	myStatusLooksOnline_ = true;
 	if (freshLogin) {
-		rosterController_ = new RosterController(jid_, client_->getRoster(), client_->getAvatarManager(), mainWindowFactory_, client_->getNickResolver(), client_->getPresenceOracle(), client_->getSubscriptionManager(), eventController_, uiEventStream_, client_->getIQRouter(), settings_);
+		rosterController_ = new RosterController(jid_, client_->getRoster(), client_->getAvatarManager(), mainWindowFactory_, client_->getNickManager(), client_->getNickResolver(), client_->getPresenceOracle(), client_->getSubscriptionManager(), eventController_, uiEventStream_, client_->getIQRouter(), settings_);
 		rosterController_->onChangeStatusRequest.connect(boost::bind(&MainController::handleChangeStatusRequest, this, _1, _2));
 		rosterController_->onSignOutRequest.connect(boost::bind(&MainController::signOut, this));
 
diff --git a/Swift/Controllers/RosterController.cpp b/Swift/Controllers/RosterController.cpp
index cb044fb..1feeb58 100644
--- a/Swift/Controllers/RosterController.cpp
+++ b/Swift/Controllers/RosterController.cpp
@@ -32,6 +32,7 @@
 #include "Swift/Controllers/UIEvents/RenameRosterItemUIEvent.h"
 #include "Swift/Controllers/UIEvents/RegroupRosterItemUIEvent.h"
 #include "Swift/Controllers/UIEvents/ToggleShowOfflineUIEvent.h"
+#include <Swiften/Client/NickManager.h>
 
 namespace Swift {
 
@@ -40,8 +41,8 @@ static const String SHOW_OFFLINE = "showOffline";
 /**
  * The controller does not gain ownership of these parameters.
  */
-RosterController::RosterController(const JID& jid, XMPPRoster* xmppRoster, AvatarManager* avatarManager, MainWindowFactory* mainWindowFactory, NickResolver* nickResolver, PresenceOracle* presenceOracle, SubscriptionManager* subscriptionManager, EventController* eventController, UIEventStream* uiEventStream, IQRouter* iqRouter, SettingsProvider* settings)
- : myJID_(jid), xmppRoster_(xmppRoster), mainWindowFactory_(mainWindowFactory), mainWindow_(mainWindowFactory_->createMainWindow(uiEventStream)), roster_(new Roster()), offlineFilter_(new OfflineRosterFilter()) {
+RosterController::RosterController(const JID& jid, XMPPRoster* xmppRoster, AvatarManager* avatarManager, MainWindowFactory* mainWindowFactory, NickManager* nickManager, NickResolver* nickResolver, PresenceOracle* presenceOracle, SubscriptionManager* subscriptionManager, EventController* eventController, UIEventStream* uiEventStream, IQRouter* iqRouter, SettingsProvider* settings)
+ : myJID_(jid), xmppRoster_(xmppRoster), mainWindowFactory_(mainWindowFactory), mainWindow_(mainWindowFactory_->createMainWindow(uiEventStream)), roster_(new Roster()), offlineFilter_(new OfflineRosterFilter()), nickManager_(nickManager), nickResolver_(nickResolver) {
 	iqRouter_ = iqRouter;
 	presenceOracle_ = presenceOracle;
 	subscriptionManager_ = subscriptionManager;
@@ -63,13 +64,21 @@ RosterController::RosterController(const JID& jid, XMPPRoster* xmppRoster, Avata
 	avatarManager_ = avatarManager;
 	avatarManager_->onAvatarChanged.connect(boost::bind(&RosterController::handleAvatarChanged, this, _1));
 	mainWindow_->setMyAvatarPath(avatarManager_->getAvatarPath(myJID_).string());
-	setNickResolver(nickResolver);
+
+	nickManager_->onOwnNickChanged.connect(boost::bind(&MainWindow::setMyNick, mainWindow_, _1));
+	mainWindow_->setMyJID(jid);
+	mainWindow_->setMyNick(nickManager_->getOwnNick());
+
+	mainWindow_->onChangeNickRequest.connect(boost::bind(&NickManager::setOwnNick, nickManager_, _1));
+
 	if (settings->getBoolSetting(SHOW_OFFLINE, false)) {
 		uiEventStream->onUIEvent(boost::shared_ptr<UIEvent>(new ToggleShowOfflineUIEvent(true)));
 	}
 }
 
 RosterController::~RosterController() {
+	nickManager_->onOwnNickChanged.disconnect(boost::bind(&MainWindow::setMyNick, mainWindow_, _1));
+
 	delete offlineFilter_;
 	delete expandiness_;
 	mainWindow_->setRosterModel(NULL);
@@ -79,19 +88,6 @@ RosterController::~RosterController() {
 	delete roster_;
 }
 
-void RosterController::setNickResolver(NickResolver* nickResolver) {
-	nickResolver_ = nickResolver;
-	if (nickResolver_ != NULL) {
-		handleOwnNickChanged(nickResolver_->jidToNick(myJID_));
-
-		nickResolver_->onOwnNickChanged.connect(boost::bind(&RosterController::handleOwnNickChanged, this, _1));
-	}
-}
-
-void RosterController::handleOwnNickChanged(const String& nick) {
-	mainWindow_->setMyName(nick);
-}
-
 void RosterController::setEnabled(bool enabled) {
 	if (!enabled) {
 		roster_->applyOnItems(AppearOffline());
diff --git a/Swift/Controllers/RosterController.h b/Swift/Controllers/RosterController.h
index 2b1793e..79c14b9 100644
--- a/Swift/Controllers/RosterController.h
+++ b/Swift/Controllers/RosterController.h
@@ -33,14 +33,14 @@ namespace Swift {
 	class UIEventStream;
 	class IQRouter;
 	class SettingsProvider;
+	class NickManager;
 
 	class RosterController {
 		public:
-			RosterController(const JID& jid, XMPPRoster* xmppRoster, AvatarManager* avatarManager, MainWindowFactory* mainWindowFactory, NickResolver* nickResolver, PresenceOracle* presenceOracle, SubscriptionManager* subscriptionManager, EventController* eventController, UIEventStream* uiEventStream, IQRouter* iqRouter_, SettingsProvider* settings);
+			RosterController(const JID& jid, XMPPRoster* xmppRoster, AvatarManager* avatarManager, MainWindowFactory* mainWindowFactory, NickManager* nickManager, NickResolver* nickResolver, PresenceOracle* presenceOracle, SubscriptionManager* subscriptionManager, EventController* eventController, UIEventStream* uiEventStream, IQRouter* iqRouter_, SettingsProvider* settings);
 			~RosterController();
 			void showRosterWindow();
 			MainWindow* getWindow() {return mainWindow_;};
-			void setNickResolver(NickResolver* nickResolver);
 			boost::signal<void (StatusShow::Type, const String&)> onChangeStatusRequest;
 			boost::signal<void ()> onSignOutRequest;
 			void handleAvatarChanged(const JID& jid);
@@ -59,7 +59,6 @@ namespace Swift {
 			void handleSubscriptionRequestDeclined(SubscriptionRequestEvent* event);
 			void handleUIEvent(boost::shared_ptr<UIEvent> event);
 			void handleRosterSetError(ErrorPayload::ref error, boost::shared_ptr<RosterPayload> rosterPayload);
-			void handleOwnNickChanged(const String& nick);
 			void applyAllPresenceTo(const JID& jid);
 			JID myJID_;
 			XMPPRoster* xmppRoster_;
@@ -68,6 +67,7 @@ namespace Swift {
 			Roster* roster_;
 			OfflineRosterFilter* offlineFilter_;
 			AvatarManager* avatarManager_;
+			NickManager* nickManager_;
 			NickResolver* nickResolver_;
 			PresenceOracle* presenceOracle_;
 			SubscriptionManager* subscriptionManager_;
diff --git a/Swift/Controllers/UIInterfaces/MainWindow.h b/Swift/Controllers/UIInterfaces/MainWindow.h
index 0d33466..124d229 100644
--- a/Swift/Controllers/UIInterfaces/MainWindow.h
+++ b/Swift/Controllers/UIInterfaces/MainWindow.h
@@ -25,7 +25,8 @@ namespace Swift {
 				return canDelete_;
 			}
 
-			virtual void setMyName(const String& name) = 0;
+			virtual void setMyNick(const String& name) = 0;
+			virtual void setMyJID(const JID& jid) = 0;
 			virtual void setMyAvatarPath(const String& path) = 0;
 			virtual void setMyStatusText(const String& status) = 0;
 			virtual void setMyStatusType(StatusShow::Type type) = 0;
@@ -35,6 +36,7 @@ namespace Swift {
 			
 			boost::signal<void (StatusShow::Type, const String&)> onChangeStatusRequest;
 			boost::signal<void ()> onSignOutRequest;
+			boost::signal<void (const String&)> onChangeNickRequest;
 
 		private:
 			bool canDelete_;
diff --git a/Swift/Controllers/UnitTest/MockMainWindow.h b/Swift/Controllers/UnitTest/MockMainWindow.h
index 3d786d9..79c148a 100644
--- a/Swift/Controllers/UnitTest/MockMainWindow.h
+++ b/Swift/Controllers/UnitTest/MockMainWindow.h
@@ -15,7 +15,8 @@ namespace Swift {
 			MockMainWindow() {};
 			virtual ~MockMainWindow() {};
 			virtual void setRosterModel(Roster* roster) {this->roster = roster;};
-			virtual void setMyName(const String& /*name*/) {};;
+			virtual void setMyNick(const String& /*name*/) {};;
+			virtual void setMyJID(const JID& /*jid*/) {};;
 			virtual void setMyAvatarPath(const String& /*path*/) {};
 			virtual void setMyStatusText(const String& /*status*/) {};
 			virtual void setMyStatusType(StatusShow::Type /*type*/) {};
diff --git a/Swift/Controllers/UnitTest/RosterControllerTest.cpp b/Swift/Controllers/UnitTest/RosterControllerTest.cpp
index 50419f9..df93ca5 100644
--- a/Swift/Controllers/UnitTest/RosterControllerTest.cpp
+++ b/Swift/Controllers/UnitTest/RosterControllerTest.cpp
@@ -30,6 +30,7 @@
 #include "Swift/Controllers/UIEvents/RenameRosterItemUIEvent.h"
 #include "Swift/Controllers/UIEvents/RegroupRosterItemUIEvent.h"
 #include "Swiften/MUC/MUCRegistry.h"
+#include <Swiften/Client/DummyNickManager.h>
 
 using namespace Swift;
 
@@ -67,12 +68,14 @@ class RosterControllerTest : public CppUnit::TestFixture
 			eventController_ = new EventController();
 			uiEventStream_ = new UIEventStream();
 			settings_ = new DummySettingsProvider();
-			rosterController_ = new RosterController(jid_, xmppRoster_, avatarManager_, mainWindowFactory_, nickResolver_, presenceOracle_, subscriptionManager_, eventController_, uiEventStream_, router_, settings_);
+			nickManager_ = new DummyNickManager();
+			rosterController_ = new RosterController(jid_, xmppRoster_, avatarManager_, mainWindowFactory_, nickManager_, nickResolver_, presenceOracle_, subscriptionManager_, eventController_, uiEventStream_, router_, settings_);
 			mainWindow_ = mainWindowFactory_->last;
 		};
 
 		void tearDown() {
 			delete rosterController_;
+			delete nickManager_;
 			delete nickResolver_;
 			delete mucRegistry_;
 			delete mainWindowFactory_;
@@ -304,6 +307,7 @@ class RosterControllerTest : public CppUnit::TestFixture
 		MUCRegistry* mucRegistry_;
 		AvatarManager* avatarManager_;
 		MockMainWindowFactory* mainWindowFactory_;
+		NickManager* nickManager_;
 		NickResolver* nickResolver_;
 		RosterController* rosterController_;
 		DummyIQChannel* channel_;
diff --git a/Swift/QtUI/QtMainWindow.cpp b/Swift/QtUI/QtMainWindow.cpp
index 710ef61..fb84da4 100644
--- a/Swift/QtUI/QtMainWindow.cpp
+++ b/Swift/QtUI/QtMainWindow.cpp
@@ -40,6 +40,7 @@ QtMainWindow::QtMainWindow(UIEventStream* uiEventStream) : QWidget(), MainWindow
 	meView_ = new QtRosterHeader(this);
 	mainLayout->addWidget(meView_);
 	connect(meView_, SIGNAL(onChangeStatusRequest(StatusShow::Type, const QString&)), this, SLOT(handleStatusChanged(StatusShow::Type, const QString&)));
+	connect(meView_, SIGNAL(onChangeNickRequest(const QString&)), this, SLOT(handleChangeNickRequest(const QString&)));
 
 	tabs_ = new QtTabWidget(this);
 #if QT_VERSION >= 0x040500
@@ -162,8 +163,12 @@ void QtMainWindow::handleShowOfflineToggled(bool state) {
 	}
 }
 
-void QtMainWindow::setMyName(const String& name) {
-	meView_->setName(P2QSTRING(name));
+void QtMainWindow::setMyNick(const String& nick) {
+	meView_->setNick(P2QSTRING(nick));
+}
+
+void QtMainWindow::setMyJID(const JID& jid) {
+	meView_->setJID(P2QSTRING(jid.toBare().toString()));
 }
 
 void QtMainWindow::setMyAvatarPath(const String& path) {
@@ -182,5 +187,9 @@ void QtMainWindow::setConnecting() {
 	meView_->setConnecting();
 }
 
+void QtMainWindow::handleChangeNickRequest(const QString& nick) {
+	onChangeNickRequest(Q2PSTRING(nick));
+}
+
 }
 
diff --git a/Swift/QtUI/QtMainWindow.h b/Swift/QtUI/QtMainWindow.h
index 9e200b1..ccec12c 100644
--- a/Swift/QtUI/QtMainWindow.h
+++ b/Swift/QtUI/QtMainWindow.h
@@ -38,7 +38,8 @@ namespace Swift {
 			QtMainWindow(UIEventStream* eventStream);
 			~QtMainWindow();
 			std::vector<QMenu*> getMenus() {return menus_;}
-			void setMyName(const String& name);
+			void setMyNick(const String& name);
+			void setMyJID(const JID& jid);
 			void setMyAvatarPath(const String& path);
 			void setMyStatusText(const String& status);
 			void setMyStatusType(StatusShow::Type type);
@@ -55,6 +56,8 @@ namespace Swift {
 			void handleAddContactDialogComplete(const JID& contact, const QString& name);
 			void handleAddActionTriggered(bool checked);
 			void handleEventCountUpdated(int count);
+			void handleChangeNickRequest(const QString& nick);
+
 		private:
 			std::vector<QMenu*> menus_;
 			QtTreeWidget* treeWidget_;
diff --git a/Swift/QtUI/QtNameWidget.cpp b/Swift/QtUI/QtNameWidget.cpp
new file mode 100644
index 0000000..bf38da8
--- /dev/null
+++ b/Swift/QtUI/QtNameWidget.cpp
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2010 Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#include "QtNameWidget.h"
+
+#include <QStackedWidget>
+#include <QHBoxLayout>
+#include <QMouseEvent>
+
+#include <Swift/QtUI/QtElidingLabel.h>
+#include <Swift/QtUI/QtSwiftUtil.h>
+#include <Swift/QtUI/QtLineEdit.h>
+
+namespace Swift {
+
+QtNameWidget::QtNameWidget(QWidget *parent) : QWidget(parent) {
+	QHBoxLayout* mainLayout = new QHBoxLayout(this);
+	mainLayout->setSpacing(0);
+	mainLayout->setContentsMargins(0,0,0,0);
+
+	stack = new QStackedWidget(this);
+	mainLayout->addWidget(stack);
+
+	textLabel = new QtElidingLabel(this);
+	QFont font = textLabel->font();
+	font.setBold(true);
+	textLabel->setFont(font);
+	stack->addWidget(textLabel);
+
+	nickEdit = new QtLineEdit(this);
+	connect(nickEdit, SIGNAL(returnPressed()), this, SLOT(handleEditComplete()));
+	connect(nickEdit, SIGNAL(escapePressed()), this, SLOT(handleEditCancelled()));
+	stack->addWidget(nickEdit);
+}
+
+void QtNameWidget::mouseDoubleClickEvent(QMouseEvent* event) {
+	if (stack->currentWidget() != nickEdit) {
+		if (event->button() == Qt::LeftButton) {
+			nickEdit->setText(nick);
+			stack->setCurrentWidget(nickEdit);
+		}
+	}
+}
+
+void QtNameWidget::handleEditComplete() {
+	stack->setCurrentWidget(textLabel);
+	emit onChangeNickRequest(nickEdit->text());
+}
+
+void QtNameWidget::handleEditCancelled() {
+	stack->setCurrentWidget(textLabel);
+}
+
+void QtNameWidget::setNick(const QString& nick) {
+	this->nick = nick;
+	updateText();
+}
+
+void QtNameWidget::setJID(const QString& jid) {
+	this->jid = jid;
+	updateText();
+}
+
+void QtNameWidget::updateText() {
+	QString text;
+	if (nick.isEmpty()) {
+		text = jid;
+	}
+	else {
+		text = nick + " (" + jid + ")";
+	}
+	text.replace("<","&lt;");
+	textLabel->setText(text);
+}
+
+}
+
+
+
+
diff --git a/Swift/QtUI/QtNameWidget.h b/Swift/QtUI/QtNameWidget.h
new file mode 100644
index 0000000..c1c3e07
--- /dev/null
+++ b/Swift/QtUI/QtNameWidget.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2010 Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#pragma once
+
+#include <QWidget>
+
+class QLabel;
+class QStackedWidget;
+
+namespace Swift {
+	class QtElidingLabel;
+	class QtLineEdit;
+
+	class QtNameWidget : public QWidget {
+			Q_OBJECT
+
+		public:
+			QtNameWidget(QWidget *parent);
+
+			void setNick(const QString& text);
+			void setJID(const QString& jid);
+
+		signals:
+			/**
+			 * When this is emitted, the widget is disabled until
+			 * setNick() is called.
+			 */
+			void onChangeNickRequest(const QString& nick);
+
+		private slots:
+			void handleEditComplete();
+			void handleEditCancelled();
+			virtual void mouseDoubleClickEvent(QMouseEvent* event);
+
+		private:
+			void updateText();
+
+		private:
+			QStackedWidget* stack;
+			QtElidingLabel* textLabel;
+			QtLineEdit* nickEdit;
+			QString jid;
+			QString nick;
+	};
+}
+
diff --git a/Swift/QtUI/QtRosterHeader.cpp b/Swift/QtUI/QtRosterHeader.cpp
index e6b5f1b..efc198a 100644
--- a/Swift/QtUI/QtRosterHeader.cpp
+++ b/Swift/QtUI/QtRosterHeader.cpp
@@ -14,8 +14,8 @@
 #include <QMouseEvent>
 
 #include "QtStatusWidget.h"
-#include "Swift/QtUI/QtElidingLabel.h"
-
+#include <Swift/QtUI/QtElidingLabel.h>
+#include <Swift/QtUI/QtNameWidget.h>
 
 namespace Swift {
 QtRosterHeader::QtRosterHeader(QWidget* parent) : QWidget(parent) {
@@ -39,12 +39,9 @@ QtRosterHeader::QtRosterHeader(QWidget* parent) : QWidget(parent) {
 	rightLayout->setContentsMargins(4,0,0,0);
 	topLayout->addLayout(rightLayout);
 
-	nameLabel_ = new QtElidingLabel(this);
-	setName("Me");
-	QFont font = nameLabel_->font();
-	font.setBold(true);
-	nameLabel_->setFont(font);
-	rightLayout->addWidget(nameLabel_);
+	nameWidget_ = new QtNameWidget(this);
+	connect(nameWidget_, SIGNAL(onChangeNickRequest(const QString&)), this, SIGNAL(onChangeNickRequest(const QString&)));
+	rightLayout->addWidget(nameWidget_);
 
 
 	statusWidget_ = new QtStatusWidget(this);
@@ -95,40 +92,6 @@ void QtRosterHeader::setConnecting() {
 	statusWidget_->setConnecting();
 }
 
-void QtRosterHeader::setName(const QString& name) {
-	name_ = name;
-	QString escapedName = name_;
-	escapedName.replace("<","&lt;");
-// 	nameLabel_->setText("<b>" + escapedName + "</b>");
- 	nameLabel_->setText(escapedName);
-//	resizeNameLabel();
-}
-
-// void QtRosterHeader::resizeNameLabel() {	
-// 	QString escapedName = name_;
-// 	escapedName.replace("<","&lt;");
-// 	nameLabel_->setText("<b>" + escapedName + "</b>");
-// 	return;
-// 	//FIXME: Make this not an infinite loop, so it can be continued.
-	
-// 	int reductionCount = 0;
-// 	while (nameLabel_->sizeHint().width() + statusWidget_->width() + 30 > width()) {
-// 		//qDebug() << nameLabel_->sizeHint().width() << " " << statusWidget_->width() << " " << width();
-// 		reductionCount++;
-// 		QString reducedName = name_;
-// 		reducedName.remove(name_.length() - reductionCount, reductionCount);
-// 		reducedName.replace("<","&lt;");
-// 		nameLabel_->setText("<b>" + reducedName +  + "...</b>");
-// 	//	qDebug() << "Shrunk " << escapedName << " down to " << reducedName;
-// 	}
-// 	nameLabel_->setToolTip(name_);
-// }
-
-//void QtRosterHeader::resizeEvent(QResizeEvent* event) {
-//	QWidget::resizeEvent(event);
-//	resizeNameLabel();
-//}
-
 void QtRosterHeader::setAvatar(const QString& path) {
 	QIcon avatar(path);
 	if (avatar.isNull()) {
@@ -138,9 +101,15 @@ void QtRosterHeader::setAvatar(const QString& path) {
 	avatarLabel_->setPixmap(avatar.pixmap(avatarSize_, avatarSize_));
 }
 
-//QSize QtRosterHeader::sizeHint() const {
-//	return minimumSizeHint();
-//}
+void QtRosterHeader::setNick(const QString& nick) {
+	nameWidget_->setNick(nick);
+}
+
+void QtRosterHeader::setJID(const QString& jid) {
+	nameWidget_->setJID(jid);
+}
+
+
 
 const int QtRosterHeader::avatarSize_ = 40;
 
diff --git a/Swift/QtUI/QtRosterHeader.h b/Swift/QtUI/QtRosterHeader.h
index 6330200..cd5f26c 100644
--- a/Swift/QtUI/QtRosterHeader.h
+++ b/Swift/QtUI/QtRosterHeader.h
@@ -21,25 +21,30 @@ class QHBoxLayout;
 
 namespace Swift {
 	class QtStatusWidget;
-	class QtElidingLabel;
+	class QtNameWidget;
 	
 	class QtRosterHeader : public QWidget {
 		Q_OBJECT
 	public:
 		QtRosterHeader(QWidget* parent = NULL);
 		void setAvatar(const QString& path);
-		void setName(const QString& name);
+
+		void setJID(const QString& jid);
+		void setNick(const QString& nick);
+
 		void setStatusText(const QString& statusMessage);
 		void setStatusType(StatusShow::Type type);
 		void setConnecting();
 	signals:
 		void onChangeStatusRequest(StatusShow::Type showType, const QString &statusMessage);
+		void onChangeNickRequest(const QString &nick);
+
 	private slots:
 		void handleChangeStatusRequest(StatusShow::Type type, const QString &statusMessage);
 	private:
 		QString name_;
 		QLabel* avatarLabel_;
-		QtElidingLabel* nameLabel_;
+		QtNameWidget* nameWidget_;
 		QtTextEdit* statusEdit_;
 		QToolBar* toolBar_;
 		QtStatusWidget* statusWidget_;
diff --git a/Swift/QtUI/SConscript b/Swift/QtUI/SConscript
index 53c023a..864fdb5 100644
--- a/Swift/QtUI/SConscript
+++ b/Swift/QtUI/SConscript
@@ -69,6 +69,7 @@ sources = [
     "QtLoginWindowFactory.cpp",
     "QtMainWindow.cpp",
     "QtMainWindowFactory.cpp",
+    "QtNameWidget.cpp",
     "QtSettingsProvider.cpp",
     "QtStatusWidget.cpp",
     "QtSwift.cpp",
diff --git a/Swiften/Client/Client.cpp b/Swiften/Client/Client.cpp
index dcc8a79..d3dcd3e 100644
--- a/Swiften/Client/Client.cpp
+++ b/Swiften/Client/Client.cpp
@@ -24,6 +24,7 @@
 #include "Swiften/Client/NickResolver.h"
 #include "Swiften/Presence/SubscriptionManager.h"
 #include "Swiften/TLS/BlindCertificateTrustChecker.h"
+#include <Swiften/Client/NickManagerImpl.h>
 
 namespace Swift {
 
@@ -53,6 +54,7 @@ Client::Client(EventLoop* eventLoop, NetworkFactories* networkFactories, const J
 	capsManager = new CapsManager(getStorages()->getCapsStorage(), getStanzaChannel(), getIQRouter());
 	entityCapsManager = new EntityCapsManager(capsManager, getStanzaChannel());
 
+	nickManager = new NickManagerImpl(jid.toBare(), vcardManager);
 	nickResolver = new NickResolver(jid.toBare(), roster, vcardManager, mucRegistry);
 
 	blindCertificateTrustChecker = new BlindCertificateTrustChecker();
@@ -62,6 +64,7 @@ Client::~Client() {
 	delete blindCertificateTrustChecker;
 
 	delete nickResolver;
+	delete nickManager;
 
 	delete entityCapsManager;
 	delete capsManager;
@@ -121,8 +124,13 @@ EntityCapsProvider* Client::getEntityCapsProvider() const {
 	return entityCapsManager;
 }
 
+
 void Client::setAlwaysTrustCertificates() {
 	setCertificateTrustChecker(blindCertificateTrustChecker);
 }
 
+NickManager* Client::getNickManager() const {
+	return nickManager;
+}
+
 }
diff --git a/Swiften/Client/Client.h b/Swiften/Client/Client.h
index 6fa3a34..975d499 100644
--- a/Swiften/Client/Client.h
+++ b/Swiften/Client/Client.h
@@ -30,6 +30,7 @@ namespace Swift {
 	class NickResolver;
 	class SubscriptionManager;
 	class ClientDiscoManager;
+	class NickManager;
 
 	/**
 	 * Provides the core functionality for writing XMPP client software.
@@ -115,6 +116,8 @@ namespace Swift {
 
 			EntityCapsProvider* getEntityCapsProvider() const;
 
+			NickManager* getNickManager() const;
+
 			NickResolver* getNickResolver() const {
 				return nickResolver;
 			}
@@ -158,6 +161,7 @@ namespace Swift {
 			AvatarManager* avatarManager;
 			CapsManager* capsManager;
 			EntityCapsManager* entityCapsManager;
+			NickManager* nickManager;
 			NickResolver* nickResolver;
 			SubscriptionManager* subscriptionManager;
 			MUCManager* mucManager;
diff --git a/Swiften/Client/DummyNickManager.h b/Swiften/Client/DummyNickManager.h
new file mode 100644
index 0000000..27a42c0
--- /dev/null
+++ b/Swiften/Client/DummyNickManager.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2010 Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Client/NickManager.h>
+
+namespace Swift {
+	class VCardManager;
+
+	class DummyNickManager : public NickManager {
+		public:
+			String getOwnNick() const {
+				return "";
+			}
+
+			void setOwnNick(const String& nick) {
+			}
+	};
+}
diff --git a/Swiften/Client/NickManager.cpp b/Swiften/Client/NickManager.cpp
new file mode 100644
index 0000000..90e3217
--- /dev/null
+++ b/Swiften/Client/NickManager.cpp
@@ -0,0 +1,14 @@
+/*
+ * Copyright (c) 2010 Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#include <Swiften/Client/NickManager.h>
+
+namespace Swift {
+
+NickManager::~NickManager()  {
+}
+
+}
diff --git a/Swiften/Client/NickManager.h b/Swiften/Client/NickManager.h
new file mode 100644
index 0000000..e918b07
--- /dev/null
+++ b/Swiften/Client/NickManager.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2010 Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Base/boost_bsignals.h>
+#include <Swiften/Base/String.h>
+
+namespace Swift {
+	class NickManager {
+		public:
+			virtual ~NickManager();
+
+			virtual String getOwnNick() const = 0;
+			virtual void setOwnNick(const String& nick) = 0;
+
+			boost::signal<void (const String&)> onOwnNickChanged;
+	};
+}
diff --git a/Swiften/Client/NickManagerImpl.cpp b/Swiften/Client/NickManagerImpl.cpp
new file mode 100644
index 0000000..09f8de5
--- /dev/null
+++ b/Swiften/Client/NickManagerImpl.cpp
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2010 Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#include <Swiften/Client/NickManagerImpl.h>
+
+#include <boost/bind.hpp>
+
+#include <Swiften/VCards/VCardManager.h>
+
+namespace Swift {
+
+NickManagerImpl::NickManagerImpl(const JID& ownJID, VCardManager* vcardManager) : ownJID(ownJID), vcardManager(vcardManager) {
+	vcardManager->onVCardChanged.connect(boost::bind(&NickManagerImpl::handleVCardReceived, this, _1, _2));
+}
+
+NickManagerImpl::~NickManagerImpl() {
+	vcardManager->onVCardChanged.disconnect(boost::bind(&NickManagerImpl::handleVCardReceived, this, _1, _2));
+}
+
+String NickManagerImpl::getOwnNick() const {
+	return ownJID;
+}
+
+void NickManagerImpl::setOwnNick(const String&) {
+}
+
+void NickManagerImpl::handleVCardReceived(const JID& jid, VCard::ref vcard) {
+	if (!jid.equals(ownJID, JID::WithoutResource)) {
+		return;
+	}
+
+	String nick;
+	if (!vcard->getNickname().isEmpty()) {
+		nick = vcard->getNickname();
+	}
+	if (ownNick != nick) {
+		ownNick = nick;
+		onOwnNickChanged(ownNick);
+	}
+}
+
+}
diff --git a/Swiften/Client/NickManagerImpl.h b/Swiften/Client/NickManagerImpl.h
new file mode 100644
index 0000000..87c9711
--- /dev/null
+++ b/Swiften/Client/NickManagerImpl.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2010 Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Client/NickManager.h>
+#include <Swiften/Elements/VCard.h>
+#include <Swiften/JID/JID.h>
+#include <Swiften/Base/String.h>
+
+namespace Swift {
+	class VCardManager;
+
+	class NickManagerImpl : public NickManager {
+		public:
+			NickManagerImpl(const JID& ownJID, VCardManager* vcardManager);
+			~NickManagerImpl();
+
+			String getOwnNick() const;
+			void setOwnNick(const String& nick);
+
+		private:
+			void handleVCardReceived(const JID& jid, VCard::ref vCard);
+
+		private:
+			JID ownJID;
+			VCardManager* vcardManager;
+			String ownNick;
+	};
+}
diff --git a/Swiften/Client/NickResolver.cpp b/Swiften/Client/NickResolver.cpp
index c151dfa..9bfe269 100644
--- a/Swiften/Client/NickResolver.cpp
+++ b/Swiften/Client/NickResolver.cpp
@@ -16,6 +16,7 @@
 // FIXME: The NickResolver currently relies on the vcard being requested by the client on login.
 // The VCardManager should get an onConnected() signal (which is signalled when the stanzachannel is available(, and each time this is emitted,
 // the nickresolver should request the vcard.
+// FIXME: The ownJID functionality should probably be removed, and NickManager should be used directly.
 
 namespace Swift {
 
@@ -67,9 +68,6 @@ void NickResolver::handleVCardReceived(const JID& jid, VCard::ref ownVCard) {
 			ownNick_ = ownVCard->getFullName();
 		}
 	}
-	if (ownNick_ != initialNick) {
-		onOwnNickChanged(ownNick_);
-	}
 }
 
 }
diff --git a/Swiften/Client/NickResolver.h b/Swiften/Client/NickResolver.h
index 806afb8..de7d64a 100644
--- a/Swiften/Client/NickResolver.h
+++ b/Swiften/Client/NickResolver.h
@@ -22,8 +22,8 @@ namespace Swift {
 
 			String jidToNick(const JID& jid);
 
-			boost::signal<void (const String&)> onOwnNickChanged;
 			boost::signal<void (const JID&, const String& /*previousNick*/)> onNickChanged;
+
 		private:
 			void handleVCardReceived(const JID& jid, VCard::ref vCard);
 			void handleJIDUpdated(const JID& jid, const String& previousNick, const std::vector<String>& groups);
diff --git a/Swiften/SConscript b/Swiften/SConscript
index c5198a6..a4eb75d 100644
--- a/Swiften/SConscript
+++ b/Swiften/SConscript
@@ -49,6 +49,8 @@ if env["SCONS_STAGE"] == "build" :
 			"Client/MemoryStorages.cpp",
 			"Client/FileStorages.cpp",
 			"Client/NickResolver.cpp",
+			"Client/NickManager.cpp",
+			"Client/NickManagerImpl.cpp",
 			"Compress/ZLibCodecompressor.cpp",
 			"Compress/ZLibDecompressor.cpp",
 			"Compress/ZLibCompressor.cpp",
-- 
cgit v0.10.2-6-g49f6