← Back to team overview

linuxdcpp-team team mailing list archive

[Branch ~dcplusplus-team/dcplusplus/trunk] Rev 2333: Add user information tooltips

 

------------------------------------------------------------
revno: 2333
committer: poy <poy@xxxxxxxxxx>
branch nick: trunk
timestamp: Wed 2010-12-08 17:54:29 +0100
message:
  Add user information tooltips
modified:
  changelog.txt
  dcpp/ClientManager.cpp
  dcpp/ClientManager.h
  dcpp/User.cpp
  dcpp/User.h
  dcpp/Util.cpp
  dcpp/Util.h
  dwt/include/dwt/util/StringUtils.h
  dwt/include/dwt/widgets/Table.h
  dwt/src/util/StringUtils.cpp
  dwt/src/widgets/TabView.cpp
  dwt/src/widgets/Table.cpp
  win32/HubFrame.cpp
  win32/TransferView.cpp
  win32/UserInfoBase.cpp
  win32/UserInfoBase.h
  win32/UsersFrame.cpp
  win32/WinUtil.h


--
lp:dcplusplus
https://code.launchpad.net/~dcplusplus-team/dcplusplus/trunk

Your team Dcplusplus-team is subscribed to branch lp:dcplusplus.
To unsubscribe from this branch go to https://code.launchpad.net/~dcplusplus-team/dcplusplus/trunk/+edit-subscription
=== modified file 'changelog.txt'
--- changelog.txt	2010-12-05 18:59:52 +0000
+++ changelog.txt	2010-12-08 16:54:29 +0000
@@ -51,6 +51,7 @@
 * [L#534242] Better looking settings dialog (fleetcommand, poy)
 * Allow regular expressions in ADL searches (poy)
 * [L#395464] [ADC] Send "000" as the STA success code
+* Add user information tooltips (poy)
 
 -- 0.770 2010-07-05 --
 * [L#550300] Catch more potential file corruptions (thanks bigmuscle)

=== modified file 'dcpp/ClientManager.cpp'
--- dcpp/ClientManager.cpp	2010-08-27 13:47:33 +0000
+++ dcpp/ClientManager.cpp	2010-12-08 16:54:29 +0000
@@ -324,7 +324,7 @@
 	}
 }
 
-OnlineUser* ClientManager::findOnlineUser_hint(const CID& cid, const string& hintUrl, OnlinePair& p) throw() {
+OnlineUser* ClientManager::findOnlineUser_hint(const CID& cid, const string& hintUrl, OnlinePair& p) {
 	p = onlineUsers.equal_range(cid);
 	if(p.first == p.second) // no user found with the given CID.
 		return 0;
@@ -341,7 +341,11 @@
 	return 0;
 }
 
-OnlineUser* ClientManager::findOnlineUser(const CID& cid, const string& hintUrl, bool priv) throw() {
+OnlineUser* ClientManager::findOnlineUser(const HintedUser& user, bool priv) {
+	return findOnlineUser(user.user->getCID(), user.hint, priv);
+}
+
+OnlineUser* ClientManager::findOnlineUser(const CID& cid, const string& hintUrl, bool priv) {
 	OnlinePair p;
 	OnlineUser* u = findOnlineUser_hint(cid, hintUrl, p);
 	if(u) // found an exact match (CID + hint).
@@ -362,7 +366,7 @@
 	bool priv = FavoriteManager::getInstance()->isPrivate(user.hint);
 
 	Lock l(cs);
-	OnlineUser* u = findOnlineUser(user.user->getCID(), user.hint, priv);
+	OnlineUser* u = findOnlineUser(user, priv);
 
 	if(u) {
 		u->getClient().connect(*u, token);
@@ -373,7 +377,7 @@
 	bool priv = FavoriteManager::getInstance()->isPrivate(user.hint);
 
 	Lock l(cs);
-	OnlineUser* u = findOnlineUser(user.user->getCID(), user.hint, priv);
+	OnlineUser* u = findOnlineUser(user, priv);
 
 	if(u) {
 		u->getClient().privateMessage(*u, msg, thirdPerson);

=== modified file 'dcpp/ClientManager.h'
--- dcpp/ClientManager.h	2010-08-27 13:47:33 +0000
+++ dcpp/ClientManager.h	2010-12-08 16:54:29 +0000
@@ -73,7 +73,8 @@
 	* @param priv discard any user that doesn't match the hint.
 	* @return OnlineUser* found by CID and hint; might be only by CID if priv is false.
 	*/
-	OnlineUser* findOnlineUser(const CID& cid, const string& hintUrl, bool priv) throw();
+	OnlineUser* findOnlineUser(const HintedUser& user, bool priv);
+	OnlineUser* findOnlineUser(const CID& cid, const string& hintUrl, bool priv);
 
 	UserPtr findUser(const string& aNick, const string& aHubUrl) const throw() { return findUser(makeCid(aNick, aHubUrl)); }
 	UserPtr findUser(const CID& cid) const throw();
@@ -156,7 +157,7 @@
 	void updateNick(const OnlineUser& user) throw();
 
 	/// @return OnlineUser* found by CID and hint; discard any user that doesn't match the hint.
-	OnlineUser* findOnlineUser_hint(const CID& cid, const string& hintUrl) throw() {
+	OnlineUser* findOnlineUser_hint(const CID& cid, const string& hintUrl) {
 		OnlinePair p;
 		return findOnlineUser_hint(cid, hintUrl, p);
 	}
@@ -164,7 +165,7 @@
 	* @param p OnlinePair of all the users found by CID, even those who don't match the hint.
 	* @return OnlineUser* found by CID and hint; discard any user that doesn't match the hint.
 	*/
-	OnlineUser* findOnlineUser_hint(const CID& cid, const string& hintUrl, OnlinePair& p) throw();
+	OnlineUser* findOnlineUser_hint(const CID& cid, const string& hintUrl, OnlinePair& p);
 
 	string getUsersFile() const { return Util::getPath(Util::PATH_USER_LOCAL) + "Users.xml"; }
 

=== modified file 'dcpp/User.cpp'
--- dcpp/User.cpp	2010-02-11 21:44:13 +0000
+++ dcpp/User.cpp	2010-12-08 16:54:29 +0000
@@ -90,6 +90,10 @@
 		get("HR") + "/" + get("HO") + ",S:" + get("SL") + ">";
 }
 
+string Identity::getCountry() const {
+	return Util::getIpCountry(getIp());
+}
+
 string Identity::get(const char* name) const {
 	FastLock l(cs);
 	InfMap::const_iterator i = info.find(*(short*)name);

=== modified file 'dcpp/User.h'
--- dcpp/User.h	2010-12-03 17:26:12 +0000
+++ dcpp/User.h	2010-12-08 16:54:29 +0000
@@ -139,6 +139,7 @@
 	void setBot(bool bot) { set("BO", bot ? "1" : Util::emptyString); }
 	void setHidden(bool hidden) { set("HI", hidden ? "1" : Util::emptyString); }
 	string getTag() const;
+	string getCountry() const;
 	bool supports(const string& name) const;
 	bool isHub() const { return isClientType(CT_HUB) || isSet("HU"); }
 	bool isOp() const { return isClientType(CT_OP) || isClientType(CT_SU) || isClientType(CT_OWNER) || isSet("OP"); }

=== modified file 'dcpp/Util.cpp'
--- dcpp/Util.cpp	2010-12-01 16:03:18 +0000
+++ dcpp/Util.cpp	2010-12-08 16:54:29 +0000
@@ -899,9 +899,10 @@
 	for exemple: it returns "PT", whitch standards for "Portugal"
 	more info: http://www.maxmind.com/app/csv
 */
-string Util::getIpCountry (string IP) {
-	if (BOOLSETTING(GET_USER_COUNTRY)) {
-		dcassert(count(IP.begin(), IP.end(), '.') == 3);
+string Util::getIpCountry(const string& IP) {
+	if(BOOLSETTING(GET_USER_COUNTRY)) {
+		if(count(IP.begin(), IP.end(), '.') != 3)
+			return Util::emptyString;
 
 		//e.g IP 23.24.25.26 : w=23, x=24, y=25, z=26
 		string::size_type a = IP.find('.');
@@ -920,7 +921,7 @@
 		}
 	}
 
-	return Util::emptyString; //if doesn't returned anything already, something is wrong...
+	return Util::emptyString;
 }
 
 string Util::getTimeString() {

=== modified file 'dcpp/Util.h'
--- dcpp/Util.h	2010-12-01 16:03:18 +0000
+++ dcpp/Util.h	2010-12-08 16:54:29 +0000
@@ -412,7 +412,7 @@
 	static int stricmp(const wstring& a, const wstring& b) { return stricmp(a.c_str(), b.c_str()); }
 	static int strnicmp(const wstring& a, const wstring& b, size_t n) { return strnicmp(a.c_str(), b.c_str(), n); }
 
-	static string getIpCountry (string IP);
+	static string getIpCountry(const string& IP);
 
 	static bool getAway() { return away; }
 	static void setAway(bool aAway) {

=== modified file 'dwt/include/dwt/util/StringUtils.h'
--- dwt/include/dwt/util/StringUtils.h	2010-02-11 21:44:13 +0000
+++ dwt/include/dwt/util/StringUtils.h	2010-12-08 16:54:29 +0000
@@ -38,6 +38,8 @@
 
 tstring escapeMenu(tstring str);
 
+void cutStr(tstring& str, size_t n);
+
 } }
 
 #endif /*STRINGUTILS_H_*/

=== modified file 'dwt/include/dwt/widgets/Table.h'
--- dwt/include/dwt/widgets/Table.h	2010-07-10 14:36:48 +0000
+++ dwt/include/dwt/widgets/Table.h	2010-12-08 16:54:29 +0000
@@ -79,18 +79,26 @@
 {
 	typedef CommonControl BaseType;
 
-	struct HeaderDispatcher {
-		typedef std::function<void (int)> F;
-
-		HeaderDispatcher(const F& f_) : f(f_) { }
-
-		bool operator()(const MSG& msg, LRESULT& ret) const {
-			LPNMLISTVIEW p = (LPNMLISTVIEW) msg.lParam;
-			f(p->iSubItem);
-			return true;
-		}
-
-		F f;
+	struct HeaderDispatcher : Dispatchers::Base<void (int)> {
+		typedef Dispatchers::Base<void (int)> BaseType;
+		HeaderDispatcher(const F& f_) : BaseType(f_) { }
+
+		bool operator()(const MSG& msg, LRESULT& ret) const {
+			f(reinterpret_cast<LPNMLISTVIEW>(msg.lParam)->iSubItem);
+			return true;
+		}
+	};
+
+	struct TooltipDispatcher : Dispatchers::Base<tstring (int)> {
+		typedef Dispatchers::Base<tstring (int)> BaseType;
+		TooltipDispatcher(const F& f_) : BaseType(f_) { }
+
+		bool operator()(const MSG& msg, LRESULT& ret) const {
+			NMLVGETINFOTIP& tip = *reinterpret_cast<LPNMLVGETINFOTIP>(msg.lParam);
+			tstring text(f(tip.iItem));
+			_tcscpy_s(tip.pszText, tip.cchTextMax, text.c_str());
+			return true;
+		}
 	};
 
 	// Need to be friend to access private data...
@@ -353,6 +361,8 @@
 	  */
 	void setSingleRowSelection( bool value = true );
 
+	void setTooltips(const TooltipDispatcher::F& f);
+
 	/// Adds (or removes) grid lines.
 	/** A grid with grid lines will have lines surrounding every cell in it. <br>
 	  * value defines if we're supposed to add grid lines or remove them. <br>

=== modified file 'dwt/src/util/StringUtils.cpp'
--- dwt/src/util/StringUtils.cpp	2010-02-11 21:44:13 +0000
+++ dwt/src/util/StringUtils.cpp	2010-12-08 16:54:29 +0000
@@ -43,4 +43,9 @@
 	return str;
 }
 
+void cutStr(tstring& str, size_t n) {
+	if(str.size() > n)
+		str = str.substr(0, n - 3) + _T("...");
+}
+
 } }

=== modified file 'dwt/src/widgets/TabView.cpp'
--- dwt/src/widgets/TabView.cpp	2010-10-28 22:43:23 +0000
+++ dwt/src/widgets/TabView.cpp	2010-12-08 16:54:29 +0000
@@ -387,8 +387,8 @@
 }
 
 tstring TabView::formatTitle(tstring title) {
-	if(widthConfig && title.length() > widthConfig)
-		title = title.substr(0, widthConfig - 3) + _T("...");
+	if(widthConfig)
+		util::cutStr(title, widthConfig);
 	return util::escapeMenu(title);
 }
 

=== modified file 'dwt/src/widgets/Table.cpp'
--- dwt/src/widgets/Table.cpp	2010-07-10 14:36:48 +0000
+++ dwt/src/widgets/Table.cpp	2010-12-08 16:54:29 +0000
@@ -149,8 +149,8 @@
 	ListView_SetItemState(handle(), item, LVIS_SELECTED | LVIS_FOCUSED, LVIS_SELECTED | LVIS_FOCUSED);
 }
 
-void Table::selectAll() {
-	for(size_t i = 0, n = size(); i < n; ++i)
+void Table::selectAll() {
+	for(size_t i = 0, n = size(); i < n; ++i)
 		setSelected(i);
 }
 
@@ -554,4 +554,9 @@
 	return ListView_HitTest(handle(), &lvi);
 }
 
+void Table::setTooltips(const TooltipDispatcher::F& f) {
+	addRemoveTableExtendedStyle(LVS_EX_INFOTIP, true);
+	addCallback(Message(WM_NOTIFY, LVN_GETINFOTIP), TooltipDispatcher(f));
+}
+
 }

=== modified file 'win32/HubFrame.cpp'
--- win32/HubFrame.cpp	2010-12-03 18:27:30 +0000
+++ win32/HubFrame.cpp	2010-12-08 16:54:29 +0000
@@ -162,6 +162,8 @@
 		users->onKeyDown(std::bind(&HubFrame::handleUsersKeyDown, this, _1));
 		users->onContextMenu(std::bind(&HubFrame::handleUsersContextMenu, this, _1));
 
+		prepareUserList(users, true);
+
 		TextBox::Seed cs = WinUtil::Seeds::textBox;
 		cs.style |= ES_AUTOHSCROLL;
 		filter = userGrid->addChild(cs);
@@ -639,10 +641,8 @@
 	columns[COLUMN_DESCRIPTION] = Text::toT(identity.getDescription());
 	columns[COLUMN_TAG] = Text::toT(identity.getTag());
 	columns[COLUMN_CONNECTION] = Text::toT(identity.getConnection());
-	string ip = identity.getIp();
-	string country = ip.empty()?Util::emptyString:Util::getIpCountry(ip);
-	columns[COLUMN_IP] = Text::toT(ip);
-	columns[COLUMN_COUNTRY] = Text::toT(country);
+	columns[COLUMN_IP] = Text::toT(identity.getIp());
+	columns[COLUMN_COUNTRY] = Text::toT(identity.getCountry());
 	columns[COLUMN_EMAIL] = Text::toT(identity.getEmail());
 	columns[COLUMN_CID] = Text::toT(identity.getUser()->getCID().toBase32());
 

=== modified file 'win32/TransferView.cpp'
--- win32/TransferView.cpp	2010-12-03 13:59:16 +0000
+++ win32/TransferView.cpp	2010-12-08 16:54:29 +0000
@@ -125,6 +125,8 @@
 		connections->onKeyDown(std::bind(&TransferView::handleKeyDown, this, _1));
 		connections->onDblClicked(std::bind(&TransferView::handleDblClicked, this));
 		connections->onRaw(std::bind(&TransferView::handleCustomDraw, this, _1, _2), dwt::Message(WM_NOTIFY, NM_CUSTOMDRAW));
+
+		prepareUserList(connections);
 	}
 
 	{

=== modified file 'win32/UserInfoBase.cpp'
--- win32/UserInfoBase.cpp	2010-02-11 21:44:13 +0000
+++ win32/UserInfoBase.cpp	2010-12-08 16:54:29 +0000
@@ -20,12 +20,15 @@
 
 #include "UserInfoBase.h"
 
+#include <dcpp/ClientManager.h>
+#include <dcpp/FavoriteManager.h>
+#include <dcpp/LogManager.h>
 #include <dcpp/QueueManager.h>
-#include <dcpp/LogManager.h>
-#include <dcpp/FavoriteManager.h>
 #include <dcpp/UploadManager.h>
 #include <dcpp/User.h>
 
+#include <dwt/util/StringUtils.h>
+
 #include "PrivateFrame.h"
 #include "HubFrame.h"
 
@@ -78,6 +81,57 @@
 	}
 }
 
+const size_t maxChars = 100; // max chars per tooltip line
+
+tstring UserInfoBase::getTooltip(bool priv) const {
+	bool hubSet = priv;
+	if(!priv)
+		priv = FavoriteManager::getInstance()->isPrivate(user.hint);
+
+	tstring ret(WinUtil::getNicks(user, priv));
+	dwt::util::cutStr(ret, maxChars);
+
+	auto addLine = [&ret](tstring line) {
+		dwt::util::cutStr(line, maxChars);
+		ret += _T("\r\n") + line;
+	};
+
+	if(!hubSet)
+		addLine(str(TF_("Hubs: %1%") % WinUtil::getHubNames(user, priv).first));
+
+	OnlineUser* ou = ClientManager::getInstance()->findOnlineUser(user, priv);
+	if(!ou)
+		return ret;
+	const Identity& id = ou->getIdentity();
+
+	auto getField = [&id](const char* code) -> tstring {
+		string field = id.get(code);
+		return field.empty() ? _T("?") : Text::toT(field);
+	};
+
+	if(id.isHidden())
+		addLine(T_("Hidden user"));
+	if(id.isBot())
+		addLine(T_("Bot"));
+	if(id.isOp())
+		addLine(T_("Hub operator"));
+	if(id.isAway())
+		addLine(T_("In away mode"));
+
+	addLine(str(TF_("Shared: %1%") % Text::toT(Util::formatBytes(id.getBytesShared()))));
+	addLine(str(TF_("Description: %1%") % Text::toT(id.getDescription())));
+	addLine(str(TF_("Tag: %1%") % Text::toT(id.getTag())));
+	addLine(str(TF_("Connection: %1%") % Text::toT(id.getConnection())));
+	addLine(str(TF_("IP: %1%") % getField("I4")));
+	const string country = id.getCountry();
+	if(!country.empty())
+		addLine(str(TF_("Country: %1%") % Text::toT(country)));
+	addLine(str(TF_("E-mail: %1%") % Text::toT(id.getEmail())));
+	addLine(str(TF_("Slots: %1%/%2%") % getField("FS") % getField("SL")));
+
+	return ret;
+}
+
 void UserInfoBase::UserTraits::parse(UserInfoBase* ui) {
 	if(ui->getUser().user->isSet(User::NMDC))
 		adcOnly = false;

=== modified file 'win32/UserInfoBase.h'
--- win32/UserInfoBase.h	2010-07-10 14:36:48 +0000
+++ win32/UserInfoBase.h	2010-12-08 16:54:29 +0000
@@ -41,6 +41,8 @@
 	void removeFromQueue();
 	void connectFav(dwt::TabViewPtr);
 
+	tstring getTooltip(bool priv) const;
+
 	const HintedUser& getUser() const { return user; }
 
 	struct UserTraits {
@@ -140,6 +142,11 @@
 		menu->appendSeparator();
 		menu->appendItem(T_("Remove user from queue"), std::bind(&ThisType::handleRemoveFromQueue, this));
 	}
+
+	template<typename TableType>
+	void prepareUserList(TableType* table, bool priv = false) {
+		table->setTooltips([table, priv](int i) -> tstring { return table->getData(i)->getTooltip(priv); });
+	}
 };
 
 #endif /*USERINFOBASE_H_*/

=== modified file 'win32/UsersFrame.cpp'
--- win32/UsersFrame.cpp	2010-11-30 18:21:53 +0000
+++ win32/UsersFrame.cpp	2010-12-08 16:54:29 +0000
@@ -55,6 +55,8 @@
 		users->onKeyDown(std::bind(&UsersFrame::handleKeyDown, this, _1));
 		users->onRaw(std::bind(&UsersFrame::handleItemChanged, this, _2), dwt::Message(WM_NOTIFY, LVN_ITEMCHANGED));
 		users->onContextMenu(std::bind(&UsersFrame::handleContextMenu, this, _1));
+
+		prepareUserList(users);
 	}
 
 	{

=== modified file 'win32/WinUtil.h'
--- win32/WinUtil.h	2010-11-24 22:14:02 +0000
+++ win32/WinUtil.h	2010-12-08 16:54:29 +0000
@@ -167,12 +167,14 @@
 	static tstring getNicks(const UserPtr& u, const string& hintUrl);
 	static tstring getNicks(const CID& cid, const string& hintUrl, bool priv);
 	static tstring getNicks(const HintedUser& user) { return getNicks(user.user->getCID(), user.hint); }
+	static tstring getNicks(const HintedUser& user, bool priv) { return getNicks(user.user->getCID(), user.hint, priv); }
 
 	/** @return Pair of hubnames as a string and a bool representing the user's online status */
 	static pair<tstring, bool> getHubNames(const CID& cid, const string& hintUrl);
 	static pair<tstring, bool> getHubNames(const UserPtr& u, const string& hintUrl);
 	static pair<tstring, bool> getHubNames(const CID& cid, const string& hintUrl, bool priv);
 	static pair<tstring, bool> getHubNames(const HintedUser& user) { return getHubNames(user.user->getCID(), user.hint); }
+	static pair<tstring, bool> getHubNames(const HintedUser& user, bool priv) { return getHubNames(user.user->getCID(), user.hint, priv); }
 
 	static void reducePaths(string& message);