From 7bca08eb2829982865f1649483f9aa01b3413b1c Mon Sep 17 00:00:00 2001
From: Kevin Smith <git@kismith.co.uk>
Date: Fri, 4 Jun 2010 23:09:21 +0100
Subject: Starting towards tooltips for the colour-blind.

Putting status show names along with the text in tooltips.
Covers the MeView and roster entries.

Still ToDo: status setter

Resolves: #429

diff --git a/Swift/Controllers/Chat/MUCController.cpp b/Swift/Controllers/Chat/MUCController.cpp
index e582f1b..14fe180 100644
--- a/Swift/Controllers/Chat/MUCController.cpp
+++ b/Swift/Controllers/Chat/MUCController.cpp
@@ -141,7 +141,11 @@ void MUCController::handleWindowClosed() {
 void MUCController::handleOccupantJoined(const MUCOccupant& occupant) {
 	receivedActivity();
 	JID jid(nickToJID(occupant.getNick()));
-	roster_->addContact(jid, occupant.getNick(), roleToGroupName(occupant.getRole()));
+	JID realJID;
+	if (occupant.getRealJID()) {
+		realJID = occupant.getRealJID().get();
+	}
+	roster_->addContact(jid, realJID, occupant.getNick(), roleToGroupName(occupant.getRole()));
 	if (joined_) {
 		String joinString = occupant.getNick() + " has joined the room";
 		MUCOccupant::Role role = occupant.getRole();
@@ -177,12 +181,16 @@ void MUCController::preHandleIncomingMessage(boost::shared_ptr<Message>) {
 	joined_ = true;
 }
 
-void MUCController::handleOccupantRoleChanged(const String& nick, const MUCOccupant::Role& newRole, const MUCOccupant::Role& oldRole) {
+void MUCController::handleOccupantRoleChanged(const String& nick, const MUCOccupant& occupant, const MUCOccupant::Role& oldRole) {
 	receivedActivity();
 	JID jid(nickToJID(nick));
 	roster_->removeContactFromGroup(jid, roleToGroupName(oldRole));
-	roster_->addContact(jid, nick, roleToGroupName(newRole));
-	chatWindow_->addSystemMessage(nick + " is now a " + roleToFriendlyName(newRole));
+	JID realJID;
+	if (occupant.getRealJID()) {
+		realJID = occupant.getRealJID().get();
+	}
+	roster_->addContact(jid, realJID, nick, roleToGroupName(occupant.getRole()));
+	chatWindow_->addSystemMessage(nick + " is now a " + roleToFriendlyName(occupant.getRole()));
 }
 
 String MUCController::roleToGroupName(MUCOccupant::Role role) {
diff --git a/Swift/Controllers/Chat/MUCController.h b/Swift/Controllers/Chat/MUCController.h
index bf46a08..f409309 100644
--- a/Swift/Controllers/Chat/MUCController.h
+++ b/Swift/Controllers/Chat/MUCController.h
@@ -46,7 +46,7 @@ namespace Swift {
 			void handleOccupantJoined(const MUCOccupant& occupant);
 			void handleOccupantLeft(const MUCOccupant& occupant, MUC::LeavingType type, const String& reason);
 			void handleOccupantPresenceChange(boost::shared_ptr<Presence> presence);
-			void handleOccupantRoleChanged(const String& nick, const MUCOccupant::Role& newRole, const MUCOccupant::Role& oldRole);
+			void handleOccupantRoleChanged(const String& nick, const MUCOccupant& occupant,const MUCOccupant::Role& oldRole);
 			void handleJoinComplete(const String& nick);
 			void handleJoinFailed(boost::shared_ptr<ErrorPayload> error);
 			void handleJoinTimeoutTick();
diff --git a/Swift/Controllers/RosterController.cpp b/Swift/Controllers/RosterController.cpp
index 191d5fb..46248a1 100644
--- a/Swift/Controllers/RosterController.cpp
+++ b/Swift/Controllers/RosterController.cpp
@@ -104,10 +104,10 @@ void RosterController::handleOnJIDAdded(const JID& jid) {
 	String name = nickResolver_->jidToNick(jid);
 	if (!groups.empty()) {
 		foreach(const String& group, groups) {
-			roster_->addContact(jid, name, group);
+			roster_->addContact(jid, jid, name, group);
 		}
 	} else {
-		roster_->addContact(jid, name, "Contacts");
+		roster_->addContact(jid, jid, name, "Contacts");
 	}
 }
 
@@ -132,7 +132,7 @@ void RosterController::handleOnJIDUpdated(const JID& jid, const String& oldName,
 	}
 	foreach(const String& group, groups) {
 		if (std::find(oldGroups.begin(), oldGroups.end(), group) == oldGroups.end()) {
-			roster_->addContact(jid, xmppRoster_->getNameForJID(jid), group);
+			roster_->addContact(jid, jid, xmppRoster_->getNameForJID(jid), group);
 		}
 	} 
 	foreach(const String& group, oldGroups) {
diff --git a/Swift/QtUI/QtStatusWidget.cpp b/Swift/QtUI/QtStatusWidget.cpp
index 7d39531..d7c0e63 100644
--- a/Swift/QtUI/QtStatusWidget.cpp
+++ b/Swift/QtUI/QtStatusWidget.cpp
@@ -124,11 +124,15 @@ void QtStatusWidget::generateList() {
 	foreach (StatusShow::Type type, icons_.keys()) {
 		QListWidgetItem* item = new QListWidgetItem(text, menu_);
 		item->setIcon(icons_[type]);
+		item->setToolTip(P2QSTRING(StatusShow::typeToFriendlyName(type)) + ": " + item->text());
+		item->setStatusTip(item->toolTip());
 		item->setData(Qt::UserRole, QVariant(type));
 	}
 	foreach (StatusShow::Type type, icons_.keys()) {
 		QListWidgetItem* item = new QListWidgetItem(P2QSTRING(StatusShow::typeToFriendlyName(type)), menu_);
 		item->setIcon(icons_[type]);
+		item->setToolTip(item->text());
+		item->setStatusTip(item->toolTip());
 		item->setData(Qt::UserRole, QVariant(type));
 	}
 }
@@ -207,6 +211,9 @@ void QtStatusWidget::handleItemClicked(QListWidgetItem* item) {
 	handleEditComplete();
 }
 
+void QtStatusWidget::setNewToolTip() {
+	statusTextLabel_->setToolTip(P2QSTRING(StatusShow::typeToFriendlyName(selectedStatusType_)) + ": " + statusTextLabel_->text());
+}
 
 void QtStatusWidget::setStatusText(const QString& text) {
 	statusText_ = text;
@@ -215,11 +222,13 @@ void QtStatusWidget::setStatusText(const QString& text) {
 	escapedText.replace("<","&lt;");
 //	statusTextLabel_->setText("<i>" + escapedText + "</i>");
 	statusTextLabel_->setText(escapedText);
+	setNewToolTip();
 }
 
 void QtStatusWidget::setStatusType(StatusShow::Type type) {
 	selectedStatusType_ = icons_.contains(type) ? type : StatusShow::Online;
 	statusIcon_->setPixmap(icons_[selectedStatusType_].pixmap(16, 16));
+	setNewToolTip();
 }
 
 }
diff --git a/Swift/QtUI/QtStatusWidget.h b/Swift/QtUI/QtStatusWidget.h
index 4425b1d..2163d5a 100644
--- a/Swift/QtUI/QtStatusWidget.h
+++ b/Swift/QtUI/QtStatusWidget.h
@@ -43,6 +43,7 @@ namespace Swift {
 			void handleItemClicked(QListWidgetItem* item);
 		private:
 			void viewMode();
+			void setNewToolTip();
 			//QComboBox *types_;
 			QStackedWidget* stack_;
 			QLabel* statusIcon_;
diff --git a/Swift/QtUI/Roster/RosterModel.cpp b/Swift/QtUI/Roster/RosterModel.cpp
index e5a938e..a801d3f 100644
--- a/Swift/QtUI/Roster/RosterModel.cpp
+++ b/Swift/QtUI/Roster/RosterModel.cpp
@@ -115,7 +115,18 @@ QColor RosterModel::getBackgroundColor(RosterItem* item) const {
 }
 
 QString RosterModel::getToolTip(RosterItem* item) const {
-	return dynamic_cast<ContactRosterItem*>(item) && !getStatusText(item).isEmpty() ? P2QSTRING(item->getDisplayName()) + "\n" + getStatusText(item) : P2QSTRING(item->getDisplayName());
+	QString tip(P2QSTRING(item->getDisplayName()));
+	ContactRosterItem* contact = dynamic_cast<ContactRosterItem*>(item);
+	if (contact) {
+		if (contact->getDisplayJID().isValid()) {
+			tip += "\n" + P2QSTRING(contact->getDisplayJID().toBare().toString());
+		}
+		tip += "\n " + P2QSTRING(StatusShow::typeToFriendlyName(contact->getStatusShow()));
+		if (!getStatusText(item).isEmpty()) {
+			tip += ": " + getStatusText(item);
+		}
+	}
+	return tip;
 }
 
 QIcon RosterModel::getAvatar(RosterItem* item) const {
diff --git a/Swiften/MUC/MUC.cpp b/Swiften/MUC/MUC.cpp
index 60b81a0..b4265b5 100644
--- a/Swiften/MUC/MUC.cpp
+++ b/Swiften/MUC/MUC.cpp
@@ -88,16 +88,17 @@ void MUC::handleIncomingPresence(boost::shared_ptr<Presence> presence) {
 	}
 	else if (presence->getType() == Presence::Available) {
 		std::map<String, MUCOccupant>::iterator it = occupants.find(nick);
+		MUCOccupant occupant(nick, role, affiliation);
 		if (it != occupants.end()) {
 			MUCOccupant oldOccupant = it->second;
 			if (oldOccupant.getRole() != role) {
-				onOccupantRoleChanged(nick, role, oldOccupant.getRole());
+				onOccupantRoleChanged(nick, occupant, oldOccupant.getRole());
 			}
 			if (oldOccupant.getAffiliation() != affiliation) {
 				onOccupantAffiliationChanged(nick, affiliation, oldOccupant.getAffiliation());
 			}
 		}
-		std::pair<std::map<String, MUCOccupant>::iterator, bool> result = occupants.insert(std::make_pair(nick, MUCOccupant(nick, role, affiliation)));
+		std::pair<std::map<String, MUCOccupant>::iterator, bool> result = occupants.insert(std::make_pair(nick, occupant));
 		if (result.second) {
 			onOccupantJoined(result.first->second);
 		}
diff --git a/Swiften/MUC/MUC.h b/Swiften/MUC/MUC.h
index 4bf56c9..40fc2f6 100644
--- a/Swiften/MUC/MUC.h
+++ b/Swiften/MUC/MUC.h
@@ -41,7 +41,7 @@ namespace Swift {
 			boost::signal<void (const String& /*nick*/)> onJoinComplete;
 			boost::signal<void (boost::shared_ptr<ErrorPayload>)> onJoinFailed;
 			boost::signal<void (boost::shared_ptr<Presence>)> onOccupantPresenceChange;
-			boost::signal<void (const String&, const MUCOccupant::Role& /*new*/, const MUCOccupant::Role& /*old*/)> onOccupantRoleChanged;
+			boost::signal<void (const String&, const MUCOccupant& /*now*/, const MUCOccupant::Role& /*old*/)> onOccupantRoleChanged;
 			boost::signal<void (const String&, const MUCOccupant::Affiliation& /*new*/, const MUCOccupant::Affiliation& /*old*/)> onOccupantAffiliationChanged;
 			boost::signal<void (const MUCOccupant&)> onOccupantJoined;
 			boost::signal<void (const MUCOccupant&, LeavingType, const String& /*reason*/)> onOccupantLeft;
diff --git a/Swiften/Roster/ContactRosterItem.cpp b/Swiften/Roster/ContactRosterItem.cpp
index 2d5082c..a9591a5 100644
--- a/Swiften/Roster/ContactRosterItem.cpp
+++ b/Swiften/Roster/ContactRosterItem.cpp
@@ -10,7 +10,7 @@
 namespace Swift {
 
 
-ContactRosterItem::ContactRosterItem(const JID& jid, const String& name, GroupRosterItem* parent) : RosterItem(name, parent), jid_(jid) {
+ContactRosterItem::ContactRosterItem(const JID& jid, const JID& displayJID, const String& name, GroupRosterItem* parent) : RosterItem(name, parent), jid_(jid), displayJID_(displayJID) {
 }
 
 ContactRosterItem::~ContactRosterItem() {
@@ -48,6 +48,15 @@ const JID& ContactRosterItem::getJID() const {
 	return jid_;
 }
 
+void ContactRosterItem::setDisplayJID(const JID& jid) {
+	displayJID_ = jid;
+}
+
+const JID& ContactRosterItem::getDisplayJID() const {
+	return displayJID_;
+}
+
+
 typedef std::pair<String, boost::shared_ptr<Presence> > StringPresencePair;
 
 void ContactRosterItem::calculateShownPresence() {
diff --git a/Swiften/Roster/ContactRosterItem.h b/Swiften/Roster/ContactRosterItem.h
index d4c92aa..21f6024 100644
--- a/Swiften/Roster/ContactRosterItem.h
+++ b/Swiften/Roster/ContactRosterItem.h
@@ -22,7 +22,7 @@ namespace Swift {
 class GroupRosterItem;
 class ContactRosterItem : public RosterItem {
 	public:
-		ContactRosterItem(const JID& jid, const String& name, GroupRosterItem* parent);
+		ContactRosterItem(const JID& jid, const JID& displayJID, const String& name, GroupRosterItem* parent);
 		virtual ~ContactRosterItem();
 
 		StatusShow::Type getStatusShow() const;
@@ -31,11 +31,14 @@ class ContactRosterItem : public RosterItem {
 		void setAvatarPath(const String& path);
 		const String& getAvatarPath() const;
 		const JID& getJID() const;
+		void setDisplayJID(const JID& jid);
+		const JID& getDisplayJID() const;
 		void applyPresence(const String& resource, boost::shared_ptr<Presence> presence);
 		void clearPresence();
 		void calculateShownPresence();
 	private:
 		JID jid_;
+		JID displayJID_;
 		String avatarPath_;
 		bool hidden_;
 		std::map<String, boost::shared_ptr<Presence> > presences_;
diff --git a/Swiften/Roster/Roster.cpp b/Swiften/Roster/Roster.cpp
index 9291421..b7ed6c4 100644
--- a/Swiften/Roster/Roster.cpp
+++ b/Swiften/Roster/Roster.cpp
@@ -67,9 +67,9 @@ void Roster::handleChildrenChanged(GroupRosterItem* item) {
 	onChildrenChanged(item);
 }
 
-void Roster::addContact(const JID& jid, const String& name, const String& groupName) {
+void Roster::addContact(const JID& jid, const JID& displayJID, const String& name, const String& groupName) {
 	GroupRosterItem* group(getGroup(groupName));
-	ContactRosterItem *item = new ContactRosterItem(jid, name, group);
+	ContactRosterItem *item = new ContactRosterItem(jid, displayJID, name, group);
 	group->addChild(item);
 	itemMap_[fullJIDMapping_ ? jid : jid.toBare()].push_back(item);
 	item->onDataChanged.connect(boost::bind(&Roster::handleDataChanged, this, item));
diff --git a/Swiften/Roster/Roster.h b/Swiften/Roster/Roster.h
index 78606e8..346157e 100644
--- a/Swiften/Roster/Roster.h
+++ b/Swiften/Roster/Roster.h
@@ -28,7 +28,7 @@ class Roster {
 		Roster(bool fullJIDMapping = false);
 		~Roster();
 
-		void addContact(const JID& jid, const String& name, const String& group);
+		void addContact(const JID& jid, const JID& displayJID, const String& name, const String& group);
 		void removeContact(const JID& jid);
 		void removeContactFromGroup(const JID& jid, const String& group);
 		void applyOnItems(const RosterItemOperation& operation);
diff --git a/Swiften/Roster/UnitTest/RosterTest.cpp b/Swiften/Roster/UnitTest/RosterTest.cpp
index d170396..13a4ab0 100644
--- a/Swiften/Roster/UnitTest/RosterTest.cpp
+++ b/Swiften/Roster/UnitTest/RosterTest.cpp
@@ -43,9 +43,9 @@ class RosterTest : public CppUnit::TestFixture
 		}
 
 		void testGetGroup() {
-			roster_->addContact(jid1_, "Bert", "group1");
-			roster_->addContact(jid2_, "Ernie", "group2");
-			roster_->addContact(jid3_, "Cookie", "group1");
+			roster_->addContact(jid1_, JID(), "Bert", "group1");
+			roster_->addContact(jid2_, JID(), "Ernie", "group2");
+			roster_->addContact(jid3_, JID(), "Cookie", "group1");
 
 			CPPUNIT_ASSERT_EQUAL(2, (int)roster_->getRoot()->getChildren().size());
 			CPPUNIT_ASSERT_EQUAL(String("group1"), roster_->getRoot()->getChildren()[0]->getDisplayName());
@@ -57,7 +57,7 @@ class RosterTest : public CppUnit::TestFixture
 		}
 
 		void testRemoveContact() {
-			roster_->addContact(jid1_, "Bert", "group1");
+			roster_->addContact(jid1_, jid1_, "Bert", "group1");
 			CPPUNIT_ASSERT_EQUAL(String("Bert"), ((GroupRosterItem*)roster_->getRoot()->getChildren()[0])->getChildren()[0]->getDisplayName());
 
 			roster_->removeContact(jid1_);
@@ -65,8 +65,8 @@ class RosterTest : public CppUnit::TestFixture
 		}
 
 		void testRemoveSecondContact() {
-			roster_->addContact(jid1_, "Bert", "group1");
-			roster_->addContact(jid2_, "Cookie", "group1");
+			roster_->addContact(jid1_, jid1_, "Bert", "group1");
+			roster_->addContact(jid2_, jid2_, "Cookie", "group1");
 			CPPUNIT_ASSERT_EQUAL(String("Cookie"), ((GroupRosterItem*)roster_->getRoot()->getChildren()[0])->getChildren()[1]->getDisplayName());
 
 			roster_->removeContact(jid2_);
@@ -77,8 +77,8 @@ class RosterTest : public CppUnit::TestFixture
 		void testRemoveSecondContactSameBare() {
 			JID jid4a("a@b/c");
 			JID jid4b("a@b/d");
-			roster_->addContact(jid4a, "Bert", "group1");
-			roster_->addContact(jid4b, "Cookie", "group1");
+			roster_->addContact(jid4a, JID(), "Bert", "group1");
+			roster_->addContact(jid4b, JID(), "Cookie", "group1");
 			CPPUNIT_ASSERT_EQUAL(String("Cookie"), ((GroupRosterItem*)roster_->getRoot()->getChildren()[0])->getChildren()[1]->getDisplayName());
 
 			roster_->removeContact(jid4b);
@@ -90,11 +90,11 @@ class RosterTest : public CppUnit::TestFixture
 			JID jid4a("a@b/c");
 			JID jid4b("a@b/d");
 			JID jid4c("a@b/e");
-			roster_->addContact(jid4a, "Bird", "group1");
-			roster_->addContact(jid4b, "Cookie", "group1");
+			roster_->addContact(jid4a, JID(), "Bird", "group1");
+			roster_->addContact(jid4b, JID(), "Cookie", "group1");
 			roster_->removeContact(jid4b);
-			roster_->addContact(jid4c, "Bert", "group1");
-			roster_->addContact(jid4b, "Ernie", "group1");
+			roster_->addContact(jid4c, JID(), "Bert", "group1");
+			roster_->addContact(jid4b, JID(), "Ernie", "group1");
 			boost::shared_ptr<Presence> presence(new Presence());
 			presence->setShow(StatusShow::DND);
 			presence->setFrom(jid4a);
-- 
cgit v0.10.2-6-g49f6