← Back to team overview

linuxdcpp-team team mailing list archive

[Branch ~dcplusplus-team/dcplusplus/trunk] Rev 3007: improve the dev plugin

 

------------------------------------------------------------
revno: 3007
committer: poy <poy@xxxxxxxxxx>
branch nick: trunk
timestamp: Fri 2012-07-20 15:04:43 +0200
message:
  improve the dev plugin
modified:
  plugins/Dev/Dialog.cpp
  plugins/Dev/Dialog.h
  plugins/Dev/Plugin.cpp
  plugins/Dev/resource.h
  plugins/Dev/resource.rc


--
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 'plugins/Dev/Dialog.cpp'
--- plugins/Dev/Dialog.cpp	2012-07-19 22:00:20 +0000
+++ plugins/Dev/Dialog.cpp	2012-07-20 13:04:43 +0000
@@ -23,14 +23,11 @@
 
 #include <vector>
 
-#include <boost/algorithm/string.hpp>
-#include <boost/format.hpp>
-#include <boost/lambda/lambda.hpp>
-
 #include <CriticalSection.h>
 
-#include <richedit.h>
+#include <commctrl.h>
 
+using std::move;
 using std::vector;
 
 using dcpp::CriticalSection;
@@ -41,52 +38,171 @@
 namespace {
 
 // store the messages to be displayed here; process them with a timer.
+struct Message { bool sending; string ip; string peer; string message; };
+vector<Message> messages;
+
 CriticalSection mutex;
-vector<string> messages;
 uint16_t counter = 0;
-
-// RTF formatting taken from dwt's RichTextBox
-
-typedef boost::iterator_range<boost::range_const_iterator<string>::type> string_range;
-
-string unicodeEscapeFormatter(const string_range& match) {
-	if(match.empty())
-		return string();
-	return (boost::format("\\ud\\u%dh")%(int(*match.begin()))).str();
-}
-
-string escapeUnicode(const string& str) {
-	string ret;
-	boost::find_format_all_copy(std::back_inserter(ret), str,
-		boost::first_finder(L"\x7f", std::greater<char>()), unicodeEscapeFormatter);
-	return ret;
-}
-
-string rtfEscapeFormatter(const string_range& match) {
-	if(match.empty())
-		return string();
-	string s(1, *match.begin());
-	if (s == "\r") return "";
-	if (s == "\n") return "\\line\n";
-	return "\\" + s;
-}
-
-string rtfEscape(const string& str) {
-	using boost::lambda::_1;
-	string escaped;
-	boost::find_format_all_copy(std::back_inserter(escaped), str,
-		boost::first_finder("\x7f", _1 == '{' || _1 == '}' || _1 == '\\' || _1 == '\n' || _1 == '\r'), rtfEscapeFormatter);
-	return escaped;
-}
-
-string formatText(const string& text) {
-	return "{\\urtf " + escapeUnicode(rtfEscape(Util::toString(++counter) + " " + text)) + "}";
-}
+bool scroll = true;
+
+struct Item {
+	tstring index;
+	tstring dir;
+	tstring ip;
+	tstring peer;
+	tstring message;
+};
 
 BOOL init(HWND hwnd) {
+	auto control = GetDlgItem(hwnd, IDC_MESSAGES);
+
+	ListView_SetExtendedListViewStyle(control, LVS_EX_DOUBLEBUFFER | LVS_EX_HEADERDRAGDROP | LVS_EX_FULLROWSELECT | LVS_EX_LABELTIP);
+
+	RECT rect;
+	GetClientRect(control, &rect);
+
+	LVCOLUMN col = { LVCF_FMT | LVCF_TEXT | LVCF_WIDTH, LVCFMT_LEFT, 50, _T("N�") };
+	ListView_InsertColumn(control, 0, &col);
+
+	col.pszText = _T("Dir");
+	ListView_InsertColumn(control, 1, &col);
+
+	col.cx = 100;
+	col.pszText = _T("IP");
+	ListView_InsertColumn(control, 2, &col);
+
+	col.cx = 200;
+	col.pszText = _T("Peer info");
+	ListView_InsertColumn(control, 3, &col);
+
+	col.cx = rect.right - rect.left - 50 - 50 - 100 - 200 - 30;
+	col.pszText = _T("Message");
+	ListView_InsertColumn(control, 4, &col);
+
+	SendMessage(GetDlgItem(hwnd, IDC_SCROLL), BM_SETCHECK, BST_CHECKED, 0);
+
+	SetTimer(hwnd, 1, 500, 0);
+
 	return TRUE;
 }
 
+void timer(HWND hwnd) {
+	decltype(messages) messages_;
+	{
+		Lock l(mutex);
+		messages_.swap(messages);
+	}
+	if(messages_.empty()) {
+		return;
+	}
+
+	auto control = GetDlgItem(hwnd, IDC_MESSAGES);
+
+	LVITEM lvi = { 0 };
+
+	for(auto& message: messages_) {
+		auto item = new Item;
+		item->index = Util::toT(Util::toString(counter));
+		item->dir = message.sending ? _T("Out") : _T("In");
+		item->ip = Util::toT(message.ip);
+		item->peer = Util::toT(message.peer);
+		item->message = Util::toT(message.message);
+
+		// first column; include the lParam.
+		lvi.mask = LVIF_PARAM | LVIF_TEXT;
+		lvi.iItem = counter;
+		lvi.iSubItem = 0;
+		lvi.pszText = const_cast<LPTSTR>(item->index.c_str());
+		lvi.lParam = reinterpret_cast<LPARAM>(item);
+		ListView_InsertItem(control, &lvi);
+
+		// no lParam for other columns (ie sub-items).
+		lvi.mask = LVIF_TEXT;
+
+		lvi.iSubItem = 1;
+		lvi.pszText = const_cast<LPTSTR>(item->dir.c_str());
+		ListView_SetItem(control, &lvi);
+
+		lvi.iSubItem = 2;
+		lvi.pszText = const_cast<LPTSTR>(item->ip.c_str());
+		ListView_SetItem(control, &lvi);
+
+		lvi.iSubItem = 3;
+		lvi.pszText = const_cast<LPTSTR>(item->peer.c_str());
+		ListView_SetItem(control, &lvi);
+
+		lvi.iSubItem = 4;
+		lvi.pszText = const_cast<LPTSTR>(item->message.c_str());
+		ListView_SetItem(control, &lvi);
+
+		++counter;
+	}
+
+	if(scroll) {
+		ListView_EnsureVisible(control, lvi.iItem, FALSE);
+	}
+}
+
+void copy(HWND hwnd) {
+	tstring str;
+
+	auto control = GetDlgItem(hwnd, IDC_MESSAGES);
+	LVITEM lvi = { LVIF_PARAM };
+	int i = -1;
+	while((i = ListView_GetNextItem(control, i, LVNI_SELECTED)) != -1) {
+		lvi.iItem = i;
+		if(ListView_GetItem(control, &lvi)) {
+			auto& item = *reinterpret_cast<Item*>(lvi.lParam);
+			if(!str.empty()) { str += _T("\r\n"); }
+			str += item.index + _T(" ") + item.ip + _T(" (") + item.peer + _T("): ") + item.message;
+		}
+	}
+
+	// the following has been taken from WinUtil::setClipboard
+
+	if(!::OpenClipboard(hwnd)) {
+		return;
+	}
+
+	EmptyClipboard();
+
+	// Allocate a global memory object for the text.
+	HGLOBAL hglbCopy = GlobalAlloc(GMEM_MOVEABLE, (str.size() + 1) * sizeof(TCHAR));
+	if(hglbCopy == NULL) {
+		CloseClipboard();
+		return;
+	}
+
+	// Lock the handle and copy the text to the buffer.
+	TCHAR* lptstrCopy = (TCHAR*) GlobalLock(hglbCopy);
+	_tcscpy(lptstrCopy, str.c_str());
+	GlobalUnlock(hglbCopy);
+
+	// Place the handle on the clipboard.
+	SetClipboardData(CF_UNICODETEXT, hglbCopy);
+
+	CloseClipboard();
+}
+
+void switchScroll(HWND hwnd) {
+	scroll = SendMessage(GetDlgItem(hwnd, IDC_SCROLL), BM_GETCHECK, 0, 0) == BST_CHECKED;
+}
+
+void clear(HWND hwnd) {
+	auto control = GetDlgItem(hwnd, IDC_MESSAGES);
+
+	LVITEM lvi = { LVIF_PARAM };
+	for(decltype(counter) i = 0; i < counter; ++i) {
+		lvi.iItem = i;
+		if(ListView_GetItem(control, &lvi)) {
+			delete reinterpret_cast<Item*>(lvi.lParam);
+		}
+	}
+
+	ListView_DeleteAllItems(control);
+	counter = 0;
+}
+
 void command(HWND hwnd, UINT id) {
 	switch(id) {
 	case IDOK:
@@ -95,27 +211,25 @@
 			SendMessage(hwnd, WM_CLOSE, 0, 0);
 			break;
 		}
-	}
-}
-
-void timer(HWND hwnd) {
-	auto control = GetDlgItem(hwnd, IDC_MESSAGES);
-
-	SendMessage(control, WM_SETREDRAW, FALSE, 0);
-
-	{
-		SETTEXTEX config = { ST_SELECTION, CP_ACP };
-
-		Lock l(mutex);
-		for(auto& text: messages) {
-			SendMessage(control, EM_SETSEL, static_cast<WPARAM>(-1), static_cast<LPARAM>(-1));
-			SendMessage(control, EM_SETTEXTEX, reinterpret_cast<WPARAM>(&config), reinterpret_cast<LPARAM>(formatText(text).c_str()));
-		}
-		messages.clear();
-	}
-
-	SendMessage(control, WM_SETREDRAW, TRUE, 0);
-	RedrawWindow(control, 0, 0, RDW_ERASE | RDW_INVALIDATE);
+
+	case IDC_COPY:
+		{
+			copy(hwnd);
+			break;
+		}
+
+	case IDC_SCROLL:
+		{
+			switchScroll(hwnd);
+			break;
+		}
+
+	case IDC_CLEAR:
+		{
+			clear(hwnd);
+			break;
+		}
+	}
 }
 
 INT_PTR CALLBACK DialogProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
