/* Miranda IM: the free IM client for Microsoft* Windows* Copyright 2000-2009 Miranda ICQ/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 "..\..\core\commonheaders.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 HANDLE hMainMenuItem = NULL; static int OnSystemModulesLoaded(WPARAM wParam, LPARAM lParam); static int FindAddDlgResizer(HWND, LPARAM lParam, UTILRESIZECONTROL *urc) { static int y, nextY, oldTop; struct FindAddDlgData *dat; dat=(struct 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) { HBRUSH hBr; HDC hMemDC; HBITMAP hBitmap; HPEN hPen; RECT rc; int x, width, height, height2; InflateRect(rcItem, -1, 0); width=rcItem->right-rcItem->left; height=rcItem->bottom-rcItem->top; height2=height/2; if (*throbbing) { /* create memdc */ hMemDC=CreateCompatibleDC(0); hBitmap=(HBITMAP)SelectObject(hMemDC, CreateCompatibleBitmap(hdc, width, height)); /* flush it */ rc.left=rc.top=0; rc.right=width; rc.bottom=height; hBr=GetSysColorBrush(COLOR_BTNFACE); FillRect(hMemDC, &rc, hBr); DeleteObject(hBr); /* set up the pen */ hPen=(HPEN)SelectObject(hMemDC, CreatePen(PS_SOLID, 4, GetSysColor(COLOR_BTNSHADOW))); /* draw everything before the pivot */ 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 */ hBr=GetSysColorBrush(COLOR_BTNFACE); FillRect(hdc, rcItem, hBr); DeleteObject(hBr); } } static void StartThrobber(HWND hwndDlg, struct FindAddDlgData *dat) { dat->throbbing=1; SetTimer(hwndDlg, TIMERID_THROBBER, 25, NULL); } static void StopThrobber(HWND hwndDlg, struct FindAddDlgData *dat) { KillTimer(hwndDlg, TIMERID_THROBBER); dat->throbbing=0; dat->pivot=0; InvalidateRect(GetDlgItem(hwndDlg, IDC_STATUSBAR), NULL, FALSE); } static void ShowAdvancedSearchDlg(HWND hwndDlg, struct 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)CallProtoService(szProto, PS_CREATEADVSEARCHUI, 0, (LPARAM)hwndDlg); GetWindowRect(GetDlgItem(hwndDlg, IDC_RESULTS), &rc); SetWindowPos(dat->hwndAdvSearch, 0, rc.left, rc.top, 0, 0, SWP_NOZORDER|SWP_NOSIZE); } if (animateWindow) { animateWindow(dat->hwndAdvSearch, 150, AW_ACTIVATE|AW_SLIDE|AW_HOR_POSITIVE); RedrawWindow(dat->hwndAdvSearch, NULL, NULL, RDW_INVALIDATE|RDW_UPDATENOW|RDW_ALLCHILDREN); } else ShowWindow(dat->hwndAdvSearch, SW_SHOW); CheckDlgButton(hwndDlg, IDC_ADVANCED, BST_CHECKED); } static void ReposTinySearchDlg(HWND hwndDlg, struct FindAddDlgData *dat) { if (dat->hwndTinySearch != NULL) { 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); //SetWindowPos(GetDlgItem(hwndDlg, IDC_TINYEXTENDEDGROUP), 0, 0, 0, rc.right-rc.left, clientRect.bottom-clientRect.top+20, SWP_NOMOVE|SWP_NOZORDER); } } static void ShowTinySearchDlg(HWND hwndDlg, struct 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)CallProtoService(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, struct FindAddDlgData *dat) { if (dat->hwndAdvSearch == NULL) return; if (animateWindow && IsWinVerXPPlus()) //blending is quite slow on win2k animateWindow(dat->hwndAdvSearch, 150, AW_HIDE|AW_BLEND); else ShowWindow(dat->hwndAdvSearch, SW_HIDE); CheckDlgButton(hwndDlg, IDC_ADVANCED, BST_UNCHECKED); } void EnableResultButtons(HWND hwndDlg, int enable) { EnableWindow(GetDlgItem(hwndDlg, IDC_ADD), enable || IsDlgButtonChecked(hwndDlg, IDC_BYPROTOID)); EnableWindow(GetDlgItem(hwndDlg, IDC_MOREOPTIONS), enable); } static void CheckSearchTypeRadioButton(HWND hwndDlg, int idControl) { int i; static const int controls[]={IDC_BYPROTOID, IDC_BYEMAIL, IDC_BYNAME, IDC_BYADVANCED, IDC_BYCUSTOM}; for (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 && szText[0]) { ListView_SetItemText(hwndList, idx, col, szText); } else { ListView_SetItemText(hwndList, idx, col, TranslateT("")); } } static INT_PTR CALLBACK DlgProcFindAdd(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) { struct FindAddDlgData* dat = (struct FindAddDlgData*)GetWindowLongPtr(hwndDlg, GWLP_USERDATA); HWND hwndList = GetDlgItem(hwndDlg, IDC_RESULTS); switch (msg) { case WM_INITDIALOG: { int i, netProtoCount; COMBOBOXEXITEM cbei; HICON hIcon; TranslateDialogDefault(hwndDlg); Window_SetIcon_IcoLib(hwndDlg, SKINICON_OTHER_FINDUSER); dat=(struct FindAddDlgData*)mir_calloc(sizeof(struct FindAddDlgData)); SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (LONG_PTR)dat); dat->notSearchedYet=1; dat->iLastColumnSortIndex=1; dat->bSortAscending=1; dat->hBmpSortUp=(HBITMAP)LoadImage(hMirandaInst, MAKEINTRESOURCE(IDB_SORTCOLUP), IMAGE_BITMAP, 0, 0, LR_LOADMAP3DCOLORS); dat->hBmpSortDown=(HBITMAP)LoadImage(hMirandaInst, MAKEINTRESOURCE(IDB_SORTCOLDOWN), IMAGE_BITMAP, 0, 0, LR_LOADMAP3DCOLORS); SendDlgItemMessage(hwndDlg, IDC_MOREOPTIONS, BUTTONSETARROW, 1, 0); ListView_SetExtendedListViewStyle(hwndList, LVS_EX_FULLROWSELECT|LVS_EX_HEADERDRAGDROP); { LVCOLUMN lvc; RECT rc; LVITEM lvi; GetClientRect(hwndList, &rc); lvc.mask = LVCF_TEXT | LVCF_WIDTH; lvc.pszText = TranslateT("Results"); lvc.cx = rc.right-1; ListView_InsertColumn(hwndList, 0, &lvc); 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 { int partWidth[3]; SIZE textSize; HDC hdc; hdc=GetDC(GetDlgItem(hwndDlg, IDC_STATUSBAR)); SelectObject(hdc, (HFONT)SendDlgItemMessage(hwndDlg, IDC_STATUSBAR, WM_GETFONT, 0, 0)); GetTextExtentPoint32(hdc, TranslateT("Searching"), lstrlen(TranslateT("Searching")), &textSize); 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; int index = 0; DBVARIANT dbv={0}; HDC hdc; SIZE textSize; RECT rect; int cbwidth = 0; if ( !DBGetContactSettingTString(NULL, "FindAdd", "LastSearched", &dbv)) szProto = dbv.ptszVal; for (i=0, netProtoCount=0; i < accounts.getCount(); i++) { if ( !Proto_IsAccountEnabled(accounts[i])) continue; DWORD caps = (DWORD)CallProtoService(accounts[i]->szModuleName, PS_GETCAPS, PFLAGNUM_1, 0); if (caps & PF1_BASICSEARCH || caps & PF1_EXTSEARCH || caps & PF1_SEARCHBYEMAIL || caps & PF1_SEARCHBYNAME) netProtoCount++; } dat->himlComboIcons=ImageList_Create(GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), (IsWinVerXPPlus()?ILC_COLOR32:ILC_COLOR16)|ILC_MASK, netProtoCount+1, netProtoCount+1); SendDlgItemMessage(hwndDlg, IDC_PROTOLIST, CBEM_SETIMAGELIST, 0, (LPARAM)dat->himlComboIcons); 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, lstrlen(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)CallProtoService(pa->szModuleName, PS_GETCAPS, PFLAGNUM_1, 0); if ( !(caps&PF1_BASICSEARCH) && !(caps&PF1_EXTSEARCH) && !(caps&PF1_SEARCHBYEMAIL) && !(caps&PF1_SEARCHBYNAME)) continue; cbei.pszText = pa->tszAccountName; GetTextExtentPoint32(hdc, cbei.pszText, lstrlen(cbei.pszText), &textSize); if (textSize.cx>cbwidth) cbwidth = textSize.cx; hIcon=(HICON)CallProtoService(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 && !lstrcmp(szProto, pa->tszAccountName)) index = cbei.iItem; cbei.iItem++; } cbwidth+=32; SendDlgItemMessage(hwndDlg, IDC_PROTOLIST, CB_GETDROPPEDCONTROLRECT, 0, (LPARAM)&rect); if ((rect.right-rect.left)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: { MINMAXINFO *mmi=(MINMAXINFO*)lParam; RECT rc, rc2; GetWindowRect(hwndList, &rc); GetWindowRect(hwndDlg, &rc2); 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: { char *szProto; int i; DWORD protoCaps; MINMAXINFO mmi; RECT rc; int checkmarkVisible; dat->showAdvanced = dat->showEmail = dat->showName = dat->showProtoId = dat->showTiny = 0; 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 (i=0; i < accounts.getCount(); i++) { PROTOACCOUNT* pa = accounts[i]; if ( !Proto_IsAccountEnabled(pa)) continue; protoCaps=(DWORD)CallProtoService(pa->szModuleName, PS_GETCAPS, PFLAGNUM_1, 0); if (protoCaps&PF1_SEARCHBYEMAIL) dat->showEmail=1; if (protoCaps&PF1_SEARCHBYNAME) dat->showName=1; } } else { protoCaps=(DWORD)CallProtoService(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_EXTSEARCH && !(protoCaps&PF1_EXTSEARCHUI)) dat->showTiny=1; if (protoCaps&PF1_EXTSEARCHUI) dat->showAdvanced=1; if (protoCaps&PF1_USERIDISEMAIL && dat->showProtoId) {dat->showProtoId=0; dat->showEmail=1;} if (dat->showProtoId) { char *szUniqueId; szUniqueId=(char*)CallProtoService(szProto, PS_GETCAPS, PFLAG_UNIQUEIDTEXT, 0); if (szUniqueId) { #if defined(_UNICODE) TCHAR* p = mir_a2u(szUniqueId); SetDlgItemText(hwndDlg, IDC_BYPROTOID, p); mir_free(p); #else SetDlgItemTextA(hwndDlg, IDC_BYPROTOID, szUniqueId); #endif } 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 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); SendMessage(hwndDlg, WM_GETMINMAXINFO, 0, (LPARAM)&mmi); GetWindowRect(hwndDlg, &rc); if (rc.bottom-rc.topthrobbing, &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: { LPNMLISTVIEW nmlv=(LPNMLISTVIEW)lParam; HDITEM hdi; hdi.mask=HDI_BITMAP|HDI_FORMAT; hdi.fmt=HDF_LEFT|HDF_STRING; Header_SetItem(ListView_GetHeader(hwndList), dat->iLastColumnSortIndex, &hdi); if (nmlv->iSubItem != dat->iLastColumnSortIndex) { dat->bSortAscending=TRUE; dat->iLastColumnSortIndex=nmlv->iSubItem; } else dat->bSortAscending=!dat->bSortAscending; hdi.fmt=HDF_LEFT|HDF_BITMAP|HDF_STRING|HDF_BITMAP_ON_RIGHT; hdi.hbm=dat->bSortAscending?dat->hBmpSortDown:dat->hBmpSortUp; Header_SetItem(ListView_GetHeader(hwndList), dat->iLastColumnSortIndex, &hdi); ListView_SortItemsEx(hwndList, SearchResultsCompareFunc, (LPARAM)hwndDlg); } break; } } 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: EnableWindow(GetDlgItem(hwndDlg, IDC_ADD), TRUE); HideAdvancedSearchDlg(hwndDlg, dat); break; case IDC_BYEMAIL: case IDC_BYNAME: EnableWindow(GetDlgItem(hwndDlg, IDC_ADD), ListView_GetSelectedCount(hwndList) > 0); HideAdvancedSearchDlg(hwndDlg, dat); break; case IDC_PROTOID: if (HIWORD(wParam) == EN_CHANGE) { HideAdvancedSearchDlg(hwndDlg, dat); CheckSearchTypeRadioButton(hwndDlg, IDC_BYPROTOID); EnableWindow(GetDlgItem(hwndDlg, IDC_ADD), TRUE); } 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); break; } 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)); rtrim(str); if (str[0] == 0) MessageBox(hwndDlg, sttErrMsg, sttErrTitle, MB_OK); else BeginSearch(hwndDlg, dat, szProto, PS_BASICSEARCHT, PF1_BASICSEARCH, str); } else if (IsDlgButtonChecked(hwndDlg, IDC_BYEMAIL)) { TCHAR str[256]; GetDlgItemText(hwndDlg, IDC_EMAIL, str, SIZEOF(str)); rtrim(str); if (str[0] == 0) MessageBox(hwndDlg, sttErrMsg, sttErrTitle, MB_OK); else BeginSearch(hwndDlg, dat, szProto, PS_SEARCHBYEMAILT, 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_OK); else BeginSearch(hwndDlg, dat, szProto, PS_SEARCHBYNAMET, PF1_SEARCHBYNAME, &psbn); } else if (IsDlgButtonChecked(hwndDlg, IDC_BYADVANCED)) { if (dat->hwndAdvSearch == NULL) MessageBox(hwndDlg, sttErrMsg, sttErrTitle, 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: { LVITEM lvi; struct ListSearchResult *lsr; ADDCONTACTSTRUCT acs = {0}; if (ListView_GetSelectedCount(hwndList) == 1) { lvi.mask = LVIF_PARAM; lvi.iItem = ListView_GetNextItem(hwndList, -1, LVNI_ALL | LVNI_SELECTED); ListView_GetItem(hwndList, &lvi); lsr = (struct ListSearchResult*)lvi.lParam; acs.szProto = lsr->szProto; acs.psr = &lsr->psr; } else { TCHAR str[256]; GetDlgItemText(hwndDlg, IDC_PROTOID, str, SIZEOF(str)); if (*rtrim(str) == 0) break; PROTOSEARCHRESULT psr = {0}; psr.cbSize = sizeof(psr); psr.flags = PSR_TCHAR; psr.id = 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 && !IsDlgButtonChecked(hwndDlg, IDC_BYCUSTOM)) { CheckSearchTypeRadioButton(hwndDlg, IDC_BYCUSTOM); } break; case WM_CONTEXTMENU: { POINT pt; LVHITTESTINFO lvhti; pt.x=(short)LOWORD(lParam); pt.y=(short)HIWORD(lParam); 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; int i; if (ack->type != ACKTYPE_SEARCH) break; for (i=0;isearchCount;i++) if (dat->search[i].hProcess == ack->hProcess && dat->search[i].hProcess != NULL && !lstrcmpA(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) { PROTOSEARCHRESULT *psr; CUSTOMSEARCHRESULTS * csr=(CUSTOMSEARCHRESULTS*)ack->lParam; dat->bFlexSearchResult=TRUE; psr=&(csr->psr); // check if this is column names data (psr->cbSize == 0) if (psr->cbSize == 0) { // blob contain info about columns int iColumn; LVCOLUMN lvc={0}; //firstly remove all exist items FreeSearchResults(hwndList); ListView_DeleteAllItems(hwndList); //not sure if previous delete list items too //secondly remove all columns while (ListView_DeleteColumn(hwndList, 1)); //will delete fist column till it possible //now will add columns and captions; lvc.mask=LVCF_TEXT; for (iColumn=0; iColumnnFieldCount; iColumn++) { lvc.pszText=TranslateTS(csr->pszFields[iColumn]); ListView_InsertColumn (hwndList, iColumn+1, &lvc); } // Column inserting Done } else { // blob contain info about found contacts LVITEM lvi = {0}; int i, col; struct ListSearchResult *lsr; char *szComboProto; COMBOBOXEXITEM cbei = {0}; lsr = (struct 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 */ bool isUnicode = (psr->flags & PSR_UNICODE) != 0; if (psr->id) { BOOL validPtr = isUnicode ? IsBadStringPtrW((wchar_t*)psr->id, 25) : IsBadStringPtrA((char*)psr->id, 25); if ( !validPtr) { isUnicode = false; lsr->psr.id = NULL; } else lsr->psr.id = isUnicode ? mir_u2t((wchar_t*)psr->id) : mir_a2t((char*)psr->id); } lsr->psr.nick = isUnicode ? mir_u2t((wchar_t*)psr->nick) : mir_a2t((char*)psr->nick); lsr->psr.firstName = isUnicode ? mir_u2t((wchar_t*)psr->firstName) : mir_a2t((char*)psr->firstName); lsr->psr.lastName = isUnicode ? mir_u2t((wchar_t*)psr->lastName) : mir_a2t((char*)psr->lastName); lsr->psr.email = isUnicode ? mir_u2t((wchar_t*)psr->email) : mir_a2t((char*)psr->email); lsr->psr.flags = psr->flags & ~PSR_UNICODE | PSR_TCHAR; lvi.mask = LVIF_PARAM | LVIF_IMAGE; lvi.lParam = (LPARAM)lsr; for (i = SendDlgItemMessage(hwndDlg, IDC_PROTOLIST, CB_GETCOUNT, 0, 0); i--;) { szComboProto=(char*)SendDlgItemMessage(hwndDlg, IDC_PROTOLIST, CB_GETITEMDATA, i, 0); if (szComboProto == NULL) continue; if ( !lstrcmpA(szComboProto, ack->szModule)) { cbei.mask = CBEIF_IMAGE; cbei.iItem = i; SendDlgItemMessage(hwndDlg, IDC_PROTOLIST, CBEM_GETITEM, 0, (LPARAM)&cbei); lvi.iImage = cbei.iImage; } } i = ListView_InsertItem(hwndList, &lvi); for (col=0; colnFieldCount; col++) { SetListItemText(hwndList, i, col+1 , csr->pszFields[col]); } ListView_SortItemsEx(hwndList, SearchResultsCompareFunc, (LPARAM)hwndDlg); i=0; while (ListView_SetColumnWidth(hwndList, i++, LVSCW_AUTOSIZE_USEHEADER)); SetStatusBarResultInfo(hwndDlg); } break; } else if (ack->result == ACKRESULT_DATA) { LVITEM lvi={0}; int i, col; PROTOSEARCHRESULT *psr=(PROTOSEARCHRESULT*)ack->lParam; struct ListSearchResult *lsr; char *szComboProto; COMBOBOXEXITEM cbei={0}; dat->bFlexSearchResult=FALSE; lsr=(struct ListSearchResult*)mir_alloc(offsetof(struct ListSearchResult, psr)+psr->cbSize); lsr->szProto=ack->szModule; CopyMemory(&lsr->psr, psr, psr->cbSize); lsr->psr.nick = psr->flags & PSR_UNICODE ? mir_u2t((wchar_t*)psr->nick) : mir_a2t((char*)psr->nick); lsr->psr.firstName = psr->flags & PSR_UNICODE ? mir_u2t((wchar_t*)psr->firstName) : mir_a2t((char*)psr->firstName); lsr->psr.lastName = psr->flags & PSR_UNICODE ? mir_u2t((wchar_t*)psr->lastName) : mir_a2t((char*)psr->lastName); lsr->psr.email = psr->flags & PSR_UNICODE ? mir_u2t((wchar_t*)psr->email) : mir_a2t((char*)psr->email); lsr->psr.id = psr->flags & PSR_UNICODE ? mir_u2t((wchar_t*)psr->id) : mir_a2t((char*)psr->id); lsr->psr.flags = psr->flags & ~PSR_UNICODE | PSR_TCHAR; lvi.mask = LVIF_PARAM|LVIF_IMAGE; lvi.lParam=(LPARAM)lsr; for (i = SendDlgItemMessage(hwndDlg, IDC_PROTOLIST, CB_GETCOUNT, 0, 0); i--;) { szComboProto=(char*)SendDlgItemMessage(hwndDlg, IDC_PROTOLIST, CB_GETITEMDATA, i, 0); if (szComboProto == NULL) continue; if ( !lstrcmpA(szComboProto, ack->szModule)) { cbei.mask=CBEIF_IMAGE; cbei.iItem=i; SendDlgItemMessage(hwndDlg, IDC_PROTOLIST, CBEM_GETITEM, 0, (LPARAM)&cbei); lvi.iImage=cbei.iImage; break; } } i=ListView_InsertItem(hwndList, &lvi); col=1; SetListItemText(hwndList, i, col++, lsr->psr.id); SetListItemText(hwndList, i, col++, lsr->psr.nick); SetListItemText(hwndList, i, col++, lsr->psr.firstName); SetListItemText(hwndList, i, col++, lsr->psr.lastName); SetListItemText(hwndList, i, col++, lsr->psr.email); SetStatusBarResultInfo(hwndDlg); } break; } case WM_CLOSE: DestroyWindow(hwndDlg); break; case WM_DESTROY: { TCHAR *szProto; int len = SendDlgItemMessage(hwndDlg, IDC_PROTOLIST, CB_GETLBTEXTLEN, SendDlgItemMessage(hwndDlg, IDC_PROTOLIST, CB_GETCURSEL, 0, 0), 0); szProto = (TCHAR*)alloca(sizeof(TCHAR)*(len+1)); *szProto='\0'; SendDlgItemMessage(hwndDlg, IDC_PROTOLIST, CB_GETLBTEXT, SendDlgItemMessage(hwndDlg, IDC_PROTOLIST, CB_GETCURSEL, 0, 0), (LPARAM)szProto); DBWriteContactSettingTString(NULL, "FindAdd", "LastSearched", szProto?szProto:_T("")); } 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; } DeleteObject(dat->hBmpSortDown); DeleteObject(dat->hBmpSortUp); 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, i; // 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 (i=0, netProtoCount=0; i < accounts.getCount(); i++) { PROTOACCOUNT* pa = accounts[i]; if ( !Proto_IsAccountEnabled(pa)) continue; int protoCaps=CallProtoService(pa->szModuleName, PS_GETCAPS, PFLAGNUM_1, 0); if (protoCaps&PF1_BASICSEARCH || protoCaps&PF1_SEARCHBYEMAIL || protoCaps&PF1_SEARCHBYNAME || protoCaps&PF1_EXTSEARCHUI) netProtoCount++; } if (netProtoCount > 0) hwndFindAdd=CreateDialog(hMirandaInst, 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 = { 0 }; mi.cbSize = sizeof(mi); mi.position = 500020000; mi.flags = CMIF_ICONFROMICOLIB; 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, i; // Make sure we have some networks to search on. for (i=0, netProtoCount=0; i < accounts.getCount(); i++) { PROTOACCOUNT* pa = accounts[i]; int protoCaps = CallProtoService(pa->szModuleName, PS_GETCAPS, PFLAGNUM_1, 0); if (protoCaps & (PF1_BASICSEARCH | PF1_SEARCHBYEMAIL | PF1_SEARCHBYNAME | PF1_EXTSEARCHUI)) netProtoCount++; } CLISTMENUITEM cmi = { 0 }; cmi.cbSize = sizeof(cmi); cmi.flags = CMIM_FLAGS; if (netProtoCount == 0) cmi.flags |= CMIF_HIDDEN; CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM)hMainMenuItem, (LPARAM)&cmi); return 0; }