/* UserinfoEx plugin for Miranda IM Copyright: © 2006-2010 DeathAxe, Yasnovidyashii, Merlin, K. Romanov, Kreol 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 "ctrl_base.h" #include "ctrl_contact.h" #define MAX_CAT 64 //#define BTN_MENU (WM_USER+1) //#define BTN_EDIT (WM_USER+2) #define EDIT_VALUE (WM_USER+3) #define CBEXM_MENIITEMFIRST (WM_USER+100) // caution: after this message there must be room for all menuitem commnds // so it should be the last message with the highest value typedef struct TCbExItem { WORD wMask; WORD wFlags; DWORD dwID; TCHAR szCat[MAX_CAT]; LPTSTR pszVal; LPCSTR pszIcon; HICON hIcon; } CBEXITEMINTERN, *LPCBEXITEMINTERN; typedef struct TComboEx { LPCBEXITEMINTERN pItems; INT numItems; INT numOther; INT iSelectedItem; BOOLEAN bIsChanged; BOOLEAN bLocked; BOOLEAN bIsEditChanged; HINSTANCE hInstance; HFONT hFont; HWND hEdit; HWND hBtnMenu; HWND hBtnEdit; HWND hBtnAdd; HWND hBtnDel; RECT rect; } CBEX, *LPCBEX; static INT compareProc(LPCVOID cbi1, LPCVOID cbi2) { return _tcscmp(((LPCBEXITEMINTERN)cbi1)->szCat, ((LPCBEXITEMINTERN)cbi2)->szCat); } static INT CheckPhoneSyntax(LPTSTR pszSrc, LPTSTR szNumber, WORD cchNumber, INT& errorPos) { INT lenNum = 0; BOOLEAN hasLeftBreaket = FALSE, hasRightBreaket = FALSE; if (!szNumber || !pszSrc || !*pszSrc || !cchNumber) return 0; *szNumber = 0; errorPos = -1; if (*pszSrc != '+') { errorPos = 2; // set cursor after first digit *(szNumber + lenNum++) = '+'; } else *(szNumber + lenNum++) = *(pszSrc++); for (; lenNum < cchNumber - 1 && *pszSrc != 0; pszSrc++) { switch (*pszSrc) { case '(': if (hasLeftBreaket) { if (errorPos == -1) errorPos = lenNum; break; } if (*(szNumber + lenNum - 1) != ' ') { *(szNumber + lenNum++) = ' '; if (errorPos == -1) errorPos = lenNum + 1; } *(szNumber + lenNum++) = *pszSrc; hasLeftBreaket = TRUE; break; case ')': if (hasRightBreaket) { if (errorPos == -1) errorPos = lenNum; break; } *(szNumber + lenNum++) = *pszSrc; if (*(pszSrc + 1) != ' ') { *(szNumber + lenNum++) = ' '; if (errorPos == -1) errorPos = lenNum; } hasRightBreaket = TRUE; break; case ' ': if (*(szNumber + lenNum - 1) != ' ') { *(szNumber + lenNum++) = *pszSrc; } else if (errorPos == -1) errorPos = lenNum; break; default: if (*pszSrc >= '0' && *pszSrc <= '9' || *pszSrc == '-') { *(szNumber + lenNum++) = *pszSrc; } // remember first error position else if (errorPos == -1) errorPos = lenNum; break; } } *(szNumber + lenNum) = 0; return lenNum; } /** * name: DlgProc_EditEMail() * desc: dialog procedure * * return: 0 or 1 **/ static INT_PTR CALLBACK DlgProc_EMail(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam) { switch (msg) { case WM_INITDIALOG: { LPCBEXITEM cbi = (LPCBEXITEM)lParam; if (!cbi) return FALSE; SetUserData(hDlg, lParam); SendDlgItemMessage(hDlg, IDC_HEADERBAR, WM_SETICON, 0, (LPARAM)IcoLib_GetIcon(ICO_DLG_EMAIL)); if (DB::Setting::GetByte(SET_ICONS_BUTTONS, 1)) { SendDlgItemMessage(hDlg, IDOK, BM_SETIMAGE, IMAGE_ICON, (LPARAM)IcoLib_GetIcon(ICO_BTN_OK)); SendDlgItemMessage(hDlg, IDCANCEL, BM_SETIMAGE, IMAGE_ICON, (LPARAM)IcoLib_GetIcon(ICO_BTN_CANCEL)); } if (*cbi->pszVal) SetWindowText(hDlg, LPGENT("Edit E-Mail")); TranslateDialogDefault(hDlg); SendDlgItemMessage(hDlg, EDIT_CATEGORY, EM_LIMITTEXT, cbi->ccCat - 1, 0); SendDlgItemMessage(hDlg, EDIT_EMAIL, EM_LIMITTEXT, cbi->ccVal - 1, 0); SetDlgItemText(hDlg, EDIT_CATEGORY, cbi->pszCat); SetDlgItemText(hDlg, EDIT_EMAIL, cbi->pszVal); EnableWindow(GetDlgItem(hDlg, EDIT_CATEGORY), !(cbi->wFlags & CBEXIF_CATREADONLY)); EnableWindow(GetDlgItem(hDlg, IDOK), *cbi->pszVal); // translate Userinfo buttons { TCHAR szButton[MAX_PATH]; HWND hBtn; hBtn = GetDlgItem(hDlg, IDOK); GetWindowText(hBtn, szButton, MAX_PATH); SetWindowText(hBtn, TranslateTS(szButton)); hBtn = GetDlgItem(hDlg, IDCANCEL); GetWindowText(hBtn, szButton, MAX_PATH); SetWindowText(hBtn, TranslateTS(szButton)); } return TRUE; } case WM_CTLCOLORSTATIC: SetBkColor((HDC)wParam, RGB(255, 255, 255)); return (INT_PTR)GetStockObject(WHITE_BRUSH); case WM_COMMAND: switch (LOWORD(wParam)) { if (HIWORD(wParam) == BN_CLICKED) { case IDOK: { LPCBEXITEM cbi = (LPCBEXITEM)GetUserData(hDlg); if (cbi->pszVal && cbi->ccVal > 0) GetDlgItemText(hDlg, EDIT_EMAIL, cbi->pszVal, cbi->ccVal); if (cbi->pszCat && cbi->ccCat > 0) GetDlgItemText(hDlg, EDIT_CATEGORY, cbi->pszCat, cbi->ccCat); } case IDCANCEL: EndDialog(hDlg, LOWORD(wParam)); break; } case EDIT_EMAIL: if (HIWORD(wParam) == EN_UPDATE) { TCHAR szText[MAXDATASIZE]; LPTSTR pszAdd, pszDot; LPCBEXITEM cbi = (LPCBEXITEM)GetUserData(hDlg); if (PtrIsValid(cbi)) { GetWindowText((HWND)lParam, szText, SIZEOF(szText)); EnableWindow(GetDlgItem(hDlg, IDOK), ((pszAdd = _tcschr(szText, '@')) && *(pszAdd + 1) != '.' && (pszDot = _tcschr(pszAdd, '.')) && *(pszDot + 1) && _tcscmp(szText, cbi->pszVal))); } } break; } break; } return FALSE; } /** * name: DlgProc_EditPhone() * desc: dialog procedure * * return: 0 or 1 **/ INT_PTR CALLBACK DlgProc_Phone(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam) { switch (msg) { case WM_INITDIALOG: { LPCBEXITEM cbi = (LPCBEXITEM)lParam; UINT i, item, countryCount; LPIDSTRLIST pCountries; HWND hCombo = GetDlgItem(hDlg, EDIT_COUNTRY); if (!cbi) return FALSE; SetUserData(hDlg, lParam); SendDlgItemMessage(hDlg, IDC_HEADERBAR, WM_SETICON, 0, (LPARAM)IcoLib_GetIcon(ICO_DLG_PHONE)); if (DB::Setting::GetByte(SET_ICONS_BUTTONS, 1)) { SendDlgItemMessage(hDlg, IDOK, BM_SETIMAGE, IMAGE_ICON, (LPARAM)IcoLib_GetIcon(ICO_BTN_OK)); SendDlgItemMessage(hDlg, IDCANCEL, BM_SETIMAGE, IMAGE_ICON, (LPARAM)IcoLib_GetIcon(ICO_BTN_CANCEL)); } // translate Userinfo buttons { TCHAR szButton[MAX_PATH]; HWND hBtn; hBtn = GetDlgItem(hDlg, IDOK); GetWindowText(hBtn, szButton, MAX_PATH); SetWindowText(hBtn, TranslateTS(szButton)); hBtn = GetDlgItem(hDlg, IDCANCEL); GetWindowText(hBtn, szButton, MAX_PATH); SetWindowText(hBtn, TranslateTS(szButton)); } if (*cbi->pszVal) SetWindowText(hDlg, LPGENT("Edit Phone Number")); if (cbi->wFlags & CBEXIF_SMS) CheckDlgButton(hDlg, CHECK_SMS, BST_CHECKED); TranslateDialogDefault(hDlg); EnableWindow(GetDlgItem(hDlg, IDOK), *cbi->pszVal); SendDlgItemMessage(hDlg, EDIT_AREA, EM_LIMITTEXT, 31, 0); SendDlgItemMessage(hDlg, EDIT_NUMBER, EM_LIMITTEXT, 63, 0); SendDlgItemMessage(hDlg, EDIT_CATEGORY, EM_LIMITTEXT, cbi->ccCat - 1, 0); SendDlgItemMessage(hDlg, EDIT_PHONE, EM_LIMITTEXT, cbi->ccVal - 1, 0); GetCountryList(&countryCount, &pCountries); for (i = 0; i < countryCount; i++) { if (pCountries[i].nID == 0 || pCountries[i].nID == 0xFFFF) continue; item = SendMessage(hCombo, CB_ADDSTRING, NULL, (LPARAM)pCountries[i].ptszTranslated); SendMessage(hCombo, CB_SETITEMDATA, item, pCountries[i].nID); } SetDlgItemText(hDlg, EDIT_PHONE, cbi->pszVal); SetDlgItemText(hDlg, EDIT_CATEGORY, cbi->pszCat); EnableWindow(GetDlgItem(hDlg, EDIT_CATEGORY), !(cbi->wFlags & CBEXIF_CATREADONLY)); return TRUE; } case WM_CTLCOLORSTATIC: SetBkColor((HDC)wParam, RGB(255, 255, 255)); return (INT_PTR)GetStockObject(WHITE_BRUSH); case WM_COMMAND: { static INT noRecursion=0; switch (LOWORD(wParam)) { if (HIWORD(wParam) == BN_CLICKED) { case IDOK: { LPCBEXITEM cbi = (LPCBEXITEM)GetUserData(hDlg); TCHAR szText[MAXDATASIZE]; INT errorPos; if (!GetDlgItemText(hDlg, EDIT_PHONE, szText, MAXDATASIZE) || !CheckPhoneSyntax(szText, cbi->pszVal, cbi->ccVal, errorPos) || errorPos > -1) { MsgErr(hDlg, TranslateT("The phone number should start with a + and consist of\nnumbers, spaces, brackets and hyphens only.")); /* EDITBALLOONTIP btt; btt.cbStruct = SIZEOF(btt); btt.pszTitle = TranslateW(L"Syntax Error"); btt.pszText = TranslateW(L"The phone number should start with a + and consist of\nnumbers, spaces, brackets and hyphens only."); SendDlgItemMessage(hDlg, EDIT_PHONE, EM_SHOWBALLOONTIP, NULL, (LPARAM)&btt); SetDlgItemText(hDlg, EDIT_PHONE, cbi->pszVal); SendDlgItemMessage(hDlg, EDIT_PHONE, EM_SETSEL, errorPos, errorPos); */ break; } // save category string GetDlgItemText(hDlg, EDIT_CATEGORY, cbi->pszCat, cbi->ccCat); // save SMS flag if (IsDlgButtonChecked(hDlg, CHECK_SMS) != ((cbi->wFlags & CBEXIF_SMS) == CBEXIF_SMS)) { cbi->wFlags ^= CBEXIF_SMS; } } //fall through case IDCANCEL: EndDialog(hDlg, wParam); break; } case EDIT_COUNTRY: if (HIWORD(wParam) != CBN_SELCHANGE) break; case EDIT_AREA: case EDIT_NUMBER: if (LOWORD(wParam) != EDIT_COUNTRY && HIWORD(wParam) != EN_CHANGE) break; if (noRecursion) break; EnableWindow(GetDlgItem(hDlg, IDOK), TRUE); { TCHAR szPhone[MAXDATASIZE], szArea[32], szData[64]; INT nCurSel = SendDlgItemMessage(hDlg, EDIT_COUNTRY, CB_GETCURSEL, 0, 0); UINT nCountry = (nCurSel != CB_ERR) ? SendDlgItemMessage(hDlg, EDIT_COUNTRY, CB_GETITEMDATA, nCurSel, 0) : 0; GetDlgItemText(hDlg, EDIT_AREA, szArea, SIZEOF(szArea)); GetDlgItemText(hDlg, EDIT_NUMBER, szData, SIZEOF(szData)); mir_sntprintf(szPhone, MAXDATASIZE, _T("+%u (%s) %s"), nCountry, szArea, szData); noRecursion = 1; SetDlgItemText(hDlg, EDIT_PHONE, szPhone); noRecursion = 0; } break; case EDIT_PHONE: if (HIWORD(wParam) != EN_UPDATE) break; if (noRecursion) break; noRecursion = 1; { TCHAR szText[MAXDATASIZE], *pText, *pArea, *pNumber; INT isValid = 1; GetDlgItemText(hDlg, EDIT_PHONE, szText, SIZEOF(szText)); if (szText[0] != '+') isValid = 0; if (isValid) { INT i,country = _tcstol(szText + 1, &pText, 10); if (pText - szText > 4) isValid = 0; else { for (i = SendDlgItemMessage(hDlg, EDIT_COUNTRY, CB_GETCOUNT, 0, 0) - 1; i >= 0; i--) { if (country == SendDlgItemMessage(hDlg, EDIT_COUNTRY, CB_GETITEMDATA, i, 0)) { SendDlgItemMessage(hDlg, EDIT_COUNTRY, CB_SETCURSEL, i, 0); break; } } } if (i < 0) isValid=0; } if (isValid) { pArea = pText + _tcscspn(pText, _T("0123456789")); pText = pArea + _tcsspn(pArea, _T("0123456789")); if (*pText) { *pText = '\0'; pNumber = pText + 1 + _tcscspn(pText + 1, _T("0123456789")); SetDlgItemText(hDlg, EDIT_NUMBER, pNumber); } SetDlgItemText(hDlg, EDIT_AREA, pArea); } if (!isValid) { SendDlgItemMessage(hDlg, EDIT_COUNTRY, CB_SETCURSEL, -1, 0); SetDlgItemText(hDlg, EDIT_AREA, _T("")); SetDlgItemText(hDlg, EDIT_NUMBER, _T("")); } } noRecursion = 0; EnableWindow(GetDlgItem(hDlg, IDOK), GetWindowTextLength(GetDlgItem(hDlg, EDIT_PHONE))); break; } break; } } return FALSE; } /** * name: CtrlContactWndProc * desc: window procedure for the extended combobox class * param: hwnd - handle to a extended combobox window * msg - message to handle * wParam - message specific * lParam - message specific * return: message specific **/ static LRESULT CALLBACK CtrlContactWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { LPCBEX cbex = (LPCBEX)GetWindowLongPtr(hwnd, 0); switch (msg) { /** * name: WM_NCCREATE * desc: is called to initiate the window creation * param: wParam - not used * lParam - pointer to a CREATESTRUCT * * return: FALSE on error, TRUE if initialisation was ok **/ case WM_NCCREATE: { LPCREATESTRUCT cs = (LPCREATESTRUCT)lParam; if (!(cbex = (LPCBEX)mir_calloc(1*sizeof(CBEX)))) return FALSE; SetWindowLongPtr(hwnd, 0, (LONG_PTR)cbex); cbex->bLocked = 1; cbex->hFont = (HFONT)GetStockObject(DEFAULT_GUI_FONT); cbex->hInstance = cs->hInstance; cbex->iSelectedItem = -1; cbex->rect.left = cs->x; cbex->rect.top = cs->y; cbex->rect.right = cs->x + cs->cx; cbex->rect.bottom = cs->y + cs->cy; return TRUE; } /** * name: WM_NCCREATE * desc: is called to create all subitems * param: wParam - not used * lParam - not used * * return: FALSE on error, TRUE if initialisation was ok **/ case WM_CREATE: { WORD wHeight = (WORD)(cbex->rect.bottom - cbex->rect.top); WORD wWidth = 130; WORD x = 0; if (!(cbex->hBtnEdit = CreateWindowEx(WS_EX_NOPARENTNOTIFY, UINFOBUTTONCLASS, _T("none"), WS_VISIBLE|WS_CHILD|WS_TABSTOP, 0, 0, wWidth, wHeight, hwnd, NULL, cbex->hInstance, NULL))) { cbex->bLocked = 0; return FALSE; } x += wWidth + 2; wWidth = wHeight; if (!(cbex->hBtnMenu = CreateWindowEx(WS_EX_NOPARENTNOTIFY, UINFOBUTTONCLASS, NULL, WS_VISIBLE|WS_CHILD|WS_TABSTOP|MBS_PUSHBUTTON|MBS_DOWNARROW, x, 0, wWidth, wHeight, hwnd, NULL, cbex->hInstance, NULL))) { DestroyWindow(cbex->hBtnEdit); cbex->bLocked = 0; return FALSE; } x += wWidth + 2; wWidth = (WORD)(cbex->rect.right - cbex->rect.left - x - (2 * (wHeight + 2))); if (!(cbex->hEdit = CreateWindowEx(WS_EX_CLIENTEDGE, _T("Edit"), NULL, WS_VISIBLE|WS_CHILD|WS_TABSTOP|ES_AUTOHSCROLL, x, 1, wWidth, wHeight - 2, hwnd, NULL, cbex->hInstance, NULL))) { DestroyWindow(cbex->hBtnEdit); DestroyWindow(cbex->hBtnMenu); cbex->bLocked = 0; return FALSE; } x += wWidth + 2; wWidth = wHeight; if (!(cbex->hBtnAdd = CreateWindowEx(WS_EX_NOPARENTNOTIFY, UINFOBUTTONCLASS, NULL, WS_VISIBLE|WS_CHILD|WS_TABSTOP|MBS_FLAT, x, 0, wWidth, wHeight, hwnd, NULL, cbex->hInstance, NULL))) { DestroyWindow(cbex->hBtnEdit); DestroyWindow(cbex->hBtnMenu); DestroyWindow(cbex->hEdit); cbex->bLocked = 0; return FALSE; } x += wWidth + 2; if (!(cbex->hBtnDel = CreateWindowEx(WS_EX_NOPARENTNOTIFY, UINFOBUTTONCLASS, NULL, WS_VISIBLE|WS_CHILD|WS_TABSTOP|MBS_FLAT, x, 0, wWidth, wHeight, hwnd, NULL, cbex->hInstance, NULL))) { DestroyWindow(cbex->hBtnEdit); DestroyWindow(cbex->hBtnMenu); DestroyWindow(cbex->hEdit); DestroyWindow(cbex->hBtnAdd); cbex->bLocked = 0; return FALSE; } // set ids SetWindowLongPtr(cbex->hBtnEdit, GWLP_ID, BTN_EDIT); SetWindowLongPtr(cbex->hBtnMenu, GWLP_ID, BTN_MENU); SetWindowLongPtr(cbex->hEdit, GWLP_ID, EDIT_VALUE); SetWindowLongPtr(cbex->hBtnAdd, GWLP_ID, BTN_ADD); SetWindowLongPtr(cbex->hBtnDel, GWLP_ID, BTN_DEL); // set fonts & maximum edit control charachters SendMessage(cbex->hEdit, WM_SETFONT, (WPARAM)cbex->hFont, NULL); SendMessage(cbex->hEdit, EM_LIMITTEXT, (WPARAM)MAXDATASIZE, NULL); // add tooltips SendMessage(cbex->hBtnMenu, BUTTONADDTOOLTIP, (WPARAM)TranslateT("Choose the item to display."), MBF_TCHAR); SendMessage(cbex->hBtnEdit, BUTTONADDTOOLTIP, (WPARAM)TranslateT("Edit the currently displayed item."), MBF_TCHAR); SendMessage(cbex->hBtnAdd, BUTTONADDTOOLTIP, (WPARAM)TranslateT("Add a new custom item."), MBF_TCHAR); SendMessage(cbex->hBtnDel, BUTTONADDTOOLTIP, (WPARAM)TranslateT("Delete the selected item."), MBF_TCHAR); // reload icons CtrlContactWndProc(hwnd, WM_SETICON, NULL, NULL); cbex->bLocked = 0; return TRUE; } /** * name: WM_DESTROY * desc: default destroy message, so clear up memory * param: wParam - not used * lParam - not used * return: return value of DefWindowProc **/ case WM_DESTROY: CtrlContactWndProc(hwnd, CBEXM_DELALLITEMS, NULL, NULL); DestroyWindow(cbex->hBtnEdit); DestroyWindow(cbex->hBtnMenu); DestroyWindow(cbex->hBtnAdd); DestroyWindow(cbex->hBtnDel); DestroyWindow(cbex->hEdit); MIR_FREE(cbex); break; /** * name: WM_CTLCOLOREDIT * desc: is called on a paint message for a dialog item to determine its colour scheme * param: wParam - pointer to a HDC * lParam - pointer to a HWND * return: a brush **/ case WM_CTLCOLOREDIT: if (!DB::Setting::GetByte(SET_PROPSHEET_SHOWCOLOURS, 1) || (HWND)lParam != cbex->hEdit || !cbex->pItems || cbex->iSelectedItem < 0) break; return Ctrl_SetTextColour((HDC)wParam, cbex->pItems[cbex->iSelectedItem].wFlags); case WM_CTLCOLORSTATIC: if ((HWND)lParam == cbex->hEdit) return (BOOL)GetSysColor(COLOR_WINDOW); return FALSE; /** * name: WM_SETICON * desc: updates the icons of this control * param: wParam - not used * lParam - not used * return: always 0 **/ case WM_SETICON: { HICON hIcon; INT i; hIcon = IcoLib_GetIcon(ICO_BTN_ADD); SendMessage(cbex->hBtnAdd, BM_SETIMAGE, IMAGE_ICON, (LPARAM)hIcon); SendMessage(cbex->hBtnAdd, WM_SETTEXT, NULL, (LPARAM)(hIcon ? _T("") : _T("+"))); hIcon = IcoLib_GetIcon(ICO_BTN_DELETE); SendMessage(cbex->hBtnDel, BM_SETIMAGE, IMAGE_ICON, (LPARAM)hIcon); SendMessage(cbex->hBtnDel, WM_SETTEXT, NULL, (LPARAM)(hIcon ? _T("") : _T("-"))); if (cbex->pItems && cbex->numItems > 0) { for (i = 0; i < cbex->numItems; i++) { cbex->pItems[i].hIcon = IcoLib_GetIcon(cbex->pItems[i].pszIcon); } if (cbex->iSelectedItem >= 0 && cbex->iSelectedItem < cbex->numItems) SendMessage(cbex->hBtnEdit, BM_SETIMAGE, IMAGE_ICON, (LPARAM)cbex->pItems[cbex->iSelectedItem].hIcon); } return 0; } case WM_COMMAND: switch (LOWORD(wParam)) { /** * name: BTN_MENU * desc: the button to dropdown the list to show all items is pressed **/ case BTN_MENU: if (HIWORD(wParam) == BN_CLICKED) { POINT pt = { 0, 0 }; RECT rc; MENUITEMINFO mii; INT i, nItems; HMENU hMenu; if (!(hMenu = CreatePopupMenu())) return 0; SetFocus((HWND)lParam); ZeroMemory(&mii, sizeof(MENUITEMINFO)); mii.cbSize = sizeof(MENUITEMINFO); mii.fMask = MIIM_ID|MIIM_STRING|MIIM_FTYPE|MIIM_STATE; mii.fType = MFT_STRING; // insert the items for (i = nItems = 0; i < cbex->numItems; i++) { if ((cbex->pItems[i].wFlags & CBEXIF_DELETED) || *cbex->pItems[i].szCat == 0) continue; mii.fState = (cbex->pItems[i].pszVal && *cbex->pItems[i].pszVal) ? MFS_CHECKED : MFS_UNCHECKED; mii.wID = CBEXM_MENIITEMFIRST + i; mii.dwTypeData = cbex->pItems[i].szCat; if (!InsertMenuItem(hMenu, i, TRUE, &mii)) { DestroyMenu(hMenu); return 0; } nItems++; } // add separator between default and custom items if (nItems > 3) { mii.fMask = MIIM_FTYPE; mii.fType = MFT_SEPARATOR; mii.wID = 0; mii.dwItemData = 0; InsertMenuItem(hMenu, 3, TRUE, &mii); } ClientToScreen((HWND)lParam, &pt); GetClientRect((HWND)lParam, &rc); i = TrackPopupMenuEx(hMenu, TPM_RIGHTALIGN|TPM_RETURNCMD, pt.x + rc.right, pt.y + rc.bottom, hwnd, NULL); SendMessage(cbex->hBtnMenu, BM_SETCHECK, NULL, NULL); if (i >= CBEXM_MENIITEMFIRST && i < CBEXM_MENIITEMFIRST + cbex->numItems) { CtrlContactWndProc(hwnd, CBEXM_SETCURSEL, (WPARAM)i - CBEXM_MENIITEMFIRST, NULL); } DestroyMenu(hMenu); return 0; } break; /** * name: BTN_ADD * desc: the button to add a new entry is pressed **/ case BTN_ADD: if (HIWORD(wParam) == BN_CLICKED) { DLGPROC dlgProc; WORD dlgID; TCHAR szCat[MAX_CAT] = { 0 }; TCHAR szVal[MAXDATASIZE] = { 0 }; CBEXITEM cbi; HWND hDlgDetails; SetFocus((HWND)lParam); if (!(hDlgDetails = GetParent(GetParent(hwnd)))) return 1; if (SendMessage(hDlgDetails, PSM_ISLOCKED, NULL, NULL)) return 0; switch (GetWindowLongPtr(hwnd, GWLP_ID)) { case EDIT_PHONE: dlgID = IDD_ADDPHONE; dlgProc = DlgProc_Phone; cbi.pszIcon = ICO_BTN_CUSTOMPHONE; break; case EDIT_EMAIL: dlgID = IDD_ADDEMAIL; dlgProc = DlgProc_EMail; cbi.pszIcon = ICO_BTN_EMAIL; break; default: return 1; } cbi.iItem = -1; cbi.wMask = CBEXIM_CAT|CBEXIM_VAL|CBEXIM_FLAGS|CBEXIM_ICONTEXT; cbi.pszCat = szCat; cbi.pszVal = szVal; cbi.ccCat = MAX_CAT; cbi.ccVal = MAXDATASIZE; cbi.wFlags = 0; cbi.dwID = 0; if (DialogBoxParam(ghInst, MAKEINTRESOURCE(dlgID), GetParent(hwnd), dlgProc, (LPARAM)&cbi) == IDOK) { HANDLE hContact = NULL; SendMessage(hDlgDetails, PSM_GETCONTACT, NULL, (LPARAM)&hContact); if (hContact) cbi.wFlags |= CTRLF_HASCUSTOM; cbi.wFlags |= CTRLF_CHANGED; if (SendMessage(hwnd, CBEXM_ADDITEM, NULL, (LPARAM)&cbi) > CB_ERR) { SendMessage(hDlgDetails, PSM_CHANGED, NULL, NULL); cbex->bIsChanged = TRUE; SendMessage(hwnd, CBEXM_SETCURSEL, cbex->numItems - 1, NULL); } } return 0; } break; /** * name: BTN_EDIT * desc: the button to edit an existing entry is pressed **/ case BTN_EDIT: if (HIWORD(wParam) == BN_CLICKED) { DLGPROC dlgProc; WORD dlgID; TCHAR szCat[MAX_CAT] = { 0 }; TCHAR szVal[MAXDATASIZE] = { 0 }; CBEXITEM cbi; HWND hDlgDetails; SetFocus((HWND)lParam); if (!(hDlgDetails = GetParent(GetParent(hwnd)))) return 1; if (SendMessage(hDlgDetails, PSM_ISLOCKED, NULL, NULL)) return 0; if (!cbex->pItems || cbex->iSelectedItem == -1) return 0; switch (GetWindowLongPtr(hwnd, GWLP_ID)) { case EDIT_PHONE: dlgID = IDD_ADDPHONE; dlgProc = DlgProc_Phone; break; case EDIT_EMAIL: dlgID = IDD_ADDEMAIL; dlgProc = DlgProc_EMail; break; default: return 1; } cbi.iItem = cbex->iSelectedItem; cbi.dwID = 0; cbi.wMask = CBEXIM_CAT|CBEXIM_VAL|CBEXIM_FLAGS; cbi.pszCat = szCat; cbi.pszVal = szVal; cbi.ccCat = MAX_CAT; cbi.ccVal = MAXDATASIZE; if (!CtrlContactWndProc(hwnd, CBEXM_GETITEM, NULL, (LPARAM)&cbi)) { MsgErr(hwnd, LPGENT("CRITICAL: Unable to edit current entry!\nThis should not happen!")); return 1; } if (DialogBoxParam(ghInst, MAKEINTRESOURCE(dlgID), GetParent(hwnd), dlgProc, (LPARAM)&cbi) == IDOK) { HANDLE hContact; SendMessage(hDlgDetails, PSM_GETCONTACT, NULL, (LPARAM)&hContact); if (hContact) cbi.wFlags |= CTRLF_HASCUSTOM; cbi.wFlags |= CTRLF_CHANGED; SendMessage(hwnd, CBEXM_SETITEM, NULL, (LPARAM)&cbi); SendMessage(hDlgDetails, PSM_CHANGED, NULL, NULL); cbex->bIsChanged = TRUE; } return 0; } break; /** * name: BTN_DEL * desc: the button to delete an existing entry is pressed **/ case BTN_DEL: if (HIWORD(wParam) == BN_CLICKED) { HWND hDlgDetails; MSGBOX mBox; TCHAR szMsg[MAXDATASIZE]; SetFocus((HWND)lParam); if (!(hDlgDetails = GetParent(GetParent(hwnd))) || SendMessage(hDlgDetails, PSM_ISLOCKED, NULL, NULL) || !cbex->pItems || cbex->iSelectedItem < 0 || cbex->iSelectedItem >= cbex->numItems || FAILED(mir_sntprintf(szMsg, MAXDATASIZE, TranslateT("Do you really want to delete the current selected item?\n\t%s\n\t%s"), cbex->pItems[cbex->iSelectedItem].szCat, cbex->pItems[cbex->iSelectedItem].pszVal)) ) { return 1; } mBox.cbSize = sizeof(MSGBOX); mBox.hParent = hDlgDetails; mBox.hiLogo = IcoLib_GetIcon(ICO_DLG_PHONE); mBox.uType = MB_YESNO|MB_ICON_QUESTION|MB_NOPOPUP; mBox.ptszTitle = TranslateT("Delete"); mBox.ptszMsg = szMsg; if (IDYES == MsgBoxService(NULL, (LPARAM)&mBox)) { // clear value for standard entry if (cbex->pItems[cbex->iSelectedItem].wFlags & CBEXIF_CATREADONLY) { MIR_FREE(cbex->pItems[cbex->iSelectedItem].pszVal); SetWindowText(cbex->hEdit, _T("")); cbex->pItems[cbex->iSelectedItem].wFlags &= ~CBEXIF_SMS; cbex->pItems[cbex->iSelectedItem].wFlags |= CTRLF_CHANGED; } // clear values for customized database entry else if (cbex->pItems[cbex->iSelectedItem].dwID != 0) { MIR_FREE(cbex->pItems[cbex->iSelectedItem].pszVal); *cbex->pItems[cbex->iSelectedItem].szCat = 0; cbex->pItems[cbex->iSelectedItem].wFlags |= CTRLF_CHANGED|CBEXIF_DELETED; CtrlContactWndProc(hwnd, CBEXM_SETCURSEL, cbex->iSelectedItem - 1, FALSE); } // delete default entry else CtrlContactWndProc(hwnd, CBEXM_DELITEM, NULL, cbex->iSelectedItem); SendMessage(hDlgDetails, PSM_CHANGED, NULL, NULL); cbex->bIsChanged = TRUE; } return 0; } break; /** * name: EDIT_VALUE * desc: the edit control wants us to act **/ case EDIT_VALUE: switch (HIWORD(wParam)) { case EN_UPDATE: { TCHAR szVal[MAXDATASIZE] = { 0 }; INT ccVal; HANDLE hContact; HWND hDlgDetails = GetParent(GetParent(hwnd)); EnableWindow(cbex->hBtnDel, GetWindowTextLength(cbex->hEdit) > 0); if (SendMessage(hDlgDetails, PSM_ISLOCKED, NULL, NULL) || cbex->bLocked || !cbex->pItems || cbex->iSelectedItem < 0 || cbex->iSelectedItem >= cbex->numItems) return 1; // get the edit control's text value and check it for syntax switch (GetWindowLongPtr(hwnd, GWLP_ID)) { case EDIT_PHONE: { INT errorPos; TCHAR szEdit[MAXDATASIZE]; if (ccVal = GetWindowText(cbex->hEdit, szEdit, MAXDATASIZE)) { if (!(ccVal = CheckPhoneSyntax(szEdit, szVal, MAXDATASIZE, errorPos)) || errorPos > -1) { SetWindowText(cbex->hEdit, szVal); SendMessage(cbex->hEdit, EM_SETSEL, errorPos, errorPos); } } break; } case EDIT_EMAIL: ccVal = GetWindowText(cbex->hEdit, szVal, MAXDATASIZE); break; default: ccVal = GetWindowText(cbex->hEdit, szVal, MAXDATASIZE); break; } SendMessage(hDlgDetails, PSM_GETCONTACT, NULL, (LPARAM)&hContact); if ((cbex->pItems[cbex->iSelectedItem].wFlags & CTRLF_CHANGED) && !(hContact && (cbex->pItems[cbex->iSelectedItem].wFlags & CTRLF_HASCUSTOM))) return 0; if (*szVal == 0 || !cbex->pItems[cbex->iSelectedItem].pszVal || _tcscmp(szVal, cbex->pItems[cbex->iSelectedItem].pszVal)) { cbex->pItems[cbex->iSelectedItem].wFlags |= CTRLF_CHANGED; cbex->pItems[cbex->iSelectedItem].wFlags |= (hContact ? CTRLF_HASCUSTOM : CTRLF_HASPROTO); cbex->bIsChanged = TRUE; InvalidateRect((HWND)lParam, NULL, TRUE); SendMessage(hDlgDetails, PSM_CHANGED, NULL, NULL); } return 0; } case EN_KILLFOCUS: { INT ccText; if (!cbex->pItems || cbex->iSelectedItem < 0 || cbex->iSelectedItem >= cbex->numItems) return 1; if (!(cbex->pItems[cbex->iSelectedItem].wFlags & CTRLF_CHANGED)) return 0; if ((ccText = GetWindowTextLength(cbex->hEdit)) <= 0) { if (cbex->pItems[cbex->iSelectedItem].wFlags & CBEXIF_CATREADONLY) { MIR_FREE(cbex->pItems[cbex->iSelectedItem].pszVal); SetWindowText(cbex->hEdit, _T("")); cbex->pItems[cbex->iSelectedItem].wFlags &= ~CBEXIF_SMS; } else CtrlContactWndProc(hwnd, CBEXM_DELITEM, NULL, cbex->iSelectedItem); SendMessage(GetParent(GetParent(hwnd)), PSM_CHANGED, NULL, NULL); cbex->bIsChanged = TRUE; } else if (cbex->pItems[cbex->iSelectedItem].pszVal = (LPTSTR)mir_realloc(cbex->pItems[cbex->iSelectedItem].pszVal, (ccText + 2) * sizeof(TCHAR))) { cbex->pItems[cbex->iSelectedItem].pszVal[ccText + 1] = 0; GetWindowText(cbex->hEdit, cbex->pItems[cbex->iSelectedItem].pszVal, ccText + 1); } return 0; } } break; } break; /** * name: CBEXM_ADDITEM * desc: add a item to the control * param: wParam - not used * lParam - (LPCBEXITEM)&item * return: CB_ERR on failure, new item index if successful **/ case CBEXM_ADDITEM: { LPCBEXITEM pItem = (LPCBEXITEM)lParam; if (!pItem) return FALSE; // if an item with the id of pItem exists, change it instead of adding a new one // but only if it has not been changed by the user yet. if ((pItem->wMask & CBEXIM_ID) && cbex->pItems && pItem->dwID != 0) { INT iIndex; for (iIndex = 0; iIndex < cbex->numItems; iIndex++) { if (cbex->pItems[iIndex].dwID == pItem->dwID) { pItem->iItem = iIndex; if (cbex->pItems[iIndex].wFlags & CTRLF_CHANGED) pItem->wFlags |= CTRLF_CHANGED; else CtrlContactWndProc(hwnd, CBEXM_SETITEM, 0, lParam); return iIndex; } } } // add a new item to the combobox if (!(cbex->pItems = (LPCBEXITEMINTERN)mir_realloc(cbex->pItems, (cbex->numItems + 1) * sizeof(CBEXITEMINTERN)))) { cbex->numItems = 0; return CB_ERR; } // set the ID cbex->pItems[cbex->numItems].dwID = (pItem->wMask & CBEXIM_ID) ? pItem->dwID : 0; // set category string if (!pItem->pszCat || !pItem->pszCat[0] || !mir_tcsncpy(cbex->pItems[cbex->numItems].szCat, pItem->pszCat, MAX_CAT)) { mir_sntprintf(cbex->pItems[cbex->numItems].szCat, MAX_CAT, _T("%s %d"), TranslateT("Other"), ++cbex->numOther); } // set value string if ((pItem->wMask & CBEXIM_VAL) && pItem->pszVal && pItem->pszVal[0]) cbex->pItems[cbex->numItems].pszVal = mir_tstrdup(pItem->pszVal); else cbex->pItems[cbex->numItems].pszVal = NULL; // set icon if ((pItem->wMask & CBEXIM_ICONTEXT) && pItem->pszIcon) { cbex->pItems[cbex->numItems].pszIcon = pItem->pszIcon; cbex->pItems[cbex->numItems].hIcon = IcoLib_GetIcon(pItem->pszIcon); } // set flags cbex->pItems[cbex->numItems].wFlags = (pItem->wMask & CBEXIM_CAT) ? pItem->wFlags : 0; cbex->numItems++; return cbex->numItems; } /** * name: CBEXM_SETITEM * desc: Set an item's information of the control. * If iItem member of CBEXITEM is -1, the currently selected item is changed. * param: wParam - not used * lParam - (LPCBEXITEM)&item * return: CB_ERR on failure, new item index if successful **/ case CBEXM_SETITEM: { LPCBEXITEM pItem = (LPCBEXITEM)lParam; if (!PtrIsValid(pItem) || !pItem->wMask || !PtrIsValid(cbex->pItems)) return FALSE; if (pItem->iItem == -1) pItem->iItem = cbex->iSelectedItem; if (pItem->iItem < 0 || pItem->iItem >= cbex->numItems) return FALSE; // set new category string if (pItem->wMask & CBEXIM_CAT) { // set category string if (!pItem->pszCat || !pItem->pszCat[0] || !mir_tcsncpy(cbex->pItems[pItem->iItem].szCat, pItem->pszCat, SIZEOF(cbex->pItems[pItem->iItem].szCat))) mir_sntprintf(cbex->pItems[pItem->iItem].szCat, MAX_CAT, _T("%s %d\0"), TranslateT("Other"), ++cbex->numOther); if (pItem->iItem == cbex->iSelectedItem) SetWindowText(cbex->hBtnEdit, cbex->pItems[pItem->iItem].szCat); } // set new value if (pItem->wMask & CBEXIM_VAL) { MIR_FREE(cbex->pItems[pItem->iItem].pszVal); if (pItem->pszVal && pItem->pszVal[0]) cbex->pItems[pItem->iItem].pszVal = mir_tstrdup(pItem->pszVal); if (pItem->iItem == cbex->iSelectedItem) SetWindowText(cbex->hEdit, cbex->pItems[pItem->iItem].pszVal ? cbex->pItems[pItem->iItem].pszVal : _T("")); } // set icon if ((pItem->wMask & CBEXIM_ICONTEXT) && pItem->pszIcon) { cbex->pItems[pItem->iItem].pszIcon = pItem->pszIcon; cbex->pItems[pItem->iItem].hIcon = IcoLib_GetIcon(pItem->pszIcon); if (pItem->iItem == cbex->iSelectedItem) SendMessage(cbex->hBtnEdit, BM_SETIMAGE, IMAGE_ICON, (LPARAM)cbex->pItems[pItem->iItem].hIcon); } if (pItem->wMask & CBEXIM_FLAGS) { cbex->pItems[pItem->iItem].wFlags = pItem->wFlags; CtrlContactWndProc(hwnd, CBEXM_ENABLEITEM, NULL, NULL); } return TRUE; } /** * name: CBEXM_GETITEM * desc: Get an item from the control. * If iItem member of CBEXITEM is -1, the currently selected item is returned. * param: wParam - not used * lParam - (LPCBEXITEM)&item * return: CB_ERR on failure, new item index if successful **/ case CBEXM_GETITEM: { LPCBEXITEM pItem = (LPCBEXITEM)lParam; if (!pItem || !cbex->pItems) return FALSE; // try to find item by id if ((pItem->wMask & CBEXIM_ID) && pItem->dwID != 0) { INT i; for (i = 0; i < cbex->numItems; i++) { if (cbex->pItems[i].dwID == pItem->dwID) break; } pItem->iItem = i; } else if (pItem->iItem == -1) pItem->iItem = cbex->iSelectedItem; if (pItem->iItem < 0 || pItem->iItem >= cbex->numItems) return FALSE; // return only currently selected itemindex if (!pItem->wMask) return TRUE; // return the unique id if (pItem->wMask & CBEXIM_ID) pItem->dwID = cbex->pItems[pItem->iItem].dwID; // return category string if ((pItem->wMask & CBEXIM_CAT) && pItem->pszCat) { if (*cbex->pItems[pItem->iItem].szCat != 0) mir_tcsncpy(pItem->pszCat, cbex->pItems[pItem->iItem].szCat, pItem->ccCat - 1); else *pItem->pszCat = 0; } // return value string if ((pItem->wMask & CBEXIM_VAL) && pItem->pszVal) { if (cbex->pItems[pItem->iItem].pszVal) mir_tcsncpy(pItem->pszVal, cbex->pItems[pItem->iItem].pszVal, pItem->ccVal - 1); else *pItem->pszVal = 0; } // return the icon if (pItem->wMask & CBEXIM_ICONTEXT) pItem->pszIcon = cbex->pItems[pItem->iItem].pszIcon; // return the flags if (pItem->wMask & CBEXIM_FLAGS) pItem->wFlags = cbex->pItems[pItem->iItem].wFlags; return TRUE; } /** * name: CBEXM_DELITEM * desc: delete an item from the control * param: wParam - not used * lParam - item index * return: CB_ERR on failure, new item index if successful **/ case CBEXM_DELITEM: { if (!cbex->pItems || (INT)lParam < 0 || (INT)lParam >= cbex->numItems || (cbex->pItems[lParam].wFlags & CBEXIF_CATREADONLY)) return FALSE; MIR_FREE(cbex->pItems[(INT)lParam].pszVal); memmove(cbex->pItems + (INT)lParam, cbex->pItems + (INT)lParam + 1, (cbex->numItems - (INT)lParam - 1) * sizeof(CBEXITEMINTERN)); cbex->numItems--; ZeroMemory(cbex->pItems + cbex->numItems, sizeof(CBEXITEMINTERN)); CtrlContactWndProc(hwnd, CBEXM_SETCURSEL, lParam - 1, FALSE); return TRUE; } /** * name: CBEXM_DELITEM * desc: delete an item from the control * param: wParam - not used * lParam - item index * return: CB_ERR on failure, new item index if successful **/ case CBEXM_DELALLITEMS: { INT i; if (PtrIsValid(cbex)) { if (PtrIsValid(cbex->pItems)) { for (i = 0; i < cbex->numItems; i++) { MIR_FREE(cbex->pItems[i].pszVal); } MIR_FREE(cbex->pItems); cbex->pItems = NULL; } cbex->numItems = 0; cbex->iSelectedItem = -1; SetWindowText(cbex->hEdit, _T("")); SetWindowText(cbex->hBtnEdit, _T("")); SendMessage(cbex->hBtnEdit, WM_SETICON, NULL, NULL); } return TRUE; } /** * name: CBEXM_ENABLEITEM * desc: enables or disables the current item * param: wParam - not used * lParam - not used * return: always 0 **/ case CBEXM_ENABLEITEM: if (cbex->iSelectedItem >= 0 && cbex->iSelectedItem < cbex->numItems) { HANDLE hContact; BOOLEAN bEnabled; PSGetContact(GetParent(hwnd), hContact); bEnabled = !hContact || (cbex->pItems[cbex->iSelectedItem].wFlags & CTRLF_HASCUSTOM) || !(cbex->pItems[cbex->iSelectedItem].wFlags & (CTRLF_HASPROTO|CTRLF_HASMETA)) || !DB::Setting::GetByte(SET_PROPSHEET_PCBIREADONLY, 0); EnableWindow(cbex->hBtnEdit, bEnabled); EnableWindow(cbex->hBtnDel, bEnabled && GetWindowTextLength(cbex->hEdit) > 0); EnableWindow(cbex->hEdit, bEnabled); } break; /** * name: CBEXM_ISCHANGED * desc: returns whether the control contains changed values or not * param: wParam - not used * lParam - not used * return: TRUE if control was changed, FALSE if nothing was edited **/ case CBEXM_ISCHANGED: return cbex->bIsChanged; /** * name: CBEXM_RESETCHANGED * desc: resets changed flag to FALSE * param: wParam - not used * lParam - not used * return: always FALSE **/ case CBEXM_RESETCHANGED: cbex->bIsChanged = 0; return 0; /** * name: CBEXM_SETCURSEL * desc: selects a certain item * param: wParam - index of the item to select * lParam - (BOOLEAN)bValid - if TRUE, the next item with a value is selected * return: always FALSE **/ case CBEXM_SETCURSEL: { INT i; if (!cbex->pItems) return 1; if ((INT)wParam < 0 || (INT)wParam >= cbex->numItems) wParam = max(cbex->iSelectedItem, 0); cbex->bLocked = 1; if ((BOOLEAN)lParam == TRUE) { INT i = (INT)wParam; cbex->iSelectedItem = (INT)wParam; while (i < cbex->numItems) { if (cbex->pItems[i].pszVal && *cbex->pItems[i].pszVal) { cbex->iSelectedItem = i; break; } i++; } } else { // search for the next none deleted item for (i = (INT)wParam; i < cbex->numItems && *cbex->pItems[i].szCat == 0; i++); if (i == cbex->numItems && (INT)wParam > 0) { for (i = 0; i < (INT)wParam && *cbex->pItems[i].szCat == 0; i++); cbex->iSelectedItem = i == (INT)wParam ? 0 : i; } else cbex->iSelectedItem = i; } SetWindowText(cbex->hBtnEdit, cbex->pItems[cbex->iSelectedItem].szCat); SetWindowText(cbex->hEdit, cbex->pItems[cbex->iSelectedItem].pszVal ? cbex->pItems[cbex->iSelectedItem].pszVal : _T("")); SendMessage(cbex->hBtnEdit, BM_SETIMAGE, IMAGE_ICON, (LPARAM)cbex->pItems[cbex->iSelectedItem].hIcon); CtrlContactWndProc(hwnd, CBEXM_ENABLEITEM, NULL, NULL); cbex->bLocked = 0; return 0; } case CBEXM_SORT: if (cbex->numItems > 4) { qsort(cbex->pItems + 3, cbex->numItems - 3, sizeof(CBEXITEMINTERN), compareProc); } return 0; case WM_ERASEBKGND: return 1; case WM_SETFOCUS: SetFocus(cbex->hEdit); SendMessage(cbex->hEdit, EM_SETSEL, 0, (LPARAM)-1); return 0; } return DefWindowProc(hwnd, msg, wParam, lParam); } /** * name: CtrlContactUnLoadModule * desc: calls required operations to clean up used memory and objects * param: wParam - not used * lParam - not used * return: always 0 **/ INT CtrlContactUnLoadModule() { UnregisterClass(UINFOCOMBOEXCLASS, ghInst); return 0; } /** * name: CtrlContactLoadModule * desc: registers window class and does some other initializations * param: none * return: always 0 **/ INT CtrlContactLoadModule() { WNDCLASSEX wc; ZeroMemory(&wc, sizeof(wc)); wc.cbSize = sizeof(wc); wc.lpszClassName = UINFOCOMBOEXCLASS; wc.lpfnWndProc = CtrlContactWndProc; wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.cbWndExtra = sizeof(LPCBEX); wc.hbrBackground = (HBRUSH)GetStockObject(COLOR_WINDOW); wc.style = CS_GLOBALCLASS; RegisterClassEx(&wc); return 0; } /** * name: CtrlContactAddItemFromDB * desc: add a item read from db to the combobox * param: hCtrl - windowhandle to extended combobox control * hIcon - icon to use for custom items * szItem - category text for the item * wForcedFlags - force flag for each new entry * hContact - handle to contact whose settings to add * pszModule - primary module to search the setting in * pszProto - contacts protocol module * szSettingVal - value holding setting * return: TRUE - if the item is not updated, because its changed flag is set * FALSE - if item is added or updated successfully **/ INT CtrlContactAddItemFromDB( HWND hCtrl, LPCSTR szIcon, LPTSTR szItem, HANDLE hContact, LPCSTR pszModule, LPCSTR pszProto, LPCSTR szSettingVal) { DBVARIANT dbv; CBEXITEM cbi; LPTSTR sms; cbi.pszVal = NULL; cbi.dwID = hashSetting(szSettingVal); cbi.wFlags = CBEXIF_CATREADONLY|DB::Setting::GetTStringCtrl(hContact, pszModule, pszModule, pszProto, szSettingVal, &dbv); if (dbv.type >= DBVT_WCHAR) { // no value read from database if (cbi.wFlags == CBEXIF_CATREADONLY) { cbi.pszVal = NULL; } // check the database value else { cbi.pszVal = dbv.ptszVal; if (sms = _tcsstr(cbi.pszVal, _T(" SMS\0"))) { cbi.wFlags |= CBEXIF_SMS; *sms = 0; } } } cbi.pszCat = szItem; cbi.iItem = -1; cbi.wMask = CBEXIM_ALL; cbi.pszIcon = szIcon; SendMessage(hCtrl, CBEXM_ADDITEM, NULL, (LPARAM)&cbi); DB::Variant::Free(&dbv); return (cbi.wFlags & CTRLF_CHANGED) == CTRLF_CHANGED; } /** * name: CtrlContactAddMyItemsFromDB * desc: add a item read from db to the combobox * param: hCtrl - windowhandle to extended combobox control * hIcon - icon to use for custom items * wForcedFlags - force flag for each new entry * hContact - handle to contact whose settings to add * pszModule - primary module to search the setting in * pszProto - contacts protocol module * szFormatCat - format for the category holding setting * szFormatVal - format for the value holding setting * return: TRUE - if one of the items was not updated, because its changed flag is set * FALSE - if all items were added or updated successfully **/ INT CtrlContactAddMyItemsFromDB( HWND hCtrl, LPCSTR szIcon, WORD wForcedFlags, HANDLE hContact, LPCSTR pszModule, LPCSTR pszProto, LPCSTR szFormatCat, LPCSTR szFormatVal) { CBEXITEM cbi; DBVARIANT dbv; CHAR pszSetting[MAXSETTING]; WORD i; LPTSTR sms; INT bAnyItemIsChanged = 0; ZeroMemory(&cbi, sizeof(cbi)); cbi.iItem = -1; cbi.wMask = CBEXIM_ALL; cbi.pszIcon = szIcon; for (i = 0; SUCCEEDED(mir_snprintf(pszSetting, MAXSETTING, szFormatVal, i)) && (cbi.wFlags = DB::Setting::GetTStringCtrl(hContact, pszModule, pszModule, pszProto, pszSetting, &dbv)); i++) { // read value cbi.dwID = hashSetting(pszSetting); cbi.pszVal = dbv.ptszVal; dbv.type = DBVT_DELETED; dbv.ptszVal = NULL; // read category if (SUCCEEDED(mir_snprintf(pszSetting, MAXSETTING, szFormatCat, i))) { if (cbi.wFlags & CTRLF_HASCUSTOM) { if (DB::Setting::GetTString(hContact, pszModule, pszSetting, &dbv)) dbv.type = DBVT_DELETED; } else if (cbi.wFlags & CTRLF_HASPROTO) { if (DB::Setting::GetTString(hContact, pszProto, pszSetting, &dbv)) dbv.type = DBVT_DELETED; } if (dbv.type > DBVT_DELETED && dbv.ptszVal && *dbv.ptszVal) { cbi.pszCat = dbv.ptszVal; dbv.type = DBVT_DELETED; dbv.ptszVal = NULL; } } if (sms = _tcsstr(cbi.pszVal, _T(" SMS"))) { cbi.wFlags |= CBEXIF_SMS; *sms = 0; } cbi.wFlags |= wForcedFlags; if (CB_ERR == SendMessage(hCtrl, CBEXM_ADDITEM, NULL, (LPARAM)&cbi)) break; bAnyItemIsChanged |= (cbi.wFlags & CTRLF_CHANGED) == CTRLF_CHANGED; if (cbi.pszCat) { mir_free(cbi.pszCat); cbi.pszCat = NULL; } if (cbi.pszVal) { mir_free(cbi.pszVal); cbi.pszVal = NULL; } } SendMessage(hCtrl, CBEXM_SORT, NULL, NULL); return bAnyItemIsChanged; } /** * name: CtrlContactWriteItemToDB * desc: write a item from combobox to database * param: none * return: always 0 **/ INT CtrlContactWriteItemToDB( HWND hCtrl, HANDLE hContact, LPCSTR pszModule, LPCSTR pszProto, LPCSTR pszSetting) { TCHAR szVal[MAXDATASIZE]; CBEXITEM cbi; if (!CtrlContactWndProc(hCtrl, CBEXM_ISCHANGED, NULL, NULL)) return 1; cbi.wMask = CBEXIM_ID|CBEXIM_VAL|CBEXIM_FLAGS; cbi.pszVal = szVal; cbi.ccVal = MAXDATASIZE - 4; cbi.iItem = 0; cbi.dwID = hashSetting(pszSetting); if (!CtrlContactWndProc(hCtrl, CBEXM_GETITEM, NULL, (LPARAM)&cbi)) return 1; if (!(cbi.wFlags & CTRLF_CHANGED)) return 0; if (!hContact && !(pszModule = pszProto)) return 1; if (!*szVal) DB::Setting::Delete(hContact, pszModule, pszSetting); else { if (cbi.wFlags & CBEXIF_SMS) { mir_tcsncat(szVal, _T(" SMS"), SIZEOF(szVal)); } if (DB::Setting::WriteTString(hContact, pszModule, pszSetting, szVal)) return 1; } cbi.wFlags &= ~CTRLF_CHANGED; cbi.wMask = CBEXIM_FLAGS; CtrlContactWndProc(hCtrl, CBEXM_SETITEM, NULL, (LPARAM)&cbi); InvalidateRect(GetDlgItem(hCtrl, EDIT_VALUE), NULL, TRUE); return 0; } /** * name: CtrlContactWriteMyItemsToDB * desc: write a list of custom items from combobox to database * param: none * return: always 0 **/ INT CtrlContactWriteMyItemsToDB( HWND hCtrl, INT iFirstItem, HANDLE hContact, LPCSTR pszModule, LPCSTR pszProto, LPCSTR szFormatCat, LPCSTR szFormatVal) { CHAR pszSetting[MAXSETTING]; TCHAR szCat[MAX_CAT]; TCHAR szVal[MAXDATASIZE]; LPTSTR pszOther; CBEXITEM cbi; INT_PTR ccOther; INT i = 0; if (!CtrlContactWndProc(hCtrl, CBEXM_ISCHANGED, NULL, NULL)) return 1; if (!hContact && !(pszModule = pszProto)) return 1; pszOther = TranslateT("Other"); ccOther = _tcslen(pszOther); cbi.wMask = CBEXIM_CAT|CBEXIM_VAL|CBEXIM_FLAGS; cbi.pszCat = szCat; cbi.ccCat = MAX_CAT; cbi.pszVal = szVal; cbi.ccVal = MAXDATASIZE - 4; cbi.iItem = iFirstItem; cbi.dwID = 0; while (CtrlContactWndProc(hCtrl, CBEXM_GETITEM, NULL, (LPARAM)&cbi) && cbi.iItem < 50) { if (!(cbi.wFlags & CBEXIF_DELETED) && *szVal) { if (cbi.wFlags & CBEXIF_SMS) { mir_tcsncat(szVal, _T(" SMS"), SIZEOF(szVal)); } mir_snprintf(pszSetting, MAXSETTING, szFormatCat, i); if (*szCat && _tcsncmp(szCat, pszOther, ccOther)) { if (DB::Setting::WriteTString(hContact, pszModule, pszSetting, szCat)) return 1; } else DB::Setting::Delete(hContact, pszModule, pszSetting); mir_snprintf(pszSetting, MAXSETTING, szFormatVal, i); if (DB::Setting::WriteTString(hContact, pszModule, pszSetting, szVal)) return 1; cbi.wFlags &= ~CTRLF_CHANGED; cbi.wMask = CBEXIM_FLAGS; CtrlContactWndProc(hCtrl, CBEXM_SETITEM, NULL, (LPARAM)&cbi); cbi.wMask = CBEXIM_CAT|CBEXIM_VAL|CBEXIM_FLAGS; i++; } cbi.iItem++; } DB::Setting::DeleteArray(hContact, pszModule, szFormatCat, i); DB::Setting::DeleteArray(hContact, pszModule, szFormatVal, i); InvalidateRect(GetDlgItem(hCtrl, EDIT_VALUE), NULL, TRUE); return 0; }