diff options
Diffstat (limited to 'plugins/UserInfoEx/src/ctrl_contact.cpp')
-rw-r--r-- | plugins/UserInfoEx/src/ctrl_contact.cpp | 1539 |
1 files changed, 1539 insertions, 0 deletions
diff --git a/plugins/UserInfoEx/src/ctrl_contact.cpp b/plugins/UserInfoEx/src/ctrl_contact.cpp new file mode 100644 index 0000000000..8b13ad9256 --- /dev/null +++ b/plugins/UserInfoEx/src/ctrl_contact.cpp @@ -0,0 +1,1539 @@ +/*
+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);
+
+ 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)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 |