@@ -124,19 +238,24 @@
 		{
 			return init(hwnd);
 		}
+	case WM_TIMER:
+		{
+			timer(hwnd);
+			break;
+		}
+	case WM_COMMAND:
+		{
+			command(hwnd, LOWORD(wParam));
+			break;
+		}
 	case WM_CLOSE:
 		{
 			DestroyWindow(hwnd);
 			break;
 		}
-	case WM_COMMAND:
-		{
-			command(hwnd, LOWORD(wParam));
-			break;
-		}
-	case WM_TIMER:
-		{
-			timer(hwnd);
+	case WM_DESTROY:
+		{
+			clear(hwnd);
 			break;
 		}
 	}
@@ -145,7 +264,7 @@
 
 } // unnamed namespace
 
-Dialog::Dialog() : hwnd(nullptr), richEditLib(nullptr)
+Dialog::Dialog() : hwnd(nullptr)
 {
 }
 
@@ -153,14 +272,9 @@
 	if(hwnd) {
 		DestroyWindow(hwnd);
 	}
-	if(richEditLib) {
-		FreeLibrary(richEditLib);
-	}
 }
 
 void Dialog::create(HWND parent) {
-	richEditLib = LoadLibrary(_T("msftedit.dll"));
-
 	hwnd = CreateDialog(instance, MAKEINTRESOURCE(IDD_PLUGINDLG), hwnd, DialogProc);
 
 #ifdef _DEBUG
@@ -170,14 +284,10 @@
 		MessageBox(parent, buf, _T("Error creating the dev plugin's dialog"), MB_OK);
 	}
 #endif
