From 48540940b6c28bb4378abfeb500ec45a625b37b6 Mon Sep 17 00:00:00 2001 From: Vadim Dashevskiy Date: Tue, 15 May 2012 10:38:20 +0000 Subject: initial commit git-svn-id: http://svn.miranda-ng.org/main/trunk@2 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c --- src/modules/findadd/findadd.cpp | 1033 +++++++++++++++++++++++++++++++++ src/modules/findadd/findadd.h | 59 ++ src/modules/findadd/searchresults.cpp | 398 +++++++++++++ 3 files changed, 1490 insertions(+) create mode 100644 src/modules/findadd/findadd.cpp create mode 100644 src/modules/findadd/findadd.h create mode 100644 src/modules/findadd/searchresults.cpp (limited to 'src/modules/findadd') diff --git a/src/modules/findadd/findadd.cpp b/src/modules/findadd/findadd.cpp new file mode 100644 index 0000000000..b0bef4fef4 --- /dev/null +++ b/src/modules/findadd/findadd.cpp @@ -0,0 +1,1033 @@ +/* + +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 "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 = ( HANDLE )CallService(MS_CLIST_ADDMAINMENUITEM, 0, (LPARAM)&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; +} diff --git a/src/modules/findadd/findadd.h b/src/modules/findadd/findadd.h new file mode 100644 index 0000000000..8e5fcb29e1 --- /dev/null +++ b/src/modules/findadd/findadd.h @@ -0,0 +1,59 @@ +/* + +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. +*/ +struct ListSearchResult { + const char *szProto; + PROTOSEARCHRESULT psr; +}; + +struct ProtoSearchInfo { + const char *szProto; + HANDLE hProcess; +}; + +struct FindAddDlgData { + HANDLE hResultHook; + int bSortAscending; + int iLastColumnSortIndex; + HIMAGELIST himlComboIcons; + int showProtoId,showEmail,showName,showAdvanced,showTiny; + int minDlgHeight; + int notSearchedYet; + struct ProtoSearchInfo *search; + int searchCount; + HBITMAP hBmpSortUp,hBmpSortDown; + int throbbing; + int pivot; + HWND hwndAdvSearch; + HWND hwndTinySearch; + BOOL bFlexSearchResult; +}; + +int CALLBACK SearchResultsCompareFunc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort); +void FreeSearchResults(HWND hwndResults); +int BeginSearch(HWND hwndDlg,struct FindAddDlgData *dat,const char *szProto,const char *szSearchService,DWORD requiredCapability,void *pvSearchParams); +void SetStatusBarSearchInfo(HWND hwndStatus,struct FindAddDlgData *dat); +void SetStatusBarResultInfo(HWND hwndDlg); +void CreateResultsColumns(HWND hwndResults,struct FindAddDlgData *dat,char *szProto); +void EnableResultButtons(HWND hwndDlg,int enable); +void ShowMoreOptionsMenu(HWND hwndDlg,int x,int y); +void SaveColumnSizes(HWND hwndResults); diff --git a/src/modules/findadd/searchresults.cpp b/src/modules/findadd/searchresults.cpp new file mode 100644 index 0000000000..4c8b7cf46c --- /dev/null +++ b/src/modules/findadd/searchresults.cpp @@ -0,0 +1,398 @@ +/* + +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 "commonheaders.h" +#include "findadd.h" + +enum { + COLUMNID_PROTO, + COLUMNID_HANDLE, + COLUMNID_NICK, + COLUMNID_FIRST, + COLUMNID_LAST, + COLUMNID_EMAIL, + NUM_COLUMNID +}; + +void SaveColumnSizes(HWND hwndResults) +{ + int columnOrder[NUM_COLUMNID]; + int columnCount; + char szSetting[32]; + int i; + struct FindAddDlgData *dat; + + dat=(struct FindAddDlgData*)GetWindowLongPtr(GetParent(hwndResults),GWLP_USERDATA); + columnCount=Header_GetItemCount(ListView_GetHeader(hwndResults)); + if (columnCount != NUM_COLUMNID) return; + ListView_GetColumnOrderArray(hwndResults,columnCount,columnOrder); + for(i=0; i < NUM_COLUMNID; i++) { + mir_snprintf(szSetting, SIZEOF(szSetting), "ColOrder%d", i); + DBWriteContactSettingByte(NULL,"FindAdd",szSetting,(BYTE)columnOrder[i]); + if(i>=columnCount) continue; + mir_snprintf(szSetting, SIZEOF(szSetting), "ColWidth%d", i); + DBWriteContactSettingWord(NULL,"FindAdd",szSetting,(WORD)ListView_GetColumnWidth(hwndResults,i)); + } + DBWriteContactSettingByte(NULL,"FindAdd","SortColumn",(BYTE)dat->iLastColumnSortIndex); + DBWriteContactSettingByte(NULL,"FindAdd","SortAscending",(BYTE)dat->bSortAscending); +} + +static const TCHAR *szColumnNames[] = { NULL, NULL, _T("Nick"), _T("First Name"), _T("Last Name"), _T("E-mail") }; +static int defaultColumnSizes[]={0,90,100,100,100,2000}; +void LoadColumnSizes(HWND hwndResults,const char *szProto) +{ + HDITEM hdi; + int columnOrder[NUM_COLUMNID]; + int columnCount; + char szSetting[32]; + int i; + FindAddDlgData *dat; + bool colOrdersValid; + + defaultColumnSizes[COLUMNID_PROTO] = GetSystemMetrics(SM_CXSMICON) + 4; + dat = (FindAddDlgData*)GetWindowLongPtr(GetParent(hwndResults), GWLP_USERDATA); + + columnCount = NUM_COLUMNID; + colOrdersValid = true; + for(i=0; i < NUM_COLUMNID; i++) + { + LVCOLUMN lvc; + if( i < columnCount ) + { + int bNeedsFree = FALSE; + lvc.mask = LVCF_TEXT | LVCF_WIDTH; + if( szColumnNames[i] != NULL ) + lvc.pszText = TranslateTS( szColumnNames[i] ); + else if( i == COLUMNID_HANDLE ) + { + if (szProto) + { + #if defined( _UNICODE ) + bNeedsFree = TRUE; + lvc.pszText = mir_a2t((char*)CallProtoService(szProto,PS_GETCAPS,PFLAG_UNIQUEIDTEXT,0)); + #else + lvc.pszText = (char*)CallProtoService(szProto,PS_GETCAPS,PFLAG_UNIQUEIDTEXT,0); + #endif + } + else + lvc.pszText = _T("ID"); + } + else lvc.mask &= ~LVCF_TEXT; + mir_snprintf(szSetting, SIZEOF(szSetting), "ColWidth%d", i); + lvc.cx = DBGetContactSettingWord(NULL, "FindAdd", szSetting, defaultColumnSizes[i]); + ListView_InsertColumn(hwndResults, i, (LPARAM)&lvc); + #if defined( _UNICODE ) + if (bNeedsFree) + mir_free(lvc.pszText); + #endif + } + mir_snprintf(szSetting, SIZEOF(szSetting), "ColOrder%d", i); + columnOrder[i] = DBGetContactSettingByte(NULL, "FindAdd", szSetting, -1); + if (columnOrder[i] == -1 || columnOrder[i] >= NUM_COLUMNID) colOrdersValid = false; + } + + if (colOrdersValid) + ListView_SetColumnOrderArray(hwndResults, columnCount, columnOrder); + + dat->iLastColumnSortIndex = DBGetContactSettingByte(NULL, "FindAdd", "SortColumn", COLUMNID_NICK); + if (dat->iLastColumnSortIndex >= columnCount) dat->iLastColumnSortIndex = COLUMNID_NICK; + dat->bSortAscending = DBGetContactSettingByte(NULL, "FindAdd", "SortAscending", TRUE); + + hdi.mask = HDI_BITMAP | HDI_FORMAT; + hdi.fmt = HDF_LEFT | HDF_BITMAP | HDF_STRING | HDF_BITMAP_ON_RIGHT; + hdi.hbm = dat->bSortAscending ? dat->hBmpSortDown : dat->hBmpSortUp; + Header_SetItem(ListView_GetHeader(hwndResults), dat->iLastColumnSortIndex, &hdi); +} + +static LPARAM ListView_GetItemLParam(HWND hwndList, int idx) +{ + LVITEM lv; + lv.iItem = idx; + lv.mask = LVIF_PARAM; + ListView_GetItem(hwndList,&lv); + return lv.lParam; +} + +int CALLBACK SearchResultsCompareFunc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort) +{ + struct FindAddDlgData *dat=(struct FindAddDlgData*)GetWindowLongPtr((HWND) lParamSort, GWLP_USERDATA); + int sortMultiplier; + int sortCol; + struct ListSearchResult *lsr1, *lsr2; + HWND hList=GetDlgItem((HWND) lParamSort, IDC_RESULTS); + + sortMultiplier=dat->bSortAscending?1:-1; + sortCol=dat->iLastColumnSortIndex; + if (!dat->bFlexSearchResult) + { + lsr1=(struct ListSearchResult*)ListView_GetItemLParam(hList, (int)lParam1); + lsr2=(struct ListSearchResult*)ListView_GetItemLParam(hList, (int)lParam2); + + if ( lsr1 == NULL || lsr2 == NULL ) return 0; + switch(sortCol) + { + case COLUMNID_PROTO: + return lstrcmpA(lsr1->szProto, lsr2->szProto)*sortMultiplier; + case COLUMNID_HANDLE: + return lstrcmpi(lsr1->psr.id, lsr2->psr.id)*sortMultiplier; + case COLUMNID_NICK: + return lstrcmpi(lsr1->psr.nick, lsr2->psr.nick)*sortMultiplier; + case COLUMNID_FIRST: + return lstrcmpi(lsr1->psr.firstName, lsr2->psr.firstName)*sortMultiplier; + case COLUMNID_LAST: + return lstrcmpi(lsr1->psr.lastName, lsr2->psr.lastName)*sortMultiplier; + case COLUMNID_EMAIL: + return lstrcmpi(lsr1->psr.email, lsr2->psr.email)*sortMultiplier; + } + } + else + { + TCHAR szText1[100]; + TCHAR szText2[100]; + ListView_GetItemText(hList,(int)lParam1,sortCol,szText1,SIZEOF(szText1)); + ListView_GetItemText(hList,(int)lParam2,sortCol,szText2,SIZEOF(szText2)); + return _tcsicmp(szText1, szText2)*sortMultiplier; + } + return 0; +} + +void FreeSearchResults(HWND hwndResults) +{ + LV_ITEM lvi; + struct ListSearchResult *lsr; + for(lvi.iItem=ListView_GetItemCount(hwndResults)-1;lvi.iItem>=0;lvi.iItem--) { + lvi.mask=LVIF_PARAM; + ListView_GetItem(hwndResults,&lvi); + lsr=(struct ListSearchResult*)lvi.lParam; + if(lsr==NULL) continue; + mir_free(lsr->psr.id); + mir_free(lsr->psr.email); + mir_free(lsr->psr.nick); + mir_free(lsr->psr.firstName); + mir_free(lsr->psr.lastName); + mir_free(lsr); + } + ListView_DeleteAllItems(hwndResults); + EnableResultButtons(GetParent(hwndResults),0); +} + +// on its own thread +static void BeginSearchFailed(void * arg) +{ + TCHAR buf[128]; + if ( arg != NULL ) { + const TCHAR* protoName = (TCHAR*)arg; + mir_sntprintf(buf,SIZEOF(buf), + TranslateT("Could not start a search on '%s', there was a problem - is %s connected?"), + protoName,protoName); + mir_free((char*)arg); + } + else lstrcpyn(buf,TranslateT("Could not search on any of the protocols, are you online?"),SIZEOF(buf)); + MessageBox(0,buf,TranslateT("Problem with search"),MB_OK | MB_ICONERROR); +} + +int BeginSearch(HWND,struct FindAddDlgData *dat,const char *szProto,const char *szSearchService,DWORD requiredCapability,void *pvSearchParams) +{ + int i; + if ( szProto == NULL ) { + int failures = 0; + dat->searchCount = 0; + dat->search = (struct ProtoSearchInfo*)mir_calloc(sizeof(struct ProtoSearchInfo) * accounts.getCount()); + 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&requiredCapability)) continue; + dat->search[dat->searchCount].hProcess = (HANDLE)CallProtoService(pa->szModuleName,szSearchService,0,(LPARAM)pvSearchParams); + dat->search[dat->searchCount].szProto = pa->szModuleName; + if ( dat->search[dat->searchCount].hProcess == NULL ) failures++; + else dat->searchCount++; + } + if(failures) { + //infuriatingly vague error message. fixme. + if(dat->searchCount==0) { + forkthread(BeginSearchFailed,0,NULL); + mir_free(dat->search); + dat->search=NULL; + return 1; + } } + } + else { + dat->search=(struct ProtoSearchInfo*)mir_alloc(sizeof(struct ProtoSearchInfo)); + dat->searchCount=1; + dat->search[0].hProcess=(HANDLE)CallProtoService(szProto,szSearchService,0,(LPARAM)pvSearchParams); + dat->search[0].szProto=szProto; + if(dat->search[0].hProcess==NULL) { + //infuriatingly vague error message. fixme. + PROTOACCOUNT* pa = Proto_GetAccount(szProto); + forkthread(BeginSearchFailed, 0, mir_tstrdup(pa->tszAccountName)); + mir_free(dat->search); + dat->search=NULL; + dat->searchCount=0; + return 1; + } + } + return 0; +} + +// !!!!!!!! this code is dangerous like a hell +void SetStatusBarSearchInfo(HWND hwndStatus,struct FindAddDlgData *dat) +{ + TCHAR str[256]; + + if (dat->searchCount != 0 ) { + int i; + + lstrcpy( str, TranslateT("Searching")); + for( i=0; i < dat->searchCount; i++ ) { + PROTOACCOUNT* pa = Proto_GetAccount( dat->search[i].szProto ); + if ( !pa ) + continue; + + lstrcat(str, i ? _T(",") : _T( " " )); + lstrcat(str, pa->tszAccountName ); + } } + else lstrcpy(str, TranslateT("Idle")); + + SendMessage( hwndStatus, SB_SETTEXT, 0, (LPARAM)str ); +} + +struct ProtoResultsSummary { + const char *szProto; + int count; +}; +void SetStatusBarResultInfo(HWND hwndDlg) +{ + HWND hwndStatus=GetDlgItem(hwndDlg,IDC_STATUSBAR); + HWND hwndResults=GetDlgItem(hwndDlg,IDC_RESULTS); + LV_ITEM lvi; + struct ListSearchResult *lsr; + struct ProtoResultsSummary *subtotal=NULL; + int subtotalCount=0; + int i,total; + TCHAR str[256]; + + total=ListView_GetItemCount(hwndResults); + for(lvi.iItem=total-1;lvi.iItem>=0;lvi.iItem--) { + lvi.mask=LVIF_PARAM; + ListView_GetItem(hwndResults,&lvi); + lsr=(struct ListSearchResult*)lvi.lParam; + if(lsr==NULL) continue; + for(i=0;iszProto) { + subtotal[i].count++; + break; + } + } + if(i==subtotalCount) { + subtotal=(struct ProtoResultsSummary*)mir_realloc(subtotal,sizeof(struct ProtoResultsSummary)*(subtotalCount+1)); + subtotal[subtotalCount].szProto=lsr->szProto; + subtotal[subtotalCount++].count=1; + } + } + if ( total != 0 ) { + TCHAR substr[64]; + PROTOACCOUNT* pa = Proto_GetAccount( subtotal[0].szProto ); + if ( pa == NULL ) + return; + + if ( subtotalCount == 1 ) { + if(total==1) mir_sntprintf( str, SIZEOF(str), TranslateT("1 %s user found"), pa->tszAccountName ); + else mir_sntprintf( str, SIZEOF(str), TranslateT("%d %s users found"), total, pa->tszAccountName ); + } + else { + mir_sntprintf( str, SIZEOF(str), TranslateT("%d users found ("),total); + for( i=0; i < subtotalCount; i++ ) { + if ( i ) { + if (( pa = Proto_GetAccount( subtotal[i].szProto )) == NULL ) + return; + lstrcat( str, _T(", ")); + } + mir_sntprintf( substr, SIZEOF(substr), _T("%d %s"), subtotal[i].count, pa->tszAccountName ); + lstrcat( str, substr ); + } + lstrcat( str, _T(")")); + } + mir_free(subtotal); + } + else lstrcpy(str, TranslateT("No users found")); + SendMessage(hwndStatus, SB_SETTEXT, 2, (LPARAM)str ); +} + +void CreateResultsColumns(HWND hwndResults,struct FindAddDlgData *dat,char *szProto) +{ + SaveColumnSizes(hwndResults); + while(ListView_DeleteColumn(hwndResults,0)); + ListView_SetImageList(hwndResults,dat->himlComboIcons,LVSIL_SMALL); + LoadColumnSizes(hwndResults,szProto); +} + +void ShowMoreOptionsMenu(HWND hwndDlg,int x,int y) +{ + struct FindAddDlgData *dat; + HMENU hPopupMenu,hMenu; + int commandId; + struct ListSearchResult *lsr; + + dat=(struct FindAddDlgData*)GetWindowLongPtr(hwndDlg,GWLP_USERDATA); + + { LVITEM lvi; + if(ListView_GetSelectedCount(GetDlgItem(hwndDlg,IDC_RESULTS))!=1) return; + lvi.mask=LVIF_PARAM; + lvi.iItem=ListView_GetNextItem(GetDlgItem(hwndDlg,IDC_RESULTS),-1,LVNI_ALL|LVNI_SELECTED); + ListView_GetItem(GetDlgItem(hwndDlg,IDC_RESULTS),&lvi); + lsr=(struct ListSearchResult*)lvi.lParam; + } + + hMenu=LoadMenu(hMirandaInst,MAKEINTRESOURCE(IDR_CONTEXT)); + hPopupMenu=GetSubMenu(hMenu,4); + CallService(MS_LANGPACK_TRANSLATEMENU,(WPARAM)hPopupMenu,0); + commandId=TrackPopupMenu(hPopupMenu,TPM_RIGHTBUTTON|TPM_RETURNCMD,x,y,0,hwndDlg,NULL); + switch(commandId) { + case IDC_ADD: + { ADDCONTACTSTRUCT acs; + + acs.handle=NULL; + acs.handleType=HANDLE_SEARCHRESULT; + acs.szProto=lsr->szProto; + acs.psr=&lsr->psr; + CallService(MS_ADDCONTACT_SHOW,(WPARAM)hwndDlg,(LPARAM)&acs); + break; + } + case IDC_DETAILS: + { HANDLE hContact; + hContact=(HANDLE)CallProtoService(lsr->szProto,PS_ADDTOLIST,PALF_TEMPORARY,(LPARAM)&lsr->psr); + CallService(MS_USERINFO_SHOWDIALOG,(WPARAM)hContact,0); + break; + } + case IDC_SENDMESSAGE: + { HANDLE hContact; + hContact=(HANDLE)CallProtoService(lsr->szProto,PS_ADDTOLIST,PALF_TEMPORARY,(LPARAM)&lsr->psr); + CallService(MS_MSG_SENDMESSAGE,(WPARAM)hContact,(LPARAM)(const char*)NULL); + break; + } + } + DestroyMenu(hPopupMenu); + DestroyMenu(hMenu); +} + + -- cgit v1.2.3