diff options
Diffstat (limited to 'src/mir_app/src/findadd.cpp')
-rw-r--r-- | src/mir_app/src/findadd.cpp | 1061 |
1 files changed, 1061 insertions, 0 deletions
diff --git a/src/mir_app/src/findadd.cpp b/src/mir_app/src/findadd.cpp new file mode 100644 index 0000000000..e1fa64a9b5 --- /dev/null +++ b/src/mir_app/src/findadd.cpp @@ -0,0 +1,1061 @@ +/* + +Miranda NG: the free IM client for Microsoft* Windows* + +Copyright (ñ) 2012-15 Miranda NG project (http://miranda-ng.org), +Copyright (c) 2000-12 Miranda IM project, +all portions of this codebase are copyrighted to the people +listed in contributors.txt. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "stdafx.h" +#include "findadd.h" + +#define TIMERID_THROBBER 111 + +#define HM_SEARCHACK (WM_USER+10) +#define M_SETGROUPVISIBILITIES (WM_USER+11) + +static HWND hwndFindAdd = NULL; +static HANDLE hHookModulesLoaded = 0; +static HGENMENU hMainMenuItem = NULL; +static int OnSystemModulesLoaded(WPARAM wParam, LPARAM lParam); + +static int FindAddDlgResizer(HWND, LPARAM lParam, UTILRESIZECONTROL *urc) +{ + static int y, nextY, oldTop; + FindAddDlgData *dat = (FindAddDlgData*)lParam; + + switch (urc->wId) { + case IDC_RESULTS: + return RD_ANCHORX_WIDTH | RD_ANCHORY_HEIGHT; + + case IDOK: + dat->minDlgHeight = nextY + urc->rcItem.bottom - urc->rcItem.top; + return RD_ANCHORX_LEFT | RD_ANCHORY_BOTTOM; + + case IDC_ADD: + case IDC_MOREOPTIONS: + return RD_ANCHORX_RIGHT | RD_ANCHORY_BOTTOM; + + case IDC_STATUSBAR: + return RD_ANCHORX_WIDTH | RD_ANCHORY_BOTTOM; + + case IDC_PROTOIDGROUP: //the resize is always processed in template order + nextY = y = urc->rcItem.top; + if (dat->showProtoId) nextY = y + urc->rcItem.bottom - urc->rcItem.top + 7; + break; + + case IDC_EMAILGROUP: + oldTop = urc->rcItem.top; + y = nextY; + if (dat->showEmail) nextY = y + urc->rcItem.bottom - urc->rcItem.top + 7; + OffsetRect(&urc->rcItem, 0, y - oldTop); + return RD_ANCHORX_LEFT | RD_ANCHORY_CUSTOM; + + case IDC_NAMEGROUP: + oldTop = urc->rcItem.top; + y = nextY; + if (dat->showName) nextY = y + urc->rcItem.bottom - urc->rcItem.top + 7; + OffsetRect(&urc->rcItem, 0, y - oldTop); + return RD_ANCHORX_LEFT | RD_ANCHORY_CUSTOM; + + case IDC_ADVANCEDGROUP: + oldTop = urc->rcItem.top; + y = nextY; + if (dat->showAdvanced) nextY = y + urc->rcItem.bottom - urc->rcItem.top + 7; + OffsetRect(&urc->rcItem, 0, y - oldTop); + return RD_ANCHORX_LEFT | RD_ANCHORY_CUSTOM; + + case IDC_TINYEXTENDEDGROUP: + oldTop = urc->rcItem.top; + y = nextY; + if (dat->showTiny) { + int height = urc->dlgNewSize.cy - y - (urc->dlgOriginalSize.cy - urc->rcItem.bottom); + nextY = y + 200; //min height for custom dialog + urc->rcItem.top = urc->rcItem.bottom - height; + } + return RD_ANCHORX_LEFT | RD_ANCHORY_BOTTOM; + + case IDC_BYEMAIL: + case IDC_EMAIL: + case IDC_BYNAME: + case IDC_STNAMENICK: + case IDC_STNAMEFIRST: + case IDC_STNAMELAST: + case IDC_NAMENICK: + case IDC_NAMEFIRST: + case IDC_NAMELAST: + case IDC_BYADVANCED: + case IDC_BYCUSTOM: + case IDC_ADVANCED: + OffsetRect(&urc->rcItem, 0, y - oldTop); + return RD_ANCHORX_LEFT | RD_ANCHORY_CUSTOM; + + case IDC_HEADERBAR: + return RD_ANCHORX_LEFT | RD_ANCHORY_TOP | RD_ANCHORX_WIDTH; + } + return RD_ANCHORX_LEFT | RD_ANCHORY_TOP; +} + +static void RenderThrobber(HDC hdc, RECT *rcItem, int *throbbing, int *pivot) +{ + InflateRect(rcItem, -1, 0); + int width = rcItem->right - rcItem->left; + int height = rcItem->bottom - rcItem->top; + int height2 = height / 2; + + if (*throbbing) { + /* create memdc */ + HDC hMemDC = CreateCompatibleDC(0); + HBITMAP hBitmap = (HBITMAP)SelectObject(hMemDC, CreateCompatibleBitmap(hdc, width, height)); + /* flush it */ + RECT rc; + rc.left = rc.top = 0; + rc.right = width; + rc.bottom = height; + HBRUSH hBr = GetSysColorBrush(COLOR_BTNFACE); + FillRect(hMemDC, &rc, hBr); + DeleteObject(hBr); + /* set up the pen */ + HPEN hPen = (HPEN)SelectObject(hMemDC, CreatePen(PS_SOLID, 4, GetSysColor(COLOR_BTNSHADOW))); + /* draw everything before the pivot */ + int x = *pivot; + while (x > (-height)) { + MoveToEx(hMemDC, x + height2, 0, NULL); + LineTo(hMemDC, x - height2, height); + x -= 12; + } + + /* draw everything after the pivot */ + x = *pivot; + while (x < width + height) { + MoveToEx(hMemDC, x + height2, 0, NULL); + LineTo(hMemDC, x - height2, height); + x += 12; + } + + /* move the pivot */ + *pivot += 2; + /* reset the pivot point if it gets past the rect */ + if (*pivot > width) *pivot = 0; + /* put back the old pen and delete the new one */ + DeleteObject(SelectObject(hMemDC, hPen)); + /* cap the top and bottom */ + hPen = (HPEN)SelectObject(hMemDC, CreatePen(PS_SOLID, 1, GetSysColor(COLOR_BTNFACE))); + MoveToEx(hMemDC, 0, 0, NULL); + LineTo(hMemDC, width, 0); + MoveToEx(hMemDC, 0, height - 1, NULL); + LineTo(hMemDC, width, height - 1); + /* select in the old pen and delete the new pen */ + DeleteObject(SelectObject(hMemDC, hPen)); + /* paint to screen */ + BitBlt(hdc, rcItem->left, rcItem->top, width, height, hMemDC, 0, 0, SRCCOPY); + /* select back in the old bitmap and delete the created one, as well as freeing the mem dc. */ + hBitmap = (HBITMAP)SelectObject(hMemDC, hBitmap); + DeleteObject(hBitmap); + DeleteDC(hMemDC); + } + else { + /* just flush the DC */ + HBRUSH hBr = GetSysColorBrush(COLOR_BTNFACE); + FillRect(hdc, rcItem, hBr); + DeleteObject(hBr); + } +} + +static void StartThrobber(HWND hwndDlg, FindAddDlgData *dat) +{ + dat->throbbing = 1; + SetTimer(hwndDlg, TIMERID_THROBBER, 25, NULL); +} + +static void StopThrobber(HWND hwndDlg, FindAddDlgData *dat) +{ + KillTimer(hwndDlg, TIMERID_THROBBER); + dat->throbbing = 0; + dat->pivot = 0; + InvalidateRect(GetDlgItem(hwndDlg, IDC_STATUSBAR), NULL, FALSE); +} + +static LRESULT CALLBACK AdvancedSearchDlgSubclassProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) +{ + if (msg == WM_COMMAND) { + HWND parentHwnd = GetParent(hwndDlg); + switch (LOWORD(wParam)) { + case IDOK: + SendMessage(parentHwnd, WM_COMMAND, MAKEWPARAM(IDOK, BN_CLICKED), (LPARAM)GetDlgItem(parentHwnd, IDOK)); + SetFocus(GetDlgItem(parentHwnd, IDC_ADVANCED)); + break; + + case IDCANCEL: + CheckDlgButton(parentHwnd, IDC_ADVANCED, BST_UNCHECKED); + SendMessage(parentHwnd, WM_COMMAND, MAKEWPARAM(IDC_ADVANCED, BN_CLICKED), (LPARAM)GetDlgItem(parentHwnd, IDC_ADVANCED)); + SetFocus(GetDlgItem(parentHwnd, IDC_ADVANCED)); + break; + } + } + return mir_callNextSubclass(hwndDlg, AdvancedSearchDlgSubclassProc, msg, wParam, lParam); +} + +static void ShowAdvancedSearchDlg(HWND hwndDlg, FindAddDlgData *dat) +{ + char *szProto = (char*)SendDlgItemMessage(hwndDlg, IDC_PROTOLIST, CB_GETITEMDATA, SendDlgItemMessage(hwndDlg, IDC_PROTOLIST, CB_GETCURSEL, 0, 0), 0); + if (szProto == NULL) + return; + + if (dat->hwndAdvSearch == NULL) { + RECT rc; + dat->hwndAdvSearch = (HWND)CallProtoServiceInt(NULL, szProto, PS_CREATEADVSEARCHUI, 0, (LPARAM)hwndDlg); + if (dat->hwndAdvSearch != NULL) + mir_subclassWindow(dat->hwndAdvSearch, AdvancedSearchDlgSubclassProc); + GetWindowRect(GetDlgItem(hwndDlg, IDC_RESULTS), &rc); + SetWindowPos(dat->hwndAdvSearch, 0, rc.left, rc.top, 0, 0, SWP_NOZORDER | SWP_NOSIZE); + } + + AnimateWindow(dat->hwndAdvSearch, 150, AW_ACTIVATE | AW_SLIDE | AW_HOR_POSITIVE); + RedrawWindow(dat->hwndAdvSearch, NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW | RDW_ALLCHILDREN); + + CheckDlgButton(hwndDlg, IDC_ADVANCED, BST_CHECKED); +} + +static void ReposTinySearchDlg(HWND hwndDlg, FindAddDlgData *dat) +{ + if (dat->hwndTinySearch == NULL) + return; + + RECT rc; + RECT clientRect; + POINT pt = { 0, 0 }; + GetWindowRect(GetDlgItem(hwndDlg, IDC_TINYEXTENDEDGROUP), &rc); + GetWindowRect(dat->hwndTinySearch, &clientRect); + pt.x = rc.left; + pt.y = rc.top; + ScreenToClient(hwndDlg, &pt); + SetWindowPos(dat->hwndTinySearch, 0, pt.x + 5, pt.y + 15, rc.right - rc.left - 10, rc.bottom - rc.top - 30, SWP_NOZORDER); +} + +static void ShowTinySearchDlg(HWND hwndDlg, FindAddDlgData *dat) +{ + char *szProto = (char*)SendDlgItemMessage(hwndDlg, IDC_PROTOLIST, CB_GETITEMDATA, SendDlgItemMessage(hwndDlg, IDC_PROTOLIST, CB_GETCURSEL, 0, 0), 0); + if (szProto == NULL) + return; + + if (dat->hwndTinySearch == NULL) { + dat->hwndTinySearch = (HWND)CallProtoServiceInt(NULL, szProto, PS_CREATEADVSEARCHUI, 0, (LPARAM)/*GetDlgItem(*/hwndDlg/*, IDC_TINYEXTENDEDGROUP)*/); + if (dat->hwndTinySearch) + ReposTinySearchDlg(hwndDlg, dat); + else + dat->showTiny = false; + } + ShowWindow(dat->hwndTinySearch, SW_SHOW); +} + +static void HideAdvancedSearchDlg(HWND hwndDlg, FindAddDlgData *dat) +{ + if (dat->hwndAdvSearch == NULL) + return; + + AnimateWindow(dat->hwndAdvSearch, 150, AW_HIDE | AW_BLEND); + CheckDlgButton(hwndDlg, IDC_ADVANCED, BST_UNCHECKED); +} + +void EnableResultButtons(HWND hwndDlg, int enable) +{ + EnableWindow(GetDlgItem(hwndDlg, IDC_ADD), enable); + EnableWindow(GetDlgItem(hwndDlg, IDC_MOREOPTIONS), enable); +} + +static const int controls[] = { IDC_BYPROTOID, IDC_BYEMAIL, IDC_BYNAME, IDC_BYADVANCED, IDC_BYCUSTOM }; + +static void CheckSearchTypeRadioButton(HWND hwndDlg, int idControl) +{ + for (int i = 0; i < SIZEOF(controls); i++) + CheckDlgButton(hwndDlg, controls[i], idControl == controls[i] ? BST_CHECKED : BST_UNCHECKED); +} + +#define sttErrMsg TranslateT("You haven't filled in the search field. Please enter a search term and try again.") +#define sttErrTitle TranslateT("Search") + +static void SetListItemText(HWND hwndList, int idx, int col, TCHAR *szText) +{ + if (szText == NULL || *szText == 0) + szText = TranslateT("<not specified>"); + + ListView_SetItemText(hwndList, idx, col, szText); +} + +static TCHAR* sttDecodeString(DWORD dwFlags, MAllStrings &src) +{ + if (dwFlags & PSR_UNICODE) + return mir_u2t(src.w); + + if (dwFlags & PSR_UTF8) + return mir_utf8decodeT(src.a); + + return mir_a2t(src.a); +} + +static INT_PTR CALLBACK DlgProcFindAdd(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) +{ + FindAddDlgData *dat = (FindAddDlgData*)GetWindowLongPtr(hwndDlg, GWLP_USERDATA); + HWND hwndList = GetDlgItem(hwndDlg, IDC_RESULTS); + + switch (msg) { + case WM_INITDIALOG: + TranslateDialogDefault(hwndDlg); + Window_SetIcon_IcoLib(hwndDlg, SKINICON_OTHER_FINDUSER); + dat = (FindAddDlgData*)mir_calloc(sizeof(FindAddDlgData)); + SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (LONG_PTR)dat); + dat->notSearchedYet = 1; + dat->iLastColumnSortIndex = 1; + dat->bSortAscending = 1; + SendDlgItemMessage(hwndDlg, IDC_MOREOPTIONS, BUTTONSETARROW, 1, 0); + SendDlgItemMessage(hwndDlg, IDOK, BUTTONADDTOOLTIP, (WPARAM)LPGENT("Ctrl+Search add contact"), BATF_TCHAR); + + ListView_SetExtendedListViewStyle(hwndList, LVS_EX_FULLROWSELECT | LVS_EX_HEADERDRAGDROP); + { + RECT rc; + GetClientRect(hwndList, &rc); + + LVCOLUMN lvc; + lvc.mask = LVCF_TEXT | LVCF_WIDTH; + lvc.pszText = TranslateT("Results"); + lvc.cx = rc.right - 1; + ListView_InsertColumn(hwndList, 0, &lvc); + + LVITEM lvi; + lvi.mask = LVIF_TEXT; + lvi.iItem = 0; + lvi.iSubItem = 0; + lvi.pszText = TranslateT("There are no results to display."); + ListView_InsertItem(hwndList, &lvi); + + // Allocate a reasonable amount of space in the status bar + HDC hdc = GetDC(GetDlgItem(hwndDlg, IDC_STATUSBAR)); + SelectObject(hdc, (HFONT)SendDlgItemMessage(hwndDlg, IDC_STATUSBAR, WM_GETFONT, 0, 0)); + + SIZE textSize; + GetTextExtentPoint32(hdc, TranslateT("Searching"), (int)mir_tstrlen(TranslateT("Searching")), &textSize); + + int partWidth[3]; + partWidth[0] = textSize.cx; + GetTextExtentPoint32(hdc, _T("01234567890123456789"), 20, &textSize); + partWidth[0] += textSize.cx; + ReleaseDC(GetDlgItem(hwndDlg, IDC_STATUSBAR), hdc); + partWidth[1] = partWidth[0] + 150; + partWidth[2] = -1; + SendDlgItemMessage(hwndDlg, IDC_STATUSBAR, SB_SETPARTS, SIZEOF(partWidth), (LPARAM)partWidth); + SendDlgItemMessage(hwndDlg, IDC_STATUSBAR, SB_SETTEXT, 1 | SBT_OWNERDRAW, 0); + SetStatusBarSearchInfo(GetDlgItem(hwndDlg, IDC_STATUSBAR), dat); + + TCHAR *szProto = NULL; + DBVARIANT dbv; + if (!db_get_ts(NULL, "FindAdd", "LastSearched", &dbv)) { + szProto = NEWTSTR_ALLOCA(dbv.ptszVal); + db_free(&dbv); /* free string szProto was fetched with */ + } + + int i, index = 0, cbwidth = 0, netProtoCount = 0; + for (i = 0; i < accounts.getCount(); i++) { + if (!Proto_IsAccountEnabled(accounts[i])) + continue; + + DWORD caps = (DWORD)CallProtoServiceInt(NULL, accounts[i]->szModuleName, PS_GETCAPS, PFLAGNUM_1, 0); + if (caps & PF1_ANYSEARCH) + netProtoCount++; + } + dat->himlComboIcons = ImageList_Create(GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), ILC_COLOR32 | ILC_MASK, netProtoCount + 1, netProtoCount + 1); + SendDlgItemMessage(hwndDlg, IDC_PROTOLIST, CBEM_SETIMAGELIST, 0, (LPARAM)dat->himlComboIcons); + + COMBOBOXEXITEM cbei; + cbei.mask = CBEIF_IMAGE | CBEIF_SELECTEDIMAGE | CBEIF_TEXT | CBEIF_LPARAM; + cbei.iItem = 0; + hdc = GetDC(hwndDlg); + SelectObject(hdc, (HFONT)SendDlgItemMessage(hwndDlg, IDC_PROTOLIST, WM_GETFONT, 0, 0)); + if (netProtoCount > 1) { + cbei.pszText = TranslateT("All networks"); + GetTextExtentPoint32(hdc, cbei.pszText, (int)mir_tstrlen(cbei.pszText), &textSize); + if (textSize.cx > cbwidth) + cbwidth = textSize.cx; + cbei.iImage = cbei.iSelectedImage = ImageList_AddIcon_IconLibLoaded(dat->himlComboIcons, SKINICON_OTHER_SEARCHALL); + cbei.lParam = 0; + SendDlgItemMessage(hwndDlg, IDC_PROTOLIST, CBEM_INSERTITEM, 0, (LPARAM)&cbei); + cbei.iItem++; + } + + for (i = 0; i < accounts.getCount(); i++) { + PROTOACCOUNT *pa = accounts[i]; + if (!Proto_IsAccountEnabled(pa)) + continue; + + DWORD caps = (DWORD)CallProtoServiceInt(NULL, pa->szModuleName, PS_GETCAPS, PFLAGNUM_1, 0); + if (!(caps & PF1_ANYSEARCH)) + continue; + + cbei.pszText = pa->tszAccountName; + GetTextExtentPoint32(hdc, cbei.pszText, (int)mir_tstrlen(cbei.pszText), &textSize); + if (textSize.cx > cbwidth) + cbwidth = textSize.cx; + + HICON hIcon = (HICON)CallProtoServiceInt(NULL, pa->szModuleName, PS_LOADICON, PLI_PROTOCOL | PLIF_SMALL, 0); + cbei.iImage = cbei.iSelectedImage = ImageList_AddIcon(dat->himlComboIcons, hIcon); + DestroyIcon(hIcon); + cbei.lParam = (LPARAM)pa->szModuleName; + SendDlgItemMessageA(hwndDlg, IDC_PROTOLIST, CBEM_INSERTITEM, 0, (LPARAM)&cbei); + if (szProto && cbei.pszText && !mir_tstrcmp(szProto, pa->tszAccountName)) + index = cbei.iItem; + cbei.iItem++; + } + cbwidth += 32; + + RECT rect; + SendDlgItemMessage(hwndDlg, IDC_PROTOLIST, CB_GETDROPPEDCONTROLRECT, 0, (LPARAM)&rect); + if ((rect.right - rect.left) < cbwidth) + SendDlgItemMessage(hwndDlg, IDC_PROTOLIST, CB_SETDROPPEDWIDTH, cbwidth, 0); + SendDlgItemMessage(hwndDlg, IDC_PROTOLIST, CB_SETCURSEL, index, 0); + + SendMessage(hwndDlg, M_SETGROUPVISIBILITIES, 0, 0); + Utils_RestoreWindowPosition(hwndDlg, NULL, "FindAdd", ""); + } + return TRUE; + + case WM_SIZE: + { + UTILRESIZEDIALOG urd = { 0 }; + urd.cbSize = sizeof(urd); + urd.hwndDlg = hwndDlg; + urd.hInstance = g_hInst; + urd.lpTemplate = MAKEINTRESOURCEA(IDD_FINDADD); + urd.lParam = (LPARAM)dat; + urd.pfnResizer = FindAddDlgResizer; + CallService(MS_UTILS_RESIZEDIALOG, 0, (LPARAM)&urd); + ReposTinySearchDlg(hwndDlg, dat); + SendDlgItemMessage(hwndDlg, IDC_STATUSBAR, WM_SIZE, 0, 0); + if (dat->notSearchedYet) { + RECT rc; + GetClientRect(hwndList, &rc); + ListView_SetColumnWidth(hwndList, 0, rc.right); + } + } + //fall through + case WM_MOVE: + if (dat && dat->hwndAdvSearch) { + RECT rc; + GetWindowRect(hwndList, &rc); + SetWindowPos(dat->hwndAdvSearch, 0, rc.left, rc.top, 0, 0, SWP_NOZORDER | SWP_NOSIZE); + } + break; + + case WM_GETMINMAXINFO: + RECT rc, rc2; + GetWindowRect(hwndList, &rc); + GetWindowRect(hwndDlg, &rc2); + { + MINMAXINFO *mmi = (MINMAXINFO*)lParam; + mmi->ptMinTrackSize.x = rc.left - rc2.left + 10 + GetSystemMetrics(SM_CXFRAME); + GetClientRect(GetDlgItem(hwndDlg, IDC_MOREOPTIONS), &rc); + mmi->ptMinTrackSize.x += rc.right + 5; + GetClientRect(GetDlgItem(hwndDlg, IDC_ADD), &rc); + mmi->ptMinTrackSize.x += rc.right + 5; + GetClientRect(GetDlgItem(hwndDlg, IDC_STATUSBAR), &rc); + mmi->ptMinTrackSize.y = dat->minDlgHeight + 20 + GetSystemMetrics(SM_CYCAPTION) + 2 * GetSystemMetrics(SM_CYFRAME); + GetClientRect(GetDlgItem(hwndDlg, IDC_STATUSBAR), &rc); + mmi->ptMinTrackSize.y += rc.bottom; + } + return 0; + + case M_SETGROUPVISIBILITIES: + dat->showAdvanced = dat->showEmail = dat->showName = dat->showProtoId = dat->showTiny = 0; + { + char *szProto = (char*)SendDlgItemMessage(hwndDlg, IDC_PROTOLIST, CB_GETITEMDATA, SendDlgItemMessage(hwndDlg, IDC_PROTOLIST, CB_GETCURSEL, 0, 0), 0); + if (szProto == (char *)CB_ERR) + break; + if (szProto == NULL) { + for (int i = 0; i < accounts.getCount(); i++) { + PROTOACCOUNT *pa = accounts[i]; + if (Proto_IsAccountEnabled(pa)) { + DWORD protoCaps = (DWORD)CallProtoServiceInt(NULL, pa->szModuleName, PS_GETCAPS, PFLAGNUM_1, 0); + if (protoCaps & PF1_SEARCHBYEMAIL) dat->showEmail = 1; + if (protoCaps & PF1_SEARCHBYNAME) dat->showName = 1; + } + } + } + else { + DWORD protoCaps = (DWORD)CallProtoServiceInt(NULL, szProto, PS_GETCAPS, PFLAGNUM_1, 0); + if (protoCaps & PF1_BASICSEARCH) dat->showProtoId = 1; + if (protoCaps & PF1_SEARCHBYEMAIL) dat->showEmail = 1; + if (protoCaps & PF1_SEARCHBYNAME) dat->showName = 1; + + if (protoCaps & PF1_EXTSEARCHUI) dat->showAdvanced = 1; + else if (protoCaps & PF1_EXTSEARCH) dat->showTiny = 1; + + if (protoCaps & PF1_USERIDISEMAIL && dat->showProtoId) { dat->showProtoId = 0; dat->showEmail = 1; } + if (dat->showProtoId) { + char *szUniqueId = (char*)CallProtoServiceInt(NULL, szProto, PS_GETCAPS, PFLAG_UNIQUEIDTEXT, 0); + if (szUniqueId) + SetDlgItemTextA(hwndDlg, IDC_BYPROTOID, szUniqueId); + else + SetDlgItemText(hwndDlg, IDC_BYPROTOID, TranslateT("Handle")); + + if (protoCaps & PF1_NUMERICUSERID) + SetWindowLongPtr(GetDlgItem(hwndDlg, IDC_PROTOID), GWL_STYLE, GetWindowLongPtr(GetDlgItem(hwndDlg, IDC_PROTOID), GWL_STYLE) | ES_NUMBER); + else + SetWindowLongPtr(GetDlgItem(hwndDlg, IDC_PROTOID), GWL_STYLE, GetWindowLongPtr(GetDlgItem(hwndDlg, IDC_PROTOID), GWL_STYLE)&~ES_NUMBER); + } + } + + if (dat->showTiny) + ShowTinySearchDlg(hwndDlg, dat); + else if (dat->hwndTinySearch) { + DestroyWindow(dat->hwndTinySearch); + dat->hwndTinySearch = NULL; + } + +#define en(id, t) ShowWindow( GetDlgItem(hwndDlg, IDC_##id), dat->show##t?SW_SHOW:SW_HIDE) + en(PROTOIDGROUP, ProtoId); en(BYPROTOID, ProtoId); en(PROTOID, ProtoId); + en(EMAILGROUP, Email); en(BYEMAIL, Email); en(EMAIL, Email); + en(NAMEGROUP, Name); en(BYNAME, Name); + en(STNAMENICK, Name); en(NAMENICK, Name); + en(STNAMEFIRST, Name); en(NAMEFIRST, Name); + en(STNAMELAST, Name); en(NAMELAST, Name); + en(ADVANCEDGROUP, Advanced); en(BYADVANCED, Advanced); en(ADVANCED, Advanced); + en(BYCUSTOM, Tiny); en(TINYEXTENDEDGROUP, Tiny); +#undef en + int checkmarkVisible = (dat->showAdvanced && IsDlgButtonChecked(hwndDlg, IDC_BYADVANCED)) || + (dat->showEmail && IsDlgButtonChecked(hwndDlg, IDC_BYEMAIL)) || + (dat->showTiny && IsDlgButtonChecked(hwndDlg, IDC_BYCUSTOM)) || + (dat->showName && IsDlgButtonChecked(hwndDlg, IDC_BYNAME)) || + (dat->showProtoId && IsDlgButtonChecked(hwndDlg, IDC_BYPROTOID)); + if (!checkmarkVisible) { + if (dat->showProtoId) CheckSearchTypeRadioButton(hwndDlg, IDC_BYPROTOID); + else if (dat->showEmail) CheckSearchTypeRadioButton(hwndDlg, IDC_BYEMAIL); + else if (dat->showName) CheckSearchTypeRadioButton(hwndDlg, IDC_BYNAME); + else if (dat->showAdvanced) CheckSearchTypeRadioButton(hwndDlg, IDC_BYADVANCED); + else if (dat->showTiny) CheckSearchTypeRadioButton(hwndDlg, IDC_BYCUSTOM); + } + + SendMessage(hwndDlg, WM_SIZE, 0, 0); + + MINMAXINFO mmi; + SendMessage(hwndDlg, WM_GETMINMAXINFO, 0, (LPARAM)&mmi); + + RECT rc; + GetWindowRect(hwndDlg, &rc); + if (rc.bottom - rc.top < mmi.ptMinTrackSize.y) + SetWindowPos(hwndDlg, 0, 0, 0, rc.right - rc.left, mmi.ptMinTrackSize.y, SWP_NOZORDER | SWP_NOMOVE); + } + break; + + case WM_TIMER: + if (wParam == TIMERID_THROBBER) { + int borders[3]; + SendDlgItemMessage(hwndDlg, IDC_STATUSBAR, SB_GETBORDERS, 0, (LPARAM)borders); + + RECT rc; + SendDlgItemMessage(hwndDlg, IDC_STATUSBAR, SB_GETRECT, 1, (LPARAM)&rc); + InflateRect(&rc, -borders[2] / 2, -borders[1] / 2); + HDC hdc = GetDC(GetDlgItem(hwndDlg, IDC_STATUSBAR)); + RenderThrobber(hdc, &rc, &dat->throbbing, &dat->pivot); + ReleaseDC(GetDlgItem(hwndDlg, IDC_STATUSBAR), hdc); + } + break; + + case WM_DRAWITEM: + { + DRAWITEMSTRUCT *dis = (DRAWITEMSTRUCT*)lParam; + if (dis->CtlID == IDC_STATUSBAR && dis->itemID == 1) { + RenderThrobber(dis->hDC, &dis->rcItem, &dat->throbbing, &dat->pivot); + return TRUE; + } + } + break; + + case WM_NOTIFY: + if (wParam == IDC_RESULTS) { + switch (((LPNMHDR)lParam)->code) { + case LVN_ITEMCHANGED: + { + int count = ListView_GetSelectedCount(hwndList); + if (dat->notSearchedYet) + count = 0; + EnableResultButtons(hwndDlg, count); + } + break; + + case LVN_COLUMNCLICK: + HDITEM hdi; + hdi.mask = HDI_FORMAT; + hdi.fmt = HDF_LEFT | HDF_STRING; + Header_SetItem(ListView_GetHeader(hwndList), dat->iLastColumnSortIndex, &hdi); + + LPNMLISTVIEW nmlv = (LPNMLISTVIEW)lParam; + if (nmlv->iSubItem != dat->iLastColumnSortIndex) { + dat->bSortAscending = TRUE; + dat->iLastColumnSortIndex = nmlv->iSubItem; + } + else dat->bSortAscending = !dat->bSortAscending; + + hdi.fmt = HDF_LEFT | HDF_STRING | (dat->bSortAscending ? HDF_SORTDOWN : HDF_SORTUP); + Header_SetItem(ListView_GetHeader(hwndList), dat->iLastColumnSortIndex, &hdi); + + ListView_SortItemsEx(hwndList, SearchResultsCompareFunc, (LPARAM)hwndDlg); + } + } + break; + + case WM_COMMAND: + switch (LOWORD(wParam)) { + case IDC_PROTOLIST: + if (HIWORD(wParam) == CBN_SELCHANGE) { + HideAdvancedSearchDlg(hwndDlg, dat); + if (dat->hwndAdvSearch) { + DestroyWindow(dat->hwndAdvSearch); + dat->hwndAdvSearch = NULL; + } + if (dat->hwndTinySearch) { + DestroyWindow(dat->hwndTinySearch); + dat->hwndTinySearch = NULL; + } + SendMessage(hwndDlg, M_SETGROUPVISIBILITIES, 0, 0); + } + break; + + case IDC_BYPROTOID: + case IDC_BYEMAIL: + case IDC_BYNAME: + { + int count = ListView_GetSelectedCount(hwndList); + if (dat->notSearchedYet) + count = 0; + EnableWindow(GetDlgItem(hwndDlg, IDC_ADD), count); + HideAdvancedSearchDlg(hwndDlg, dat); + } + break; + + case IDC_PROTOID: + if (HIWORD(wParam) == EN_CHANGE) { + HideAdvancedSearchDlg(hwndDlg, dat); + CheckSearchTypeRadioButton(hwndDlg, IDC_BYPROTOID); + } + break; + + case IDC_EMAIL: + if (HIWORD(wParam) == EN_CHANGE) { + HideAdvancedSearchDlg(hwndDlg, dat); + CheckSearchTypeRadioButton(hwndDlg, IDC_BYEMAIL); + } + break; + + case IDC_NAMENICK: + case IDC_NAMEFIRST: + case IDC_NAMELAST: + if (HIWORD(wParam) == EN_CHANGE) { + HideAdvancedSearchDlg(hwndDlg, dat); + CheckSearchTypeRadioButton(hwndDlg, IDC_BYNAME); + } + break; + + case IDC_ADVANCED: + EnableWindow(GetDlgItem(hwndDlg, IDC_ADD), ListView_GetSelectedCount(hwndList) > 0); + if (IsDlgButtonChecked(hwndDlg, IDC_ADVANCED)) + ShowAdvancedSearchDlg(hwndDlg, dat); + else + HideAdvancedSearchDlg(hwndDlg, dat); + CheckSearchTypeRadioButton(hwndDlg, IDC_BYADVANCED); + break; + + case IDCANCEL: + DestroyWindow(hwndDlg); + break; + + case IDOK: + HideAdvancedSearchDlg(hwndDlg, dat); + if (dat->searchCount) { //cancel search + SetDlgItemText(hwndDlg, IDOK, TranslateT("&Search")); + if (dat->hResultHook) { UnhookEvent(dat->hResultHook); dat->hResultHook = NULL; } + if (dat->search) { mir_free(dat->search); dat->search = NULL; } + dat->searchCount = 0; + StopThrobber(hwndDlg, dat); + SetStatusBarSearchInfo(GetDlgItem(hwndDlg, IDC_STATUSBAR), dat); + } + else { + char *szProto = (char*)SendDlgItemMessage(hwndDlg, IDC_PROTOLIST, CB_GETITEMDATA, SendDlgItemMessage(hwndDlg, IDC_PROTOLIST, CB_GETCURSEL, 0, 0), 0); + if (dat->search) + mir_free(dat->search), dat->search = NULL; + dat->searchCount = 0; + dat->hResultHook = HookEventMessage(ME_PROTO_ACK, hwndDlg, HM_SEARCHACK); + if (IsDlgButtonChecked(hwndDlg, IDC_BYCUSTOM)) + BeginSearch(hwndDlg, dat, szProto, PS_SEARCHBYADVANCED, PF1_EXTSEARCHUI, dat->hwndTinySearch); + else if (IsDlgButtonChecked(hwndDlg, IDC_BYPROTOID)) { + TCHAR str[256]; + GetDlgItemText(hwndDlg, IDC_PROTOID, str, SIZEOF(str)); + rtrimt(str); + if (str[0] == 0) + MessageBox(hwndDlg, sttErrMsg, sttErrTitle, MB_ICONERROR | MB_OK); + else + BeginSearch(hwndDlg, dat, szProto, PS_BASICSEARCH, PF1_BASICSEARCH, str); + } + else if (IsDlgButtonChecked(hwndDlg, IDC_BYEMAIL)) { + TCHAR str[256]; + GetDlgItemText(hwndDlg, IDC_EMAIL, str, SIZEOF(str)); + rtrimt(str); + if (str[0] == 0) + MessageBox(hwndDlg, sttErrMsg, sttErrTitle, MB_ICONERROR | MB_OK); + else + BeginSearch(hwndDlg, dat, szProto, PS_SEARCHBYEMAIL, PF1_SEARCHBYEMAIL, str); + } + else if (IsDlgButtonChecked(hwndDlg, IDC_BYNAME)) { + TCHAR nick[256], first[256], last[256]; + PROTOSEARCHBYNAME psbn; + GetDlgItemText(hwndDlg, IDC_NAMENICK, nick, SIZEOF(nick)); + GetDlgItemText(hwndDlg, IDC_NAMEFIRST, first, SIZEOF(first)); + GetDlgItemText(hwndDlg, IDC_NAMELAST, last, SIZEOF(last)); + psbn.pszFirstName = first; + psbn.pszLastName = last; + psbn.pszNick = nick; + if (nick[0] == 0 && first[0] == 0 && last[0] == 0) + MessageBox(hwndDlg, sttErrMsg, sttErrTitle, MB_ICONERROR | MB_OK); + else + BeginSearch(hwndDlg, dat, szProto, PS_SEARCHBYNAME, PF1_SEARCHBYNAME, &psbn); + } + else if (IsDlgButtonChecked(hwndDlg, IDC_BYADVANCED)) { + if (dat->hwndAdvSearch == NULL) + MessageBox(hwndDlg, sttErrMsg, sttErrTitle, MB_ICONERROR | MB_OK); + else + BeginSearch(hwndDlg, dat, szProto, PS_SEARCHBYADVANCED, PF1_EXTSEARCHUI, dat->hwndAdvSearch); + } + + if (dat->searchCount == 0) { + if (dat->hResultHook) { + UnhookEvent(dat->hResultHook); + dat->hResultHook = NULL; + } + break; + } + + dat->notSearchedYet = 0; + FreeSearchResults(hwndList); + + CreateResultsColumns(hwndList, dat, szProto); + SetStatusBarSearchInfo(GetDlgItem(hwndDlg, IDC_STATUSBAR), dat); + SetStatusBarResultInfo(hwndDlg); + StartThrobber(hwndDlg, dat); + SetDlgItemText(hwndDlg, IDOK, TranslateT("Cancel")); + } + break; + + case IDC_ADD: + { + ADDCONTACTSTRUCT acs = { 0 }; + + if (ListView_GetSelectedCount(hwndList) == 1) { + LVITEM lvi; + lvi.mask = LVIF_PARAM; + lvi.iItem = ListView_GetNextItem(hwndList, -1, LVNI_ALL | LVNI_SELECTED); + ListView_GetItem(hwndList, &lvi); + ListSearchResult *lsr = (ListSearchResult*)lvi.lParam; + acs.szProto = lsr->szProto; + acs.psr = &lsr->psr; + } + else { + TCHAR str[256]; + GetDlgItemText(hwndDlg, IDC_PROTOID, str, SIZEOF(str)); + if (*rtrimt(str) == 0) + break; + + PROTOSEARCHRESULT psr = { 0 }; + psr.cbSize = sizeof(psr); + psr.flags = PSR_TCHAR; + psr.id.t = str; + + acs.psr = &psr; + acs.szProto = (char*)SendDlgItemMessage(hwndDlg, IDC_PROTOLIST, CB_GETITEMDATA, + SendDlgItemMessage(hwndDlg, IDC_PROTOLIST, CB_GETCURSEL, 0, 0), 0); + } + + acs.handleType = HANDLE_SEARCHRESULT; + CallService(MS_ADDCONTACT_SHOW, (WPARAM)hwndDlg, (LPARAM)&acs); + } + break; + + case IDC_MOREOPTIONS: + RECT rc; + GetWindowRect(GetDlgItem(hwndDlg, IDC_MOREOPTIONS), &rc); + ShowMoreOptionsMenu(hwndDlg, rc.left, rc.bottom); + break; + } + + if (lParam && dat->hwndTinySearch == (HWND)lParam && + HIWORD(wParam) == EN_SETFOCUS && LOWORD(wParam) == 0 && + BST_UNCHECKED == IsDlgButtonChecked(hwndDlg, IDC_BYCUSTOM)) { + CheckSearchTypeRadioButton(hwndDlg, IDC_BYCUSTOM); + } + break; + + case WM_CONTEXTMENU: + { + POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) }; + + LVHITTESTINFO lvhti; + lvhti.pt = pt; + ScreenToClient(hwndDlg, &pt); + switch (GetDlgCtrlID(ChildWindowFromPoint(hwndDlg, pt))) { + case IDC_RESULTS: + if (dat->notSearchedYet) + return TRUE; + ScreenToClient(hwndList, &lvhti.pt); + if (ListView_HitTest(hwndList, &lvhti) == -1) + break; + ShowMoreOptionsMenu(hwndDlg, (short)LOWORD(lParam), (short)HIWORD(lParam)); + return TRUE; + } + } + break; + + case HM_SEARCHACK: + { + ACKDATA *ack = (ACKDATA*)lParam; + if (ack->type != ACKTYPE_SEARCH) + break; + + int i; + for (i = 0; i < dat->searchCount; i++) + if (dat->search[i].hProcess == ack->hProcess && dat->search[i].hProcess != NULL && !mir_strcmp(dat->search[i].szProto, ack->szModule)) break; + if (i == dat->searchCount) + break; + + if (ack->result == ACKRESULT_SUCCESS || ack->result == ACKRESULT_FAILED) { + dat->searchCount--; + memmove(dat->search + i, dat->search + i + 1, sizeof(struct ProtoSearchInfo)*(dat->searchCount - i)); + if (dat->searchCount == 0) { + mir_free(dat->search); + dat->search = NULL; + UnhookEvent(dat->hResultHook); + dat->hResultHook = NULL; + SetDlgItemText(hwndDlg, IDOK, TranslateT("&Search")); + StopThrobber(hwndDlg, dat); + } + ListView_SortItemsEx(hwndList, SearchResultsCompareFunc, (LPARAM)hwndDlg); + SetStatusBarSearchInfo(GetDlgItem(hwndDlg, IDC_STATUSBAR), dat); + } + else if (ack->result == ACKRESULT_SEARCHRESULT && ack->lParam) { + CUSTOMSEARCHRESULTS *csr = (CUSTOMSEARCHRESULTS*)ack->lParam; + dat->bFlexSearchResult = TRUE; + PROTOSEARCHRESULT *psr = &csr->psr; + // check if this is column names data (psr->cbSize == 0) + if (psr->cbSize == 0) { // blob contain info about columns + // first remove all exist items + FreeSearchResults(hwndList); + ListView_DeleteAllItems(hwndList); //not sure if previous delete list items too + + //second remove all columns + while (ListView_DeleteColumn(hwndList, 1)); //will delete fist column till it possible + + // now will add columns and captions; + LVCOLUMN lvc = { 0 }; + lvc.mask = LVCF_TEXT; + for (int iColumn = 0; iColumn < csr->nFieldCount; iColumn++) { + lvc.pszText = TranslateTS(csr->pszFields[iColumn]); + ListView_InsertColumn(hwndList, iColumn + 1, &lvc); + } + } + else { // blob contain info about found contacts + ListSearchResult *lsr = (ListSearchResult*)mir_alloc(offsetof(struct ListSearchResult, psr) + psr->cbSize); + lsr->szProto = ack->szModule; + memcpy(&lsr->psr, psr, psr->cbSize); + + /* Next block is not needed but behavior will be kept */ + lsr->psr.id.t = sttDecodeString(psr->flags, psr->id); + lsr->psr.nick.t = sttDecodeString(psr->flags, psr->nick); + lsr->psr.firstName.t = sttDecodeString(psr->flags, psr->firstName); + lsr->psr.lastName.t = sttDecodeString(psr->flags, psr->lastName); + lsr->psr.email.t = sttDecodeString(psr->flags, psr->email); + lsr->psr.flags = psr->flags & ~PSR_UNICODE | PSR_TCHAR; + + LVITEM lvi = { 0 }; + lvi.mask = LVIF_PARAM | LVIF_IMAGE; + lvi.lParam = (LPARAM)lsr; + for (int i = SendDlgItemMessage(hwndDlg, IDC_PROTOLIST, CB_GETCOUNT, 0, 0); i--;) { + char *szComboProto = (char*)SendDlgItemMessage(hwndDlg, IDC_PROTOLIST, CB_GETITEMDATA, i, 0); + if (szComboProto == NULL) continue; + if (!mir_strcmp(szComboProto, ack->szModule)) { + COMBOBOXEXITEM cbei = { 0 }; + cbei.mask = CBEIF_IMAGE; + cbei.iItem = i; + SendDlgItemMessage(hwndDlg, IDC_PROTOLIST, CBEM_GETITEM, 0, (LPARAM)&cbei); + lvi.iImage = cbei.iImage; + } + } + int iItem = ListView_InsertItem(hwndList, &lvi); + for (int col = 0; col < csr->nFieldCount; col++) + SetListItemText(hwndList, iItem, col + 1, csr->pszFields[col]); + + ListView_SortItemsEx(hwndList, SearchResultsCompareFunc, (LPARAM)hwndDlg); + iItem = 0; + while (ListView_SetColumnWidth(hwndList, iItem++, LVSCW_AUTOSIZE_USEHEADER)); + SetStatusBarResultInfo(hwndDlg); + } + break; + } + else if (ack->result == ACKRESULT_DATA) { + PROTOSEARCHRESULT *psr = (PROTOSEARCHRESULT*)ack->lParam; + ListSearchResult *lsr = (ListSearchResult*)mir_alloc(offsetof(struct ListSearchResult, psr) + psr->cbSize); + lsr->szProto = ack->szModule; + + dat->bFlexSearchResult = FALSE; + + memcpy(&lsr->psr, psr, psr->cbSize); + lsr->psr.nick.t = sttDecodeString(psr->flags, psr->nick); + lsr->psr.firstName.t = sttDecodeString(psr->flags, psr->firstName); + lsr->psr.lastName.t = sttDecodeString(psr->flags, psr->lastName); + lsr->psr.email.t = sttDecodeString(psr->flags, psr->email); + lsr->psr.id.t = sttDecodeString(psr->flags, psr->id); + lsr->psr.flags = psr->flags & ~PSR_UNICODE | PSR_TCHAR; + + LVITEM lvi = { 0 }; + lvi.mask = LVIF_PARAM | LVIF_IMAGE; + lvi.lParam = (LPARAM)lsr; + for (int i = SendDlgItemMessage(hwndDlg, IDC_PROTOLIST, CB_GETCOUNT, 0, 0); i--;) { + char *szComboProto = (char*)SendDlgItemMessage(hwndDlg, IDC_PROTOLIST, CB_GETITEMDATA, i, 0); + if (szComboProto == NULL) continue; + if (!mir_strcmp(szComboProto, ack->szModule)) { + COMBOBOXEXITEM cbei = { 0 }; + cbei.mask = CBEIF_IMAGE; + cbei.iItem = i; + SendDlgItemMessage(hwndDlg, IDC_PROTOLIST, CBEM_GETITEM, 0, (LPARAM)&cbei); + lvi.iImage = cbei.iImage; + break; + } + } + + int iItem = ListView_InsertItem(hwndList, &lvi); + SetListItemText(hwndList, iItem, 1, lsr->psr.id.t); + SetListItemText(hwndList, iItem, 2, lsr->psr.nick.t); + SetListItemText(hwndList, iItem, 3, lsr->psr.firstName.t); + SetListItemText(hwndList, iItem, 4, lsr->psr.lastName.t); + SetListItemText(hwndList, iItem, 5, lsr->psr.email.t); + SetStatusBarResultInfo(hwndDlg); + } + } + break; + + case WM_CLOSE: + DestroyWindow(hwndDlg); + break; + + case WM_DESTROY: + int len = SendDlgItemMessage(hwndDlg, IDC_PROTOLIST, CB_GETLBTEXTLEN, SendDlgItemMessage(hwndDlg, IDC_PROTOLIST, CB_GETCURSEL, 0, 0), 0); + TCHAR *szProto = (TCHAR*)alloca(sizeof(TCHAR)*(len + 1)); + if (szProto != NULL) { + *szProto = '\0'; + SendDlgItemMessage(hwndDlg, IDC_PROTOLIST, CB_GETLBTEXT, SendDlgItemMessage(hwndDlg, IDC_PROTOLIST, CB_GETCURSEL, 0, 0), (LPARAM)szProto); + db_set_ts(NULL, "FindAdd", "LastSearched", szProto); + } + + SaveColumnSizes(hwndList); + if (dat->hResultHook != NULL) + UnhookEvent(dat->hResultHook); + FreeSearchResults(hwndList); + ImageList_Destroy(dat->himlComboIcons); + mir_free(dat->search); + if (dat->hwndAdvSearch) { + DestroyWindow(dat->hwndAdvSearch); + dat->hwndAdvSearch = NULL; + } + if (dat->hwndTinySearch) { + DestroyWindow(dat->hwndTinySearch); + dat->hwndTinySearch = NULL; + } + mir_free(dat); + Window_FreeIcon_IcoLib(hwndDlg); + Utils_SaveWindowPosition(hwndDlg, NULL, "FindAdd", ""); + break; + } + return FALSE; +} + +static INT_PTR FindAddCommand(WPARAM, LPARAM) +{ + if (IsWindow(hwndFindAdd)) { + ShowWindow(hwndFindAdd, SW_SHOWNORMAL); + SetForegroundWindow(hwndFindAdd); + SetFocus(hwndFindAdd); + } + else { + int netProtoCount = 0; + + // Make sure we have some networks to search on. This is not ideal since + // this check will be repeated every time the dialog is requested, but it + // must be done since this service can be called from other places than the menu. + // One alternative would be to only create the service if we have network + // protocols loaded but that would delay the creation until MODULE_LOADED and + // that is not good either... + for (int i = 0; i < accounts.getCount(); i++) { + PROTOACCOUNT *pa = accounts[i]; + if (!Proto_IsAccountEnabled(pa)) + continue; + + int protoCaps = CallProtoServiceInt(NULL, pa->szModuleName, PS_GETCAPS, PFLAGNUM_1, 0); + if (protoCaps & PF1_ANYSEARCH) + netProtoCount++; + } + if (netProtoCount > 0) + hwndFindAdd = CreateDialog(g_hInst, MAKEINTRESOURCE(IDD_FINDADD), NULL, DlgProcFindAdd); + } + return 0; +} + +int FindAddPreShutdown(WPARAM, LPARAM) +{ + if (IsWindow(hwndFindAdd)) + DestroyWindow(hwndFindAdd); + hwndFindAdd = NULL; + return 0; +} + +int LoadFindAddModule(void) +{ + CreateServiceFunction(MS_FINDADD_FINDADD, FindAddCommand); + HookEvent(ME_SYSTEM_MODULESLOADED, OnSystemModulesLoaded); + HookEvent(ME_PROTO_ACCLISTCHANGED, OnSystemModulesLoaded); + HookEvent(ME_SYSTEM_PRESHUTDOWN, FindAddPreShutdown); + + CLISTMENUITEM mi = { sizeof(mi) }; + mi.position = 500020000; + mi.icolibItem = GetSkinIconHandle(SKINICON_OTHER_FINDUSER); + mi.pszName = LPGEN("&Find/add contacts..."); + mi.pszService = MS_FINDADD_FINDADD; + hMainMenuItem = Menu_AddMainMenuItem(&mi); + return 0; +} + +static int OnSystemModulesLoaded(WPARAM, LPARAM) +{ + int netProtoCount = 0; + + // Make sure we have some networks to search on. + for (int i = 0; i < accounts.getCount(); i++) { + PROTOACCOUNT *pa = accounts[i]; + int protoCaps = CallProtoServiceInt(NULL, pa->szModuleName, PS_GETCAPS, PFLAGNUM_1, 0); + if (protoCaps & PF1_ANYSEARCH) + netProtoCount++; + } + + Menu_ShowItem(hMainMenuItem, netProtoCount != 0); + return 0; +} |