← Back to team overview

linuxdcpp-team team mailing list archive

[Branch ~dcplusplus-team/dcplusplus/trunk] Rev 2677: smarter sfinae in TypedTable to make text, image, sorting, custom draw optional

 

------------------------------------------------------------
revno: 2677
committer: poy <poy@xxxxxxxxxx>
branch nick: trunk
timestamp: Mon 2011-11-14 20:24:14 +0100
message:
  smarter sfinae in TypedTable to make text, image, sorting, custom draw optional
modified:
  dcpp/Util.h
  dwt/include/dwt/widgets/Table.h
  win32/FavHubGroupsDlg.cpp
  win32/FavHubGroupsDlg.h
  win32/HubFrame.h
  win32/PublicHubsFrame.h
  win32/TypedTable.h
  win32/forward.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 'dcpp/Util.h'
--- dcpp/Util.h	2011-10-08 15:21:54 +0000
+++ dcpp/Util.h	2011-11-14 19:24:14 +0000
@@ -110,6 +110,19 @@
 
 template<typename T1> inline double fraction(T1 a, T1 b) { return static_cast<double>(a) / b; }
 
+/** Uses SFINAE to determine whether a type provides a function; stores the result in "value".
+Inspired by <http://stackoverflow.com/questions/257288#264088>. */
+/// @todo simplify when MSVC supports default template arguments on functions...
+#define HAS_FUNC(name, func, signature) \
+	template<typename T> struct name { \
+		typedef char yes[1]; \
+		typedef char no[2]; \
+		template<typename T, T> struct type_check; \
+		template<typename T> static yes& check(type_check<signature, &T::func>*); \
+		template<typename> static no& check(...); \
+		enum { value = sizeof(check<T>(0)) == sizeof(yes) }; \
+	}
+
 class Util
 {
 public:

=== modified file 'dwt/include/dwt/widgets/Table.h'
--- dwt/include/dwt/widgets/Table.h	2011-11-07 22:11:39 +0000
+++ dwt/include/dwt/widgets/Table.h	2011-11-14 19:24:14 +0000
@@ -173,11 +173,9 @@
 
 	void setSort(int aColumn, SortType aType, bool aAscending = true);
 
-	bool isAscending();
-
-	int getSortColumn();
-
-	SortType getSortType();
+	bool isAscending() const;
+	int getSortColumn() const;
+	SortType getSortType() const;
 
 	/// Returns the text of the given cell
 	/** The column is which column you wish to retrieve the text for. <br>
@@ -724,15 +722,15 @@
 	return Rectangle(r);
 }
 
-inline bool Table::isAscending() {
+inline bool Table::isAscending() const {
 	return ascending;
 }
 
-inline int Table::getSortColumn() {
+inline int Table::getSortColumn() const {
 	return sortColumn;
 }
 
-inline Table::SortType Table::getSortType() {
+inline Table::SortType Table::getSortType() const {
 	return sortType;
 }
 

=== modified file 'win32/FavHubGroupsDlg.cpp'
--- win32/FavHubGroupsDlg.cpp	2011-11-12 19:36:12 +0000
+++ win32/FavHubGroupsDlg.cpp	2011-11-14 19:24:14 +0000
@@ -74,10 +74,6 @@
 	return columns[col];
 }
 
-int FavHubGroupsDlg::GroupInfo::getImage(int) const {
-	return -1;
-}
-
 int FavHubGroupsDlg::GroupInfo::compareItems(const GroupInfo* a, const GroupInfo* b, int col) {
 	return lstrcmpi(a->columns[col].c_str(), b->columns[col].c_str());
 }
@@ -163,11 +159,11 @@
 		groups->setSort(COLUMN_NAME);
 	}
 
+	handleSelectionChanged();
+
 	groups->onKeyDown([this](int c) { return handleKeyDown(c); });
 	groups->onSelectionChanged([this] { handleSelectionChanged(); });
 
-	handleSelectionChanged();
-
 	setText(T_("Favorite hub groups"));
 
 	layout();

=== modified file 'win32/FavHubGroupsDlg.h'
--- win32/FavHubGroupsDlg.h	2011-05-04 19:32:00 +0000
+++ win32/FavHubGroupsDlg.h	2011-11-14 19:24:14 +0000
@@ -45,12 +45,11 @@
 		COLUMN_LAST
 	};
 
-	class GroupInfo : public FastAlloc<GroupInfo> {
+	class GroupInfo {
 	public:
 		GroupInfo(const FavHubGroup& group_);
 
 		const tstring& getText(int col) const;
-		int getImage(int) const;
 
 		static int compareItems(const GroupInfo* a, const GroupInfo* b, int col);
 

=== modified file 'win32/HubFrame.h'
--- win32/HubFrame.h	2011-11-13 16:46:43 +0000
+++ win32/HubFrame.h	2011-11-14 19:24:14 +0000
@@ -161,7 +161,7 @@
 
 	GridPtr userGrid;
 
-	typedef TypedTable<UserInfo, false, true> WidgetUsers;
+	typedef TypedTable<UserInfo, false> WidgetUsers;
 	typedef WidgetUsers* WidgetUsersPtr;
 	WidgetUsersPtr users;
 

=== modified file 'win32/PublicHubsFrame.h'
--- win32/PublicHubsFrame.h	2011-05-04 19:32:00 +0000
+++ win32/PublicHubsFrame.h	2011-11-14 19:24:14 +0000
@@ -80,7 +80,6 @@
 
 		static int compareItems(const HubInfo* a, const HubInfo* b, int col);
 		const tstring& getText(int column) const { return columns[column]; }
-		int getImage(int) const { return 0; }
 
 		const HubEntry* entry;
 

=== modified file 'win32/TypedTable.h'
--- win32/TypedTable.h	2011-11-13 16:46:43 +0000
+++ win32/TypedTable.h	2011-11-14 19:24:14 +0000
@@ -29,18 +29,28 @@
 
 @tparam managed Whether this class should handle deleting associated objects.
 
-@tparam customColors Custom colors per item (whole row) or per sub-item (each cell).
-The ContentType class must provide a int getColor(COLORREF& text, COLORREF& bg, int col) function.
-It is called a first time with col=-1 to set colors for the whole item. It can return:
+@note Support for texts:
+The ContentType class must provide a const tstring& getText(int col) const function.
+
+@note Support for images:
+The ContentType class must provide a int getImage(int col) const function.
+
+@note Support for item sorting:
+The ContentType class must provide a
+static int compareItems(ContentType* a, ContentType* b, int col) function.
+
+@note Support for custom colors per item (whole row) or per sub-item (each cell):
+The ContentType class must provide a int getColor(COLORREF& text, COLORREF& bg, int col) const
+function. It is called a first time with col=-1 to set colors for the whole item. It can return:
 - CDRF_DODEFAULT to keep default colors for the item.
 - CDRF_NEWFONT to change colors for the item.
 - CDRF_NOTIFYSUBITEMDRAW to request custom colors for each sub-item (get Color will then be called
 for each sub-item). */
-template<typename ContentType, bool managed, bool customColors>
+template<typename ContentType, bool managed>
 class TypedTable : public Table
 {
 	typedef Table BaseType;
-	typedef TypedTable<ContentType, managed, customColors> ThisType;
+	typedef TypedTable<ContentType, managed> ThisType;
 
 public:
 	typedef ThisType* ObjectType;
@@ -64,18 +74,14 @@
 	void create(const Seed& seed) {
 		BaseType::create(seed);
 
-		this->onRaw([this](WPARAM, LPARAM lParam) -> LRESULT {
-			auto& data = *reinterpret_cast<NMLVDISPINFO*>(lParam);
-			this->handleDisplay(data);
-			return 0;
-		}, dwt::Message(WM_NOTIFY, LVN_GETDISPINFO));
-		this->onColumnClick([this](int column) { this->handleColumnClick(column); });
-		this->onSortItems([this](LPARAM lhs, LPARAM rhs) { return this->handleSort(lhs, rhs); });
-		addColorEvent<void>();
+		addTextEvent<ContentType>();
+		addImageEvent<ContentType>();
+		addSortEvent<ContentType>();
+		addColorEvent<ContentType>();
 	}
 
 	int insert(ContentType* item) {
-		return insert(getSortPos(item), item);
+		return insert(getSortPos<ContentType>(item), item);
 	}
 
 	int insert(int i, ContentType* item) {
@@ -147,7 +153,57 @@
 
 	void erase(ContentType* item) { int i = find(item); if(i != -1) this->erase(i); }
 
-	int getSortPos(ContentType* a) {
+	void setSort(int col = -1, bool ascending = true) {
+		BaseType::setSort(col, BaseType::SORT_CALLBACK, ascending);
+	}
+
+private:
+	HAS_FUNC(HasText_, getText, const tstring& (ContentType::*)(int) const);
+#define HasText HasText_<ContentType>::value
+
+	HAS_FUNC(HasImage_, getImage, int (ContentType::*)(int) const);
+#define HasImage HasImage_<ContentType>::value
+
+	HAS_FUNC(HasSort_, compareItems, int (*)(const ContentType*, const ContentType*, int));
+#define HasSort HasSort_<ContentType>::value
+
+	HAS_FUNC(HasColor_, getColor, int (ContentType::*)(COLORREF&, COLORREF&, int) const);
+#define HasColor HasColor_<ContentType>::value
+
+	template<typename ContentType> typename std::enable_if<HasText, void>::type addTextEvent() {
+		this->onRaw([this](WPARAM, LPARAM lParam) -> LRESULT {
+			auto& data = *reinterpret_cast<NMLVDISPINFO*>(lParam);
+			if(data.item.mask & LVIF_TEXT) {
+				this->handleText<ContentType>(data);
+			}
+			return 0;
+		}, dwt::Message(WM_NOTIFY, LVN_GETDISPINFO));
+	}
+	template<typename ContentType> typename std::enable_if<!HasText, void>::type addTextEvent() { }
+
+	template<typename ContentType> typename std::enable_if<HasImage, void>::type addImageEvent() {
+		this->onRaw([this](WPARAM, LPARAM lParam) -> LRESULT {
+			auto& data = *reinterpret_cast<NMLVDISPINFO*>(lParam);
+			if(data.item.mask & LVIF_IMAGE) {
+				this->handleImage<ContentType>(data);
+			}
+			return 0;
+		}, dwt::Message(WM_NOTIFY, LVN_GETDISPINFO));
+	}
+	template<typename ContentType> typename std::enable_if<!HasImage, void>::type addImageEvent() { }
+
+	template<typename ContentType> typename std::enable_if<HasSort, void>::type addSortEvent() {
+		this->onSortItems([this](LPARAM lhs, LPARAM rhs) { return this->handleSort<ContentType>(lhs, rhs); });
+		this->onColumnClick([this](int column) { this->handleColumnClick<ContentType>(column); });
+	}
+	template<typename ContentType> typename std::enable_if<!HasSort, void>::type addSortEvent() { }
+
+	template<typename ContentType> typename std::enable_if<HasColor, void>::type addColorEvent() {
+		this->onCustomDraw([this](NMLVCUSTOMDRAW& data) { return this->handleCustomDraw<ContentType>(data); });
+	}
+	template<typename ContentType> typename std::enable_if<!HasColor, void>::type addColorEvent() { }
+
+	template<typename ContentType> typename std::enable_if<HasSort, int>::type getSortPos(ContentType* a) {
 		int high = this->size();
 		if((this->getSortColumn() == -1) || (high == 0))
 			return high;
@@ -183,33 +239,25 @@
 
 		return mid;
 	}
-
-	void setSort(int col = -1, bool ascending = true) {
-		BaseType::setSort(col, BaseType::SORT_CALLBACK, ascending);
-	}
-
-private:
-	template<typename Ret> typename std::enable_if<customColors, Ret>::type addColorEvent() {
-		this->onCustomDraw([this](NMLVCUSTOMDRAW& data) { return this->handleCustomDraw<LRESULT>(data); });
-	}
-	template<typename Ret> typename std::enable_if<!customColors, Ret>::type addColorEvent() { }
-
-	void handleDisplay(NMLVDISPINFO& data) {
-		if(data.item.mask & LVIF_TEXT) {
-			ContentType* content = reinterpret_cast<ContentType*>(data.item.lParam);
-			const tstring& text = content->getText(data.item.iSubItem);
-			_tcsncpy(data.item.pszText, text.data(), std::min(text.size(), static_cast<size_t>(data.item.cchTextMax)));
-			if(text.size() < static_cast<size_t>(data.item.cchTextMax)) {
-				data.item.pszText[text.size()] = 0;
-			}
-		}
-		if(data.item.mask & LVIF_IMAGE) {
-			ContentType* content = reinterpret_cast<ContentType*>(data.item.lParam);
-			data.item.iImage = content->getImage(data.item.iSubItem);
-		}
-	}
-
-	void handleColumnClick(int column) {
+	template<typename ContentType> typename std::enable_if<!HasSort, int>::type getSortPos(ContentType* a) {
+		return this->size();
+	}
+
+	template<typename ContentType> typename std::enable_if<HasText, void>::type handleText(NMLVDISPINFO& data) {
+		ContentType* content = reinterpret_cast<ContentType*>(data.item.lParam);
+		const tstring& text = content->getText(data.item.iSubItem);
+		_tcsncpy(data.item.pszText, text.data(), std::min(text.size(), static_cast<size_t>(data.item.cchTextMax)));
+		if(text.size() < static_cast<size_t>(data.item.cchTextMax)) {
+			data.item.pszText[text.size()] = 0;
+		}
+	}
+
+	template<typename ContentType> typename std::enable_if<HasImage, void>::type handleImage(NMLVDISPINFO& data) {
+		ContentType* content = reinterpret_cast<ContentType*>(data.item.lParam);
+		data.item.iImage = content->getImage(data.item.iSubItem);
+	}
+
+	template<typename ContentType> typename std::enable_if<HasSort, void>::type handleColumnClick(int column) {
 		if(column != this->getSortColumn()) {
 			this->setSort(column, true);
 		} else if(this->isAscending()) {
@@ -219,11 +267,11 @@
 		}
 	}
 
-	int handleSort(LPARAM lhs, LPARAM rhs) {
+	template<typename ContentType> typename std::enable_if<HasSort, int>::type handleSort(LPARAM lhs, LPARAM rhs) {
 		return ContentType::compareItems(reinterpret_cast<ContentType*>(lhs), reinterpret_cast<ContentType*>(rhs), this->getSortColumn());
 	}
 
-	template<typename Ret> typename std::enable_if<customColors, Ret>::type handleCustomDraw(NMLVCUSTOMDRAW& data) {
+	template<typename ContentType> typename std::enable_if<HasColor, LRESULT>::type handleCustomDraw(NMLVCUSTOMDRAW& data) {
 		switch(data.nmcd.dwDrawStage) {
 		case CDDS_PREPAINT:
 			return CDRF_NOTIFYITEMDRAW;

=== modified file 'win32/forward.h'
--- win32/forward.h	2011-11-13 16:46:43 +0000
+++ win32/forward.h	2011-11-14 19:24:14 +0000
@@ -57,7 +57,7 @@
 
 class TransferView;
 
-template<typename ContentType, bool managed = true, bool customColors = false>
+template<typename ContentType, bool managed = true>
 class TypedTable;
 
 template<typename ContentType>