-
-	/// @todo what about when the limit is hit?
-	SendMessage(GetDlgItem(hwnd, IDC_MESSAGES), EM_LIMITTEXT, 10 * 64 * 1024, 0);
-
-	SetTimer(hwnd, 1, 500, 0);
 }
 
-void Dialog::write(string&& text) {
+void Dialog::write(bool sending, string ip, string peer, string message) {
+	Message msg = { sending, move(ip), move(peer), move(message) };
 	Lock l(mutex);
-	messages.push_back(std::move(text));
+	messages.push_back(move(msg));
 }

=== modified file 'plugins/Dev/Dialog.h'
--- plugins/Dev/Dialog.h	2012-07-19 22:00:20 +0000
+++ plugins/Dev/Dialog.h	2012-07-20 13:04:43 +0000
@@ -28,13 +28,12 @@
 	~Dialog();
 
 	void create(HWND parent);
-	void write(string&& text);
+	void write(bool sending, string ip, string peer, string message);
 
 	static HINSTANCE instance;
 
 private:
 	HWND hwnd;
-	HMODULE richEditLib;
 };
 
 #endif

=== modified file 'plugins/Dev/Plugin.cpp'
--- plugins/Dev/Plugin.cpp	2012-07-19 22:00:20 +0000
+++ plugins/Dev/Plugin.cpp	2012-07-20 13:04:43 +0000
@@ -98,22 +98,22 @@
 }
 
 Bool Plugin::onHubDataIn(HubDataPtr hHub, const char* message) {
-	dialog.write("From " + string(hHub->ip) + " (" + string(hHub->url) + "): " + string(message) + "\n");
+	dialog.write(false, hHub->ip, "Hub " + string(hHub->url), message);
 	return False;
 }
 
 Bool Plugin::onHubDataOut(HubDataPtr hHub, const char* message, Bool* bBreak) {
-	dialog.write("To " + string(hHub->ip) + " (" + string(hHub->url) + "): " + string(message) + "\n");
+	dialog.write(true, hHub->ip, "Hub " + string(hHub->url), message);
 	return False;
 }
 
 Bool Plugin::onConnectionDataIn(ConnectionDataPtr hConn, const char* message) {
-	dialog.write("From " + string(hConn->ip) + " (" + string(reinterpret_cast<UserDataPtr>(hConn->object)->nick) + "): " + string(message) + "\n");
+	dialog.write(false, hConn->ip, "User " + string(reinterpret_cast<UserDataPtr>(hConn->object)->nick), message);
 	return False;
 }
 
 Bool Plugin::onConnectionDataOut(ConnectionDataPtr hConn, const char* message) {
-	dialog.write("To " + string(hConn->ip) + " (" + string(reinterpret_cast<UserDataPtr>(hConn->object)->nick) + "): " + string(message) + "\n");
+	dialog.write(true, hConn->ip, "User " + string(reinterpret_cast<UserDataPtr>(hConn->object)->nick), message);
 	return False;
 }
 

=== modified file 'plugins/Dev/resource.h'
--- plugins/Dev/resource.h	2012-07-19 22:00:20 +0000
+++ plugins/Dev/resource.h	2012-07-20 13:04:43 +0000
@@ -5,6 +5,9 @@
 #define VERSION_INFO                    1
 #define IDD_PLUGINDLG                   101
 #define IDC_MESSAGES                    1001
+#define IDC_COPY                        1002
+#define IDC_CLEAR                       1003
+#define IDC_SCROLL                      1004
 
 // Next default values for new objects
 // 
@@ -12,7 +15,7 @@
 #ifndef APSTUDIO_READONLY_SYMBOLS
 #define _APS_NEXT_RESOURCE_VALUE        102
 #define _APS_NEXT_COMMAND_VALUE         40001
-#define _APS_NEXT_CONTROL_VALUE         1002
+#define _APS_NEXT_CONTROL_VALUE         1005
 #define _APS_NEXT_SYMED_VALUE           101
 #endif
 #endif

=== modified file 'plugins/Dev/resource.rc'
--- plugins/Dev/resource.rc	2012-07-19 22:00:20 +0000
+++ plugins/Dev/resource.rc	2012-07-20 13:04:43 +0000
@@ -89,14 +89,17 @@
 // Dialog
 //
 
-IDD_PLUGINDLG DIALOGEX 0, 0, 659, 479
+IDD_PLUGINDLG DIALOGEX 0, 0, 723, 479
 STYLE DS_SETFONT | DS_FIXEDSYS | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
 CAPTION "Dev plugin"
 FONT 8, "MS Shell Dlg", 400, 0, 0x1
 BEGIN
-    DEFPUSHBUTTON   "OK",IDOK,545,458,50,14
-    PUSHBUTTON      "Cancel",IDCANCEL,602,458,50,14
-    CONTROL         "",IDC_MESSAGES,"RICHEDIT50W",WS_BORDER | WS_VSCROLL | WS_HSCROLL | WS_TABSTOP | 0x884,7,7,645,441
+    DEFPUSHBUTTON   "Close",IDOK,666,458,50,14
+    PUSHBUTTON      "Cancel",IDCANCEL,615,458,50,14,NOT WS_VISIBLE | WS_DISABLED
+    CONTROL         "",IDC_MESSAGES,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | WS_BORDER | WS_VSCROLL | WS_HSCROLL | WS_TABSTOP,7,7,709,441
+    PUSHBUTTON      "Copy selected messages",IDC_COPY,7,458,129,14
+    PUSHBUTTON      "Clear the list",IDC_CLEAR,282,458,88,14
+    CONTROL         "Auto-scroll",IDC_SCROLL,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,181,462,58,10
 END
 
 
@@ -111,9 +114,10 @@
     IDD_PLUGINDLG, DIALOG
     BEGIN
         LEFTMARGIN, 7
-        RIGHTMARGIN, 652
+        RIGHTMARGIN, 716
         TOPMARGIN, 7
         BOTTOMMARGIN, 472
+        HORZGUIDE, 458
     END
 END
 #endif    // APSTUDIO_INVOKED