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 --- plugins/UserInfoEx/ctrl_contact.cpp | 1551 +++++++++++++++++++++++++++++++++++ 1 file changed, 1551 insertions(+) create mode 100644 plugins/UserInfoEx/ctrl_contact.cpp (limited to 'plugins/UserInfoEx/ctrl_contact.cpp') diff --git a/plugins/UserInfoEx/ctrl_contact.cpp b/plugins/UserInfoEx/ctrl_contact.cpp new file mode 100644 index 0000000000..5c54693736 --- /dev/null +++ b/plugins/UserInfoEx/ctrl_contact.cpp @@ -0,0 +1,1551 @@ +/* +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. + +=============================================================================== + +File name : $HeadURL: https://userinfoex.googlecode.com/svn/trunk/ctrl_contact.cpp $ +Revision : $Revision: 187 $ +Last change on : $Date: 2010-09-08 16:05:54 +0400 (ะกั€, 08 ัะตะฝ 2010) $ +Last change by : $Author: ing.u.horn $ + +=============================================================================== +*/ +#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); +#ifdef _UNICODE + 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."); +#else + WCHAR wszTitle[MAX_PATH]; + WCHAR wszText[MAX_PATH]; + LPSTR pszTitle = Translate("Syntax Error"); + LPSTR pszText = Translate("The phone number should start with a + and consist of\nnumbers, spaces, brackets and hyphens only."); + INT cbTitle = mir_strlen(pszTitle) + 1; + INT cbText = mir_strlen(pszText) + 1; + + MultiByteToWideChar(myGlobals.CodePage, 0, pszTitle, -1, wszTitle, cbTitle); + MultiByteToWideChar(myGlobals.CodePage, 0, pszText, -1, wszText, cbText); + btt.pszTitle = wszTitle; + btt.pszText = wszText; +#endif + 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)DlgProc_Phone; + cbi.pszIcon = ICO_BTN_CUSTOMPHONE; + break; + case EDIT_EMAIL: + dlgID = IDD_ADDEMAIL; + dlgProc = (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)DlgProc_Phone; + break; + case EDIT_EMAIL: + dlgID = IDD_ADDEMAIL; + dlgProc = (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; +} \ No newline at end of file -- cgit v1.2.3