#define STRICT #define WIN32_LEAN_AND_MEAN #include "common.h" #include "resource.h" #include "popup_history.h" #include #define POPUPMENU_TITLE 100 #define POPUPMENU_MESSAGE 101 #define POPUPMENU_TIMESTAMP 102 HWND hHistoryWindow = 0; //the history window PopupHistoryList lstPopupHistory; //defined in main.cpp WNDPROC oldPopupsListProc = NULL; PopupHistoryList::PopupHistoryList() { size = HISTORY_SIZE; //fixed size (at least for now) historyData = (PopupHistoryData *) malloc(size * sizeof(PopupHistoryData)); //alloc space for data count = 0; } PopupHistoryList::~PopupHistoryList() { Clear(); //clear the data strings free(historyData); //deallocate the data list } void PopupHistoryList::Clear() { int i; for (i = 0; i < count; i++) { DeleteData(i); } count = 0; } int PopupHistoryList::Count() { return count; } int PopupHistoryList::Size() { return size; } void PopupHistoryList::RemoveItem(int index) { int i; DeleteData(index); //free the mem for that particular item for (i = index + 1; i < count; i++) { historyData[i - 1] = historyData[i]; //shift all items to the left } } void PopupHistoryList::DeleteData(int index) { PopupHistoryData *item = &historyData[index]; if (item->flags && PHDF_UNICODE) //strings are dupped(), we need to free them { free(item->titleW); free(item->messageW); } else{ free(item->title); free(item->message); } item->timestamp = 0; //invalidate item item->title = NULL; item->message = NULL; item->flags = 0; } void PopupHistoryList::AddItem(PopupHistoryData item) { if (count >= size) { RemoveItem(0); //remove first element - the oldest count--; //it will be inc'ed later } historyData[count++] = item; //item has it's relevant strings dupped() RefreshPopupHistory(hHistoryWindow); } void PopupHistoryList::Add(char *title, char *message, time_t timestamp) { PopupHistoryData item = {0}; //create a history item item.timestamp = timestamp; item.title = strdup(title); item.message = strdup(message); AddItem(item); //add it (flags = 0) } void PopupHistoryList::Add(wchar_t *title, wchar_t *message, time_t timestamp) { PopupHistoryData item = {0}; //create an unicode history item item.flags = PHDF_UNICODE; //mark it as unicode item.timestamp = timestamp; item.titleW = _wcsdup(title); item.messageW = _wcsdup(message); AddItem(item); //add it } PopupHistoryData *PopupHistoryList::Get(int index) { if ((index < 0) || (index >= count)) //a bit of sanity check { return NULL; } return &historyData[index]; } //Stucture passed to list sort function struct SortParams{ HWND hList; int column; }; static int lastColumn = -1; //last sort column int CALLBACK PopupsCompare(LPARAM lParam1, LPARAM lParam2, LPARAM myParam) { SortParams params = *(SortParams *) myParam; const int MAX_SIZE = 512; TCHAR text1[MAX_SIZE]; TCHAR text2[MAX_SIZE]; int res; ListView_GetItemText(params.hList, (int) lParam1, params.column, text1, MAX_SIZE); ListView_GetItemText(params.hList, (int) lParam2, params.column, text2, MAX_SIZE); res = _tcsicmp(text1, text2); res = (params.column == lastColumn) ? -res : res; //do reverse search on second click on same column return res; } void RefreshPopupHistory(HWND hWnd) { if (!hWnd) { return; } HWND hHistoryList = GetDlgItem(hWnd, IDC_LST_HISTORY); ListView_DeleteAllItems(hHistoryList); int i; LVITEM item = {0}; item.mask = LVIF_TEXT; TCHAR buffer[1024]; struct tm *myTime; for (i = 0; i < lstPopupHistory.Count(); i++) { item.iItem = i; PopupHistoryData *popupItem = lstPopupHistory.Get(i); item.pszText = popupItem->titleT; ListView_InsertItem(hHistoryList, &item); ListView_SetItemText(hHistoryList, i, 1, popupItem->messageT); myTime = localtime(&popupItem->timestamp); _tcsftime(buffer, 1024, _T("%c"), myTime); ListView_SetItemText(hHistoryList, i, 2, buffer); } SortParams params = {0}; params.hList = hHistoryList; params.column = lastColumn; ListView_SortItemsEx(hHistoryList, PopupsCompare, ¶ms); } void CopyPopupDataToClipboard(HWND hList, int selection) { if (!selection) { return; } if (!GetOpenClipboardWindow()) { if (OpenClipboard(hList)) { TCHAR buffer[2048]; buffer[0] = _T('\0'); TCHAR *clipboard; int i; int found = 0; int count = ListView_GetItemCount(hList); int textType; #ifdef _UNICODE textType = CF_UNICODETEXT; #else textType = CF_TEXT; #endif for (i = 0; i < count; i++) { if (ListView_GetItemState(hList, i, LVIS_SELECTED)) { ListView_GetItemText(hList, i, selection - 100, buffer, 2048); found = 1; break; } } if (found) { EmptyClipboard(); int len = _tcslen(buffer); HANDLE hData = GlobalAlloc(GMEM_MOVEABLE, (len + 2) * sizeof(TCHAR)); clipboard = (TCHAR *) GlobalLock(hData); _tcsncpy(clipboard, buffer, len); clipboard[len] = _T('\0'); GlobalUnlock(hData); if (!SetClipboardData(textType, hData)) { PUShowMessage("Could not set clipboard data", SM_WARNING); } } CloseClipboard(); } else{ PUShowMessage("Could not open clipboard", SM_WARNING); } } else{ PUShowMessage("The clipboard is not available", SM_WARNING); } } //subclass proc for the list view BOOL CALLBACK PopupsListSubclassProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { switch (msg) { case WM_CONTEXTMENU: { int x = LOWORD(lParam); int y = HIWORD(lParam); int selection; HMENU hMenu = CreatePopupMenu(); AppendMenu(hMenu, MF_STRING, POPUPMENU_TITLE, TranslateT("Copy title to clipboard")); AppendMenu(hMenu, MF_STRING, POPUPMENU_MESSAGE, TranslateT("Copy message to clipboard")); AppendMenu(hMenu, MF_STRING, POPUPMENU_TIMESTAMP, TranslateT("Copy timestamp to clipboard")); selection = TrackPopupMenu(hMenu, TPM_LEFTALIGN | TPM_RIGHTBUTTON | TPM_RETURNCMD, x, y, 0, hWnd, NULL); DestroyMenu(hMenu); if (selection) { CopyPopupDataToClipboard(hWnd, selection); } break; } case WM_KEYUP: { switch (wParam) { case 'C': { if (GetKeyState(VK_CONTROL)) { CopyPopupDataToClipboard(hWnd, POPUPMENU_MESSAGE); } break; } case VK_ESCAPE: { SendMessage(GetParent(hWnd), WM_CLOSE, 0, 0); break; } } break; } case WM_SYSKEYDOWN: { if (wParam == 'X') { SendMessage(GetParent(hWnd), WM_CLOSE, 0, 0); } break; } } return CallWindowProc(oldPopupsListProc, hWnd, msg, wParam, lParam); } //this is the history list window handler BOOL CALLBACK DlgProcHistLst(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { switch (msg) { case WM_INITDIALOG: { TranslateDialogDefault(hWnd); HWND hHistoryList = GetDlgItem(hWnd, IDC_LST_HISTORY); ListView_SetExtendedListViewStyleEx (hHistoryList, LVS_EX_FULLROWSELECT, LVS_EX_FULLROWSELECT); oldPopupsListProc = (WNDPROC) SetWindowLong(hHistoryList, GWL_WNDPROC, (LONG) PopupsListSubclassProc); LVCOLUMN col; col.mask = LVCF_TEXT | LVCF_WIDTH; col.pszText = _T("Title"); col.cx = 100; ListView_InsertColumn(hHistoryList, 0, &col); col.pszText = _T("Message"); col.cx = 450; ListView_InsertColumn(hHistoryList, 1, &col); col.pszText = _T("Timestamp"); col.cx = 115; ListView_InsertColumn(hHistoryList, 2, &col); RefreshPopupHistory(hWnd); return TRUE; } case WM_DESTROY: { hHistoryWindow = NULL; break; } case WM_CLOSE: { DestroyWindow(hWnd); break; } case WM_COMMAND: { switch (LOWORD(wParam)) { case IDC_CLOSE: { SendMessage(hWnd, WM_CLOSE, 0, 0); break; } } break; } case WM_NOTIFY: { switch(((LPNMHDR)lParam)->idFrom) { case IDC_LST_HISTORY: { switch (((LPNMHDR)lParam)->code) { case LVN_COLUMNCLICK: { LPNMLISTVIEW lv = (LPNMLISTVIEW) lParam; int column = lv->iSubItem; SortParams params = {0}; params.hList = GetDlgItem(hWnd, IDC_LST_HISTORY); params.column = column; ListView_SortItemsEx(params.hList, PopupsCompare, (LPARAM) ¶ms); lastColumn = (params.column == lastColumn) ? -1 : params.column; break; } } break; } } break; } } return 0; }