From 9e3d7f4183f515a4d768be8166936340dee5a9b9 Mon Sep 17 00:00:00 2001
From: Kevin Smith <git@kismith.co.uk>
Date: Sat, 1 Aug 2009 18:21:06 +0100
Subject: Roster now includes avatars.


diff --git a/Swift/Controllers/MainController.cpp b/Swift/Controllers/MainController.cpp
index 77e531e..0f654e4 100644
--- a/Swift/Controllers/MainController.cpp
+++ b/Swift/Controllers/MainController.cpp
@@ -109,8 +109,11 @@ void MainController::handleConnected() {
 	delete nickResolver_;
 	nickResolver_ = new NickResolver(xmppRoster);
 
+	delete avatarManager_;
+	avatarManager_ = new AvatarManager(client_, client_, avatarStorage_, this);
+	
 	delete rosterController_;
-	rosterController_ = new RosterController(xmppRoster, mainWindowFactory_, treeWidgetFactory_);
+	rosterController_ = new RosterController(xmppRoster, avatarManager_, mainWindowFactory_, treeWidgetFactory_);
 	rosterController_->onStartChatRequest.connect(boost::bind(&MainController::handleChatRequest, this, _1));
 	rosterController_->onJoinMUCRequest.connect(boost::bind(&MainController::handleJoinMUCRequest, this, _1, _2));
 	rosterController_->onChangeStatusRequest.connect(boost::bind(&MainController::handleChangeStatusRequest, this, _1, _2));
@@ -123,9 +126,6 @@ void MainController::handleConnected() {
 	clientVersionResponder_ = new SoftwareVersionResponder(CLIENT_NAME, CLIENT_VERSION, client_);
 	loginWindow_->morphInto(rosterController_->getWindow());
 
-	delete avatarManager_;
-	avatarManager_ = new AvatarManager(client_, client_, avatarStorage_, this);
-
 	DiscoInfo discoInfo;
 	discoInfo.addIdentity(DiscoInfo::Identity(CLIENT_NAME, "client", "pc"));
 	capsInfo_ = boost::shared_ptr<CapsInfo>(new CapsInfo(CapsInfoGenerator(CLIENT_NODE).generateCapsInfo(discoInfo)));
diff --git a/Swift/Controllers/RosterController.cpp b/Swift/Controllers/RosterController.cpp
index c447602..3662241 100644
--- a/Swift/Controllers/RosterController.cpp
+++ b/Swift/Controllers/RosterController.cpp
@@ -9,6 +9,7 @@
 #include "Swiften/EventLoop/MainEventLoop.h"
 #include "Swiften/Roster/Roster.h"
 #include "Swiften/Roster/SetPresence.h"
+#include "Swiften/Roster/SetAvatar.h"
 #include "Swiften/Roster/OfflineRosterFilter.h"
 #include "Swiften/Roster/OpenChatRosterAction.h"
 #include "Swiften/Roster/TreeWidgetFactory.h"
@@ -19,9 +20,11 @@ namespace Swift {
 /**
  * The controller does not gain ownership of these parameters.
  */
-RosterController::RosterController(boost::shared_ptr<XMPPRoster> xmppRoster, MainWindowFactory* mainWindowFactory, TreeWidgetFactory* treeWidgetFactory)
+RosterController::RosterController(boost::shared_ptr<XMPPRoster> xmppRoster, AvatarManager* avatarManager, MainWindowFactory* mainWindowFactory, TreeWidgetFactory* treeWidgetFactory)
  : xmppRoster_(xmppRoster), mainWindowFactory_(mainWindowFactory), treeWidgetFactory_(treeWidgetFactory), mainWindow_(mainWindowFactory_->createMainWindow()), roster_(new Roster(mainWindow_->getTreeWidget(), treeWidgetFactory_)), offlineFilter_(new OfflineRosterFilter()) {
 	roster_->addFilter(offlineFilter_);
+	avatarManager_ = avatarManager;
+	avatarManager_->onAvatarChanged.connect(boost::bind(&RosterController::handleAvatarChanged, this, _1, _2));
 	mainWindow_->onStartChatRequest.connect(boost::bind(&RosterController::handleStartChatRequest, this, _1));
 	mainWindow_->onJoinMUCRequest.connect(boost::bind(&RosterController::handleJoinMUCRequest, this, _1, _2));
 	mainWindow_->onChangeStatusRequest.connect(boost::bind(&RosterController::handleChangeStatusRequest, this, _1, _2));
@@ -72,6 +75,11 @@ void RosterController::handleIncomingPresence(boost::shared_ptr<Presence> presen
 	roster_->applyOnItems(SetPresence(presence));
 }
 
+void RosterController::handleAvatarChanged(const JID& jid, const String& hash) {
+	String path = avatarManager_->getAvatarPath(jid).string();
+	roster_->applyOnItems(SetAvatar(jid, path));
+}
+
 void RosterController::handleStartChatRequest(const JID& contact) {
 	onStartChatRequest(contact);
 }
diff --git a/Swift/Controllers/RosterController.h b/Swift/Controllers/RosterController.h
index 945b068..f9f2258 100644
--- a/Swift/Controllers/RosterController.h
+++ b/Swift/Controllers/RosterController.h
@@ -5,6 +5,7 @@
 #include "Swiften/Base/String.h"
 #include "Swiften/Elements/Presence.h"
 #include "Swiften/Roster/UserRosterAction.h"
+#include "Swiften/Avatars/AvatarManager.h"
 
 #include <boost/signals.hpp>
 #include <boost/shared_ptr.hpp>
@@ -20,7 +21,7 @@ namespace Swift {
 
 	class RosterController {
 		public:
-			RosterController(boost::shared_ptr<XMPPRoster> xmppRoster, MainWindowFactory *mainWindowFactory, TreeWidgetFactory *treeWidgetFactory);
+			RosterController(boost::shared_ptr<XMPPRoster> xmppRoster, AvatarManager* avatarManager, MainWindowFactory *mainWindowFactory, TreeWidgetFactory *treeWidgetFactory);
 			~RosterController();
 			void showRosterWindow();
 			MainWindow* getWindow() {return mainWindow_;};
@@ -28,6 +29,7 @@ namespace Swift {
 			boost::signal<void (const JID&, const String&)> onJoinMUCRequest;
 			boost::signal<void (StatusShow::Type, const String&)> onChangeStatusRequest;
 			void handleIncomingPresence(boost::shared_ptr<Presence> presence);
+			void handleAvatarChanged(const JID& jid, const String& hash);
 
 		private:
 			void handleOnJIDAdded(const JID &jid);
@@ -42,6 +44,7 @@ namespace Swift {
 			MainWindow* mainWindow_;
 			Roster* roster_;
 			OfflineRosterFilter* offlineFilter_;
+			AvatarManager* avatarManager_;
 	};
 }
 #endif
diff --git a/Swift/QtUI/Roster/QtTreeWidgetItem.cpp b/Swift/QtUI/Roster/QtTreeWidgetItem.cpp
index bbb5e98..aa1836c 100644
--- a/Swift/QtUI/Roster/QtTreeWidgetItem.cpp
+++ b/Swift/QtUI/Roster/QtTreeWidgetItem.cpp
@@ -5,20 +5,24 @@
 
 namespace Swift {
 
-QtTreeWidgetItem::QtTreeWidgetItem(QtTreeWidgetItem* parentItem) : QObject() {
+QtTreeWidgetItem::QtTreeWidgetItem(QtTreeWidgetItem* parentItem) : QObject(), textColor_(0,0,0), backgroundColor_(255,255,255) {
 	parent_ = parentItem;
 	shown_ = true;
 }
 
 void QtTreeWidgetItem::setText(const String& text) {
 	displayName_ = P2QSTRING(text);
-	statusText_ = displayName_ + " went away";
 }
 
 void QtTreeWidgetItem::setStatusText(const String& text) {
 	statusText_ = P2QSTRING(text);
 }
 
+void QtTreeWidgetItem::setAvatarPath(const String& path) {
+	qDebug() << "Setting avatar to " << P2QSTRING(path);
+	avatar_ = QIcon(P2QSTRING(path));
+}
+
 void QtTreeWidgetItem::setTextColor(unsigned long color) {
 	textColor_ = QColor(
 	 					((color & 0xFF0000)>>16),
@@ -48,7 +52,7 @@ void QtTreeWidgetItem::show() {
 }
 
 bool QtTreeWidgetItem::isShown() {
-	return shown_;
+	return isContact() ? shown_ : shownChildren_.size() > 0;
 }
 
 QWidget* QtTreeWidgetItem::getCollapsedRosterWidget() {
@@ -88,7 +92,7 @@ void QtTreeWidgetItem::handleChanged() {
 }
 
 int QtTreeWidgetItem::rowCount() {
-	qDebug() << "Returning size of " << children_.size() << " for item " << displayName_;
+	//qDebug() << "Returning size of " << children_.size() << " for item " << displayName_;
 	return shownChildren_.size();
 }
 
@@ -101,14 +105,18 @@ int QtTreeWidgetItem::row() {
 }
 
 QtTreeWidgetItem* QtTreeWidgetItem::getItem(int row) {
-	qDebug() << "Returning row " << row << " from item " << displayName_;
+	//qDebug() << "Returning row " << row << " from item " << displayName_;
 	return shownChildren_[row];
 }
 
+
 QVariant QtTreeWidgetItem::data(int role) {
  	switch (role) {
 	 	case Qt::DisplayRole: return displayName_;
+		case Qt::TextColorRole: return textColor_;
+		case Qt::BackgroundColorRole: return backgroundColor_;
 	 	case StatusTextRole: return statusText_;
+		case AvatarRole: return avatar_;
 	 	default: return QVariant();
 	}
 }
diff --git a/Swift/QtUI/Roster/QtTreeWidgetItem.h b/Swift/QtUI/Roster/QtTreeWidgetItem.h
index e3bfff3..0a32940 100644
--- a/Swift/QtUI/Roster/QtTreeWidgetItem.h
+++ b/Swift/QtUI/Roster/QtTreeWidgetItem.h
@@ -2,6 +2,7 @@
 #define SWIFT_QtTreeWidgetItem_H
 
 #include <QColor>
+#include <QVariant>
 
 #include "Swiften/Base/String.h"
 #include "Swiften/Roster/TreeWidgetFactory.h"
@@ -33,6 +34,7 @@ class QtTreeWidgetItem : public QObject, public TreeWidgetItem {
 			QVariant data(int role);
 			QtTreeWidgetItem(QtTreeWidgetItem* parentItem);
 			void setText(const String& text);
+			void setAvatarPath(const String& path);
 			void setStatusText(const String& text);
 			void setTextColor(unsigned long color);
 			void setBackgroundColor(unsigned long color);
@@ -57,6 +59,7 @@ class QtTreeWidgetItem : public QObject, public TreeWidgetItem {
 			QString statusText_;
 			QColor textColor_;
 			QColor backgroundColor_;
+			QVariant avatar_;
 			bool shown_;
 };
 
diff --git a/Swift/QtUI/Roster/RosterDelegate.cpp b/Swift/QtUI/Roster/RosterDelegate.cpp
index 2447e8f..b05bbb1 100644
--- a/Swift/QtUI/Roster/RosterDelegate.cpp
+++ b/Swift/QtUI/Roster/RosterDelegate.cpp
@@ -16,7 +16,7 @@ QSize RosterDelegate::sizeHint(const QStyleOptionViewItem& option, const QModelI
 	}
 	//Doesn't work, yay! FIXME: why?
 	QSize size = (option.state & QStyle::State_Selected) ? QSize(150, 80) : QSize(150, avatarSize_ + margin_ * 2);
-	qDebug() << "Returning size" << size;
+	//qDebug() << "Returning size" << size;
 	return size;
 }
 
@@ -26,7 +26,7 @@ void RosterDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option
 		QStyledItemDelegate::paint(painter, option, index);
 		return;
 	}
-	qDebug() << "painting" << index.data(Qt::DisplayRole).toString();
+	//qDebug() << "painting" << index.data(Qt::DisplayRole).toString();
 	painter->save();
 	//QStyledItemDelegate::paint(painter, option, index);
 	//initStyleOption(option, index);
@@ -48,8 +48,10 @@ void RosterDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option
 	QRect textRegion(fullRegion.adjusted(avatarSize_ + margin_ * 2, 0, 0, 0));
 	
 	QFontMetrics nameMetrics(nameFont);
-	int nameHeight = nameMetrics.height() + margin_ * 2;
+	int nameHeight = nameMetrics.height() + margin_;
 	QRect nameRegion(textRegion.adjusted(0, margin_, 0, 0));
+	QColor nameColor = index.data(Qt::TextColorRole).value<QColor>();
+	painter->setPen(QPen(nameColor));
 	painter->drawText(nameRegion, Qt::AlignTop, index.data(Qt::DisplayRole).toString());
 	
 	statusFont.setStyle(QFont::StyleItalic);
diff --git a/Swift/QtUI/Roster/RosterModel.cpp b/Swift/QtUI/Roster/RosterModel.cpp
index 147aa67..f322792 100644
--- a/Swift/QtUI/Roster/RosterModel.cpp
+++ b/Swift/QtUI/Roster/RosterModel.cpp
@@ -18,7 +18,7 @@ void RosterModel::setRoot(QtTreeWidgetItem* root) {
 void RosterModel::handleItemChanged() {
 	//FIXME: This is just a lazy hack to cause the view to refresh until it works.
 	// Then I'll replace it with the proper implementation.
-	printf("Changed\n");
+	//printf("Changed\n");
 	reset();
 	emit layoutChanged();
 }
diff --git a/Swiften/Avatars/AvatarManager.h b/Swiften/Avatars/AvatarManager.h
index 984ce19..3ac4433 100644
--- a/Swiften/Avatars/AvatarManager.h
+++ b/Swiften/Avatars/AvatarManager.h
@@ -32,7 +32,7 @@ namespace Swift {
 			void handlePresenceReceived(boost::shared_ptr<Presence>);
 			void handleVCardReceived(const JID& from, const String& hash, boost::shared_ptr<VCard>, const boost::optional<Error>&);
 			void setAvatarHash(const JID& from, const String& hash);
-      JID getAvatarJID(const JID& o) const;
+			JID getAvatarJID(const JID& o) const;
 
 		private:
 			StanzaChannel* stanzaChannel_;
diff --git a/Swiften/Roster/ContactRosterItem.cpp b/Swiften/Roster/ContactRosterItem.cpp
index f38b0f7..2f2f787 100644
--- a/Swiften/Roster/ContactRosterItem.cpp
+++ b/Swiften/Roster/ContactRosterItem.cpp
@@ -34,6 +34,14 @@ void ContactRosterItem::setStatusShow(StatusShow::Type show) {
 	widget_->setTextColor(colour);
 }
 
+void ContactRosterItem::setStatusText(const String& status) {
+	widget_->setStatusText(status);
+}
+
+void ContactRosterItem::setAvatarPath(const String& path) {
+	widget_->setAvatarPath(path);
+}
+
 const JID& ContactRosterItem::getJID() const {
 	return jid_;
 }
diff --git a/Swiften/Roster/ContactRosterItem.h b/Swiften/Roster/ContactRosterItem.h
index 20f9f65..f1810aa 100644
--- a/Swiften/Roster/ContactRosterItem.h
+++ b/Swiften/Roster/ContactRosterItem.h
@@ -23,6 +23,8 @@ class ContactRosterItem : public RosterItem {
 
 		StatusShow::Type getStatusShow();
 		void setStatusShow(StatusShow::Type show);
+		void setStatusText(const String& status);
+		void setAvatarPath(const String& path);
 		const JID& getJID() const;
 		void show();
 		void hide();
diff --git a/Swiften/Roster/SetAvatar.h b/Swiften/Roster/SetAvatar.h
new file mode 100644
index 0000000..7bc9c37
--- /dev/null
+++ b/Swiften/Roster/SetAvatar.h
@@ -0,0 +1,33 @@
+#ifndef SWIFTEN_SetAvatar_H
+#define SWIFTEN_SetAvatar_H
+
+#include "Swiften/Elements/Presence.h"
+#include "Swiften/JID/JID.h"
+#include "Swiften/Roster/RosterItemOperation.h"
+#include "Swiften/Roster/ContactRosterItem.h"
+
+namespace Swift {
+
+class RosterItem;
+
+class SetAvatar : public RosterItemOperation {
+	public:
+		SetAvatar(const JID& jid, const String& path, JID::CompareType compareType = JID::WithoutResource) : jid_(jid), path_(path), compareType_(compareType) {
+		}
+
+		virtual void operator() (RosterItem* item) const {
+			ContactRosterItem* contact = dynamic_cast<ContactRosterItem*>(item);
+			if (contact && contact->getJID().equals(jid_, compareType_)) {
+				contact->setAvatarPath(path_);
+			}
+		}
+	
+	private:
+		JID jid_;
+		String path_;
+		JID::CompareType compareType_;
+};
+
+}
+#endif
+
diff --git a/Swiften/Roster/SetPresence.h b/Swiften/Roster/SetPresence.h
index aa36a52..a18ae6d 100644
--- a/Swiften/Roster/SetPresence.h
+++ b/Swiften/Roster/SetPresence.h
@@ -20,8 +20,10 @@ class SetPresence : public RosterItemOperation {
 			if (contact && contact->getJID().equals(presence_->getFrom(), compareType_)) {
 				if (presence_->getType() != Presence::Available) {
 					contact->setStatusShow(StatusShow::None);
+					contact->setStatusText(presence_->getStatus());
 				} else {
 					contact->setStatusShow(presence_->getShow());
+					contact->setStatusText(presence_->getStatus());
 				}
 			}
 		}
diff --git a/Swiften/Roster/TreeWidgetItem.h b/Swiften/Roster/TreeWidgetItem.h
index 5a96a41..4e20050 100644
--- a/Swiften/Roster/TreeWidgetItem.h
+++ b/Swiften/Roster/TreeWidgetItem.h
@@ -13,6 +13,8 @@ class TreeWidgetItem {
 	public:
 		virtual ~TreeWidgetItem() {}
 		virtual void setText(const String& text) = 0;
+		virtual void setStatusText(const String& text) = 0;
+		virtual void setAvatarPath(const String& path) = 0;
 		virtual void setExpanded(bool b) = 0;
 		virtual void setTextColor(unsigned long color) = 0;
 		virtual void setBackgroundColor(unsigned long color) = 0;
-- 
cgit v0.10.2-6-g49